util: don't require T::Error in io::load and io::save
If T::Error is declared, it must inherit from ndn::tlv::Error.
io::load now requires WireDecodable<T>;
io::save now requires WireEncodable<T>.
refs #3741
Change-Id: Iddfd2febc9c509c3e61cc9ad5da9d8694a302420
diff --git a/src/util/io.hpp b/src/util/io.hpp
index ea093d5..7da812e 100644
--- a/src/util/io.hpp
+++ b/src/util/io.hpp
@@ -22,6 +22,7 @@
#ifndef NDN_UTIL_IO_HPP
#define NDN_UTIL_IO_HPP
+#include "concepts.hpp"
#include "../encoding/block.hpp"
#include <iostream>
@@ -63,6 +64,25 @@
constexpr IoEncoding DEPRECATED(BASE_64) = BASE64;
+namespace detail {
+
+template<typename T>
+static void
+checkInnerError(typename T::Error*)
+{
+ static_assert(std::is_base_of<tlv::Error, typename T::Error>::value,
+ "T::Error, if declared, must inherit from ndn::tlv::Error");
+}
+
+template<typename T>
+static void
+checkInnerError(...)
+{
+ // T::Error is not declared
+}
+
+} // namespace detail
+
/** \brief loads a TLV block from a stream
* \return if success, the Block and true
* otherwise, a default-constructed Block and false
@@ -79,20 +99,18 @@
shared_ptr<T>
load(std::istream& is, IoEncoding encoding = BASE64)
{
+ BOOST_CONCEPT_ASSERT((WireDecodable<T>));
+ detail::checkInnerError<T>(nullptr);
+
optional<Block> block = loadBlock(is, encoding);
if (!block) {
return nullptr;
}
try {
- auto obj = make_shared<T>();
- obj->wireDecode(*block);
- return obj;
+ return make_shared<T>(*block);
}
- catch (const typename T::Error& e) {
- return nullptr;
- }
- catch (const tlv::Error& e) {
+ catch (const tlv::Error&) {
return nullptr;
}
}
@@ -122,13 +140,13 @@
void
save(const T& obj, std::ostream& os, IoEncoding encoding = BASE64)
{
+ BOOST_CONCEPT_ASSERT((WireEncodable<T>));
+ detail::checkInnerError<T>(nullptr);
+
Block block;
try {
block = obj.wireEncode();
}
- catch (const typename T::Error& e) {
- BOOST_THROW_EXCEPTION(Error(e.what()));
- }
catch (const tlv::Error& e) {
BOOST_THROW_EXCEPTION(Error(e.what()));
}