base: ensure Element::Error inherits from tlv::Error

Adding static asserts to ensure (Name|name::Component|Interest|
Selectors|Exclude|KeyLocator|Data|MetaInfo|Signature|SignatureInfo)
::Error are subclasses of tlv::Error.

This commit also adds WireEncodable and WireDecodable concept checks
to Name,name::Component,Interest,Selectors,Exclude,KeyLocator,Data,
MetaInfo,SignatureInfo types.

This commit also moves definition of Selectors method into .cpp.

refs #1983

Change-Id: I15220b93437d4a624ae09df66defc91ceac2386c
diff --git a/src/common.hpp b/src/common.hpp
index 0987cf2..f5b9e03 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -51,6 +51,7 @@
 #include <memory>
 #include <stdexcept>
 #include <string>
+#include <type_traits>
 #include <unistd.h>
 
 #if defined(__GNUC__) || defined(__clang__)
@@ -104,6 +105,7 @@
 } // namespace ndn
 
 #include <boost/assert.hpp>
+#include <boost/concept_check.hpp>
 #include <boost/noncopyable.hpp>
 
 namespace ndn {
diff --git a/src/data.cpp b/src/data.cpp
index 0a2e3fb..7954cf7 100644
--- a/src/data.cpp
+++ b/src/data.cpp
@@ -22,9 +22,16 @@
 #include "data.hpp"
 #include "encoding/block-helpers.hpp"
 #include "util/crypto.hpp"
+#include "util/concepts.hpp"
 
 namespace ndn {
 
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Data>));
+BOOST_CONCEPT_ASSERT((WireEncodable<Data>));
+BOOST_CONCEPT_ASSERT((WireDecodable<Data>));
+static_assert(std::is_base_of<tlv::Error, Data::Error>::value,
+              "Data::Error must inherit from tlv::Error");
+
 Data::Data()
   : m_content(tlv::Content) // empty content
 {
diff --git a/src/data.hpp b/src/data.hpp
index 170cad2..fec8658 100644
--- a/src/data.hpp
+++ b/src/data.hpp
@@ -33,15 +33,17 @@
 
 namespace ndn {
 
+/** @brief represents a Data packet
+ */
 class Data : public enable_shared_from_this<Data>
 {
 public:
-  class Error : public std::runtime_error
+  class Error : public tlv::Error
   {
   public:
     explicit
     Error(const std::string& what)
-      : std::runtime_error(what)
+      : tlv::Error(what)
     {
     }
   };
diff --git a/src/exclude.cpp b/src/exclude.cpp
index 8e44e1a..c32d214 100644
--- a/src/exclude.cpp
+++ b/src/exclude.cpp
@@ -22,13 +22,15 @@
  */
 
 #include "exclude.hpp"
-
-#include <boost/static_assert.hpp>
-#include <boost/type_traits.hpp>
+#include "util/concepts.hpp"
 
 namespace ndn {
 
-BOOST_STATIC_ASSERT((boost::is_base_of<tlv::Error, Exclude::Error>::value));
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Exclude>));
+BOOST_CONCEPT_ASSERT((WireEncodable<Exclude>));
+BOOST_CONCEPT_ASSERT((WireDecodable<Exclude>));
+static_assert(std::is_base_of<tlv::Error, Exclude::Error>::value,
+              "Exclude::Error must inherit from tlv::Error");
 
 Exclude::Exclude()
 {
diff --git a/src/interest.cpp b/src/interest.cpp
index 3d3d40b..eb80c4b 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -24,10 +24,17 @@
 #include "interest.hpp"
 #include "util/random.hpp"
 #include "util/crypto.hpp"
+#include "util/concepts.hpp"
 #include "data.hpp"
 
 namespace ndn {
 
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
+BOOST_CONCEPT_ASSERT((WireEncodable<Interest>));
+BOOST_CONCEPT_ASSERT((WireDecodable<Interest>));
+static_assert(std::is_base_of<tlv::Error, Interest::Error>::value,
+              "Interest::Error must inherit from tlv::Error");
+
 uint32_t
 Interest::getNonce() const
 {
@@ -266,7 +273,7 @@
   //                InterestLifetime?
 
   if (m_wire.type() != tlv::Interest)
-    throw tlv::Error("Unexpected TLV number when decoding Interest");
+    throw Error("Unexpected TLV number when decoding Interest");
 
   // Name
   m_name.wireDecode(m_wire.get(tlv::Name));
diff --git a/src/interest.hpp b/src/interest.hpp
index e075ca7..02e7ba9 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -38,12 +38,21 @@
 
 const time::seconds DEFAULT_INTEREST_LIFETIME = time::seconds(4);
 
-/**
- * An Interest holds a Name and other fields for an Interest
+/** @brief represents an Interest packet
  */
 class Interest : public enable_shared_from_this<Interest>
 {
 public:
+  class Error : public tlv::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : tlv::Error(what)
+    {
+    }
+  };
+
   /**
    * @brief Create a new Interest with an empty name (`ndn:/`)
    *
diff --git a/src/key-locator.cpp b/src/key-locator.cpp
index ba17771..ddc0029 100644
--- a/src/key-locator.cpp
+++ b/src/key-locator.cpp
@@ -21,9 +21,16 @@
 
 #include "key-locator.hpp"
 #include "encoding/block-helpers.hpp"
+#include "util/concepts.hpp"
 
 namespace ndn {
 
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<KeyLocator>));
+BOOST_CONCEPT_ASSERT((WireEncodable<KeyLocator>));
+BOOST_CONCEPT_ASSERT((WireDecodable<KeyLocator>));
+static_assert(std::is_base_of<tlv::Error, KeyLocator::Error>::value,
+              "KeyLocator::Error must inherit from tlv::Error");
+
 KeyLocator::KeyLocator()
   : m_type(KeyLocator_None)
 {
diff --git a/src/key-locator.hpp b/src/key-locator.hpp
index 2528912..3c63bbd 100644
--- a/src/key-locator.hpp
+++ b/src/key-locator.hpp
@@ -30,12 +30,12 @@
 class KeyLocator
 {
 public:
-  class Error : public std::runtime_error
+  class Error : public tlv::Error
   {
   public:
     explicit
     Error(const std::string& what)
-      : std::runtime_error(what)
+      : tlv::Error(what)
     {
     }
   };
diff --git a/src/meta-info.cpp b/src/meta-info.cpp
index e3ba2be..3db4cb3 100644
--- a/src/meta-info.cpp
+++ b/src/meta-info.cpp
@@ -22,14 +22,15 @@
 #include "meta-info.hpp"
 #include "encoding/block-helpers.hpp"
 #include "encoding/encoding-buffer.hpp"
-
-#include <boost/concept_check.hpp>
-#include <boost/type_traits.hpp>
+#include "util/concepts.hpp"
 
 namespace ndn {
 
 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<MetaInfo>));
-BOOST_STATIC_ASSERT((boost::is_base_of<tlv::Error, MetaInfo::Error>::value));
+BOOST_CONCEPT_ASSERT((WireEncodable<MetaInfo>));
+BOOST_CONCEPT_ASSERT((WireDecodable<MetaInfo>));
+static_assert(std::is_base_of<tlv::Error, MetaInfo::Error>::value,
+              "MetaInfo::Error must inherit from tlv::Error");
 
 MetaInfo::MetaInfo()
   : m_type(TYPE_DEFAULT)
diff --git a/src/name-component.cpp b/src/name-component.cpp
index 9c97773..893369f 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -28,10 +28,17 @@
 #include "encoding/block-helpers.hpp"
 #include "encoding/encoding-buffer.hpp"
 #include "util/string-helper.hpp"
+#include "util/concepts.hpp"
 
 namespace ndn {
 namespace name {
 
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
+BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
+BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
+static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
+              "name::Component::Error must inherit from tlv::Error");
+
 Component::Component()
   : Block(tlv::NameComponent)
 {
diff --git a/src/name.cpp b/src/name.cpp
index ba06322..acad1d1 100644
--- a/src/name.cpp
+++ b/src/name.cpp
@@ -27,11 +27,18 @@
 
 #include "util/time.hpp"
 #include "util/string-helper.hpp"
+#include "util/concepts.hpp"
 #include "encoding/block.hpp"
 #include "encoding/encoding-buffer.hpp"
 
 namespace ndn {
 
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Name>));
+BOOST_CONCEPT_ASSERT((WireEncodable<Name>));
+BOOST_CONCEPT_ASSERT((WireDecodable<Name>));
+static_assert(std::is_base_of<tlv::Error, Name::Error>::value,
+              "Name::Error must inherit from tlv::Error");
+
 template<bool T>
 size_t
 Name::wireEncode(EncodingImpl<T>& encoder) const
diff --git a/src/security/conf/checker.hpp b/src/security/conf/checker.hpp
index 040d343..3c4ceb2 100644
--- a/src/security/conf/checker.hpp
+++ b/src/security/conf/checker.hpp
@@ -188,18 +188,18 @@
             }
           }
       }
-    catch (tlv::Error& e)
-      {
-        onValidationFailed(packet.shared_from_this(),
-                           "Cannot decode signature");
-        return -1;
-      }
     catch (KeyLocator::Error& e)
       {
         onValidationFailed(packet.shared_from_this(),
                            "Cannot decode KeyLocator");
         return -1;
       }
+    catch (tlv::Error& e)
+      {
+        onValidationFailed(packet.shared_from_this(),
+                           "Cannot decode signature");
+        return -1;
+      }
 
     std::string failInfo;
     if (m_keyLocatorChecker->check(packet, signature.getKeyLocator(), failInfo))
diff --git a/src/security/sec-public-info-sqlite3.cpp b/src/security/sec-public-info-sqlite3.cpp
index 0c70d02..c147bf1 100644
--- a/src/security/sec-public-info-sqlite3.cpp
+++ b/src/security/sec-public-info-sqlite3.cpp
@@ -489,10 +489,6 @@
     {
       return;
     }
-  catch (KeyLocator::Error& e)
-    {
-      return;
-    }
 
   sqlite3_bind_text(statement, 3, identity.toUri(), SQLITE_TRANSIENT);
   sqlite3_bind_text(statement, 4, keyId, SQLITE_STATIC);
diff --git a/src/security/sec-rule-relative.cpp b/src/security/sec-rule-relative.cpp
index 958eb66..042d04f 100644
--- a/src/security/sec-rule-relative.cpp
+++ b/src/security/sec-rule-relative.cpp
@@ -73,10 +73,6 @@
     {
       return false;
     }
-  catch (KeyLocator::Error& e)
-    {
-      return false;
-    }
   catch (RegexMatcher::Error& e)
     {
       return false;
@@ -124,10 +120,6 @@
     {
       return false;
     }
-  catch (KeyLocator::Error& e)
-    {
-      return false;
-    }
   catch (RegexMatcher::Error& e)
     {
       return false;
diff --git a/src/security/sec-rule-specific.cpp b/src/security/sec-rule-specific.cpp
index cb7adf4..061132f 100644
--- a/src/security/sec-rule-specific.cpp
+++ b/src/security/sec-rule-specific.cpp
@@ -80,10 +80,6 @@
     {
       return false;
     }
-  catch (KeyLocator::Error& e)
-    {
-      return false;
-    }
   catch (RegexMatcher::Error& e)
     {
       return false;
diff --git a/src/security/validator-config.cpp b/src/security/validator-config.cpp
index 83b7a62..5891ff1 100644
--- a/src/security/validator-config.cpp
+++ b/src/security/validator-config.cpp
@@ -537,16 +537,16 @@
       return onValidationFailed(interest.shared_from_this(),
                                 "No valid signature");
     }
-  catch (tlv::Error& e)
-    {
-      return onValidationFailed(interest.shared_from_this(),
-                                "Cannot decode signature");
-    }
   catch (KeyLocator::Error& e)
     {
       return onValidationFailed(interest.shared_from_this(),
                                 "No valid KeyLocator");
     }
+  catch (tlv::Error& e)
+    {
+      return onValidationFailed(interest.shared_from_this(),
+                                "Cannot decode signature");
+    }
   catch (IdentityCertificate::Error& e)
     {
       return onValidationFailed(interest.shared_from_this(),
diff --git a/src/security/validator-config.hpp b/src/security/validator-config.hpp
index 69f626d..6b70a3c 100644
--- a/src/security/validator-config.hpp
+++ b/src/security/validator-config.hpp
@@ -320,14 +320,14 @@
                               "Unsupported signature type");
     }
   }
-  catch (tlv::Error& e) {
-    return onValidationFailed(packet.shared_from_this(),
-                              "Cannot decode public key signature");
-  }
   catch (KeyLocator::Error& e) {
     return onValidationFailed(packet.shared_from_this(),
                               "Cannot decode KeyLocator in public key signature");
   }
+  catch (tlv::Error& e) {
+    return onValidationFailed(packet.shared_from_this(),
+                              "Cannot decode public key signature");
+  }
 
   if (signature.getKeyLocator().getType() != KeyLocator::KeyLocator_Name) {
     return onValidationFailed(packet.shared_from_this(), "Unsupported KeyLocator type");
diff --git a/src/security/validator-regex.cpp b/src/security/validator-regex.cpp
index 194aaf1..0539abd 100644
--- a/src/security/validator-regex.cpp
+++ b/src/security/validator-regex.cpp
@@ -161,17 +161,17 @@
                   return;
                 }
             }
-          catch (tlv::Error& e)
-            {
-              return onValidationFailed(data.shared_from_this(),
-                                        "Cannot decode signature");
-            }
           catch (KeyLocator::Error& e)
             {
               return onValidationFailed(data.shared_from_this(),
                                         "Key Locator is not a name: " +
                                         data.getName().toUri());
             }
+          catch (tlv::Error& e)
+            {
+              return onValidationFailed(data.shared_from_this(),
+                                        "Cannot decode signature");
+            }
         }
     }
 
diff --git a/src/selectors.cpp b/src/selectors.cpp
new file mode 100644
index 0000000..bfb4df4
--- /dev/null
+++ b/src/selectors.cpp
@@ -0,0 +1,248 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "selectors.hpp"
+#include "encoding/encoding-buffer.hpp"
+#include "encoding/block-helpers.hpp"
+#include "util/concepts.hpp"
+
+namespace ndn {
+
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Selectors>));
+BOOST_CONCEPT_ASSERT((WireEncodable<Selectors>));
+BOOST_CONCEPT_ASSERT((WireDecodable<Selectors>));
+static_assert(std::is_base_of<tlv::Error, Selectors::Error>::value,
+              "Selectors::Error must inherit from tlv::Error");
+
+Selectors::Selectors()
+  : m_minSuffixComponents(-1)
+  , m_maxSuffixComponents(-1)
+  , m_childSelector(-1)
+  , m_mustBeFresh(false)
+{
+}
+
+Selectors::Selectors(int minSuffixComponents, int maxSuffixComponents,
+                     const Exclude& exclude,
+                     int childSelector,
+                     bool mustBeFresh)
+  : m_minSuffixComponents(minSuffixComponents)
+  , m_maxSuffixComponents(maxSuffixComponents)
+  , m_exclude(exclude)
+  , m_childSelector(childSelector)
+  , m_mustBeFresh(mustBeFresh)
+{
+}
+
+Selectors::Selectors(const Block& wire)
+{
+  wireDecode(wire);
+}
+
+bool
+Selectors::empty() const
+{
+  return m_minSuffixComponents < 0 &&
+         m_maxSuffixComponents < 0 &&
+         m_publisherPublicKeyLocator.empty() &&
+         m_exclude.empty() &&
+         m_childSelector < 0 &&
+         !m_mustBeFresh;
+}
+
+template<bool T>
+size_t
+Selectors::wireEncode(EncodingImpl<T>& block) const
+{
+  size_t totalLength = 0;
+
+  // Selectors ::= SELECTORS-TYPE TLV-LENGTH
+  //                 MinSuffixComponents?
+  //                 MaxSuffixComponents?
+  //                 PublisherPublicKeyLocator?
+  //                 Exclude?
+  //                 ChildSelector?
+  //                 MustBeFresh?
+
+  // (reverse encoding)
+
+  // MustBeFresh
+  if (getMustBeFresh()) {
+    totalLength += prependBooleanBlock(block, tlv::MustBeFresh);
+  }
+
+  // ChildSelector
+  if (getChildSelector() >= 0) {
+    totalLength += prependNonNegativeIntegerBlock(block, tlv::ChildSelector, getChildSelector());
+  }
+
+  // Exclude
+  if (!getExclude().empty()) {
+    totalLength += getExclude().wireEncode(block);
+  }
+
+  // PublisherPublicKeyLocator
+  if (!getPublisherPublicKeyLocator().empty()) {
+    totalLength += getPublisherPublicKeyLocator().wireEncode(block);
+  }
+
+  // MaxSuffixComponents
+  if (getMaxSuffixComponents() >= 0) {
+    totalLength += prependNonNegativeIntegerBlock(block, tlv::MaxSuffixComponents,
+                                                  getMaxSuffixComponents());
+  }
+
+  // MinSuffixComponents
+  if (getMinSuffixComponents() >= 0) {
+    totalLength += prependNonNegativeIntegerBlock(block, tlv::MinSuffixComponents,
+                                                  getMinSuffixComponents());
+  }
+
+  totalLength += block.prependVarNumber(totalLength);
+  totalLength += block.prependVarNumber(tlv::Selectors);
+  return totalLength;
+}
+
+template size_t
+Selectors::wireEncode<true>(EncodingImpl<true>& estimator) const;
+
+template size_t
+Selectors::wireEncode<false>(EncodingImpl<false>& encoder) const;
+
+const Block&
+Selectors::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+void
+Selectors::wireDecode(const Block& wire)
+{
+  if (wire.type() != tlv::Selectors)
+    throw tlv::Error("Unexpected TLV type when decoding Selectors");
+
+  *this = Selectors();
+
+  m_wire = wire;
+  m_wire.parse();
+
+  // MinSuffixComponents
+  Block::element_const_iterator val = m_wire.find(tlv::MinSuffixComponents);
+  if (val != m_wire.elements_end()) {
+    m_minSuffixComponents = readNonNegativeInteger(*val);
+  }
+
+  // MaxSuffixComponents
+  val = m_wire.find(tlv::MaxSuffixComponents);
+  if (val != m_wire.elements_end()) {
+    m_maxSuffixComponents = readNonNegativeInteger(*val);
+  }
+
+  // PublisherPublicKeyLocator
+  val = m_wire.find(tlv::KeyLocator);
+  if (val != m_wire.elements_end()) {
+    m_publisherPublicKeyLocator.wireDecode(*val);
+  }
+
+  // Exclude
+  val = m_wire.find(tlv::Exclude);
+  if (val != m_wire.elements_end()) {
+    m_exclude.wireDecode(*val);
+  }
+
+  // ChildSelector
+  val = m_wire.find(tlv::ChildSelector);
+  if (val != m_wire.elements_end()) {
+    m_childSelector = readNonNegativeInteger(*val);
+  }
+
+  // MustBeFresh
+  val = m_wire.find(tlv::MustBeFresh);
+  if (val != m_wire.elements_end()) {
+    m_mustBeFresh = true;
+  }
+}
+
+Selectors&
+Selectors::setMinSuffixComponents(int minSuffixComponents)
+{
+  m_minSuffixComponents = minSuffixComponents;
+  m_wire.reset();
+  return *this;
+}
+
+Selectors&
+Selectors::setMaxSuffixComponents(int maxSuffixComponents)
+{
+  m_maxSuffixComponents = maxSuffixComponents;
+  m_wire.reset();
+  return *this;
+}
+
+Selectors&
+Selectors::setPublisherPublicKeyLocator(const KeyLocator& keyLocator)
+{
+  m_publisherPublicKeyLocator = keyLocator;
+  m_wire.reset();
+  return *this;
+}
+
+Selectors&
+Selectors::setExclude(const Exclude& exclude)
+{
+  m_exclude = exclude;
+  m_wire.reset();
+  return *this;
+}
+
+Selectors&
+Selectors::setChildSelector(int childSelector)
+{
+  m_childSelector = childSelector;
+  m_wire.reset();
+  return *this;
+}
+
+Selectors&
+Selectors::setMustBeFresh(bool mustBeFresh)
+{
+  m_mustBeFresh = mustBeFresh;
+  m_wire.reset();
+  return *this;
+}
+
+bool
+Selectors::operator==(const Selectors& other) const
+{
+  return wireEncode() == other.wireEncode();
+}
+
+} // namespace ndn
diff --git a/src/selectors.hpp b/src/selectors.hpp
index c4fcb42..6db99ac 100644
--- a/src/selectors.hpp
+++ b/src/selectors.hpp
@@ -25,8 +25,6 @@
 #include "common.hpp"
 #include "key-locator.hpp"
 #include "exclude.hpp"
-#include "encoding/encoding-buffer.hpp"
-#include "encoding/block-helpers.hpp"
 
 namespace ndn {
 
@@ -36,13 +34,17 @@
 class Selectors
 {
 public:
-  Selectors()
-  : m_minSuffixComponents(-1)
-  , m_maxSuffixComponents(-1)
-  , m_childSelector(-1)
-  , m_mustBeFresh(false)
+  class Error : public tlv::Error
   {
-  }
+  public:
+    explicit
+    Error(const std::string& what)
+      : tlv::Error(what)
+    {
+    }
+  };
+
+  Selectors();
 
   /** @deprecated Selectors().setX(...).setY(...)
    */
@@ -50,22 +52,13 @@
   Selectors(int minSuffixComponents, int maxSuffixComponents,
             const Exclude& exclude,
             int childSelector,
-            bool mustBeFresh))
-    : m_minSuffixComponents(minSuffixComponents)
-    , m_maxSuffixComponents(maxSuffixComponents)
-    , m_exclude(exclude)
-    , m_childSelector(childSelector)
-    , m_mustBeFresh(mustBeFresh)
-  {
-  }
+            bool mustBeFresh));
 
   /**
    * @brief Create from wire encoding
    */
-  Selectors(const Block& wire)
-  {
-    wireDecode(wire);
-  }
+  explicit
+  Selectors(const Block& wire);
 
   bool
   empty() const;
@@ -89,10 +82,7 @@
   void
   wireDecode(const Block& wire);
 
-  ///////////////////////////////////////////////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////////////////
-
+public: // getters & setters
   int
   getMinSuffixComponents() const
   {
@@ -100,14 +90,7 @@
   }
 
   Selectors&
-  setMinSuffixComponents(int minSuffixComponents)
-  {
-    m_minSuffixComponents = minSuffixComponents;
-    m_wire.reset();
-    return *this;
-  }
-
-  //
+  setMinSuffixComponents(int minSuffixComponents);
 
   int
   getMaxSuffixComponents() const
@@ -116,14 +99,7 @@
   }
 
   Selectors&
-  setMaxSuffixComponents(int maxSuffixComponents)
-  {
-    m_maxSuffixComponents = maxSuffixComponents;
-    m_wire.reset();
-    return *this;
-  }
-
-  //
+  setMaxSuffixComponents(int maxSuffixComponents);
 
   const KeyLocator&
   getPublisherPublicKeyLocator() const
@@ -132,14 +108,7 @@
   }
 
   Selectors&
-  setPublisherPublicKeyLocator(const KeyLocator& keyLocator)
-  {
-    m_publisherPublicKeyLocator = keyLocator;
-    m_wire.reset();
-    return *this;
-  }
-
-  //
+  setPublisherPublicKeyLocator(const KeyLocator& keyLocator);
 
   const Exclude&
   getExclude() const
@@ -148,14 +117,7 @@
   }
 
   Selectors&
-  setExclude(const Exclude& exclude)
-  {
-    m_exclude = exclude;
-    m_wire.reset();
-    return *this;
-  }
-
-  //
+  setExclude(const Exclude& exclude);
 
   int
   getChildSelector() const
@@ -164,14 +126,7 @@
   }
 
   Selectors&
-  setChildSelector(int childSelector)
-  {
-    m_childSelector = childSelector;
-    m_wire.reset();
-    return *this;
-  }
-
-  //
+  setChildSelector(int childSelector);
 
   int
   getMustBeFresh() const
@@ -180,24 +135,16 @@
   }
 
   Selectors&
-  setMustBeFresh(bool mustBeFresh)
-  {
-    m_mustBeFresh = mustBeFresh;
-    m_wire.reset();
-    return *this;
-  }
+  setMustBeFresh(bool mustBeFresh);
 
 public: // EqualityComparable concept
   bool
-  operator==(const Selectors& other) const
-  {
-    return wireEncode() == other.wireEncode();
-  }
+  operator==(const Selectors& other) const;
 
   bool
   operator!=(const Selectors& other) const
   {
-    return !(*this == other);
+    return !this->operator==(other);
   }
 
 private:
@@ -211,147 +158,6 @@
   mutable Block m_wire;
 };
 
-inline bool
-Selectors::empty() const
-{
-  return
-    (m_minSuffixComponents < 0 &&
-     m_maxSuffixComponents < 0 &&
-     m_publisherPublicKeyLocator.empty() &&
-     m_exclude.empty() &&
-     m_childSelector < 0 &&
-     !m_mustBeFresh);
-}
-
-template<bool T>
-inline size_t
-Selectors::wireEncode(EncodingImpl<T>& block) const
-{
-  size_t totalLength = 0;
-
-  // Selectors ::= SELECTORS-TYPE TLV-LENGTH
-  //                 MinSuffixComponents?
-  //                 MaxSuffixComponents?
-  //                 PublisherPublicKeyLocator?
-  //                 Exclude?
-  //                 ChildSelector?
-  //                 MustBeFresh?
-
-  // (reverse encoding)
-
-  // MustBeFresh
-  if (getMustBeFresh())
-    {
-      totalLength += prependBooleanBlock(block, tlv::MustBeFresh);
-    }
-
-  // ChildSelector
-  if (getChildSelector() >= 0)
-    {
-      totalLength += prependNonNegativeIntegerBlock(block, tlv::ChildSelector, getChildSelector());
-    }
-
-  // Exclude
-  if (!getExclude().empty())
-    {
-      totalLength += getExclude().wireEncode(block);
-    }
-
-  // PublisherPublicKeyLocator
-  if (!getPublisherPublicKeyLocator().empty())
-    {
-      totalLength += getPublisherPublicKeyLocator().wireEncode(block);
-    }
-
-  // MaxSuffixComponents
-  if (getMaxSuffixComponents() >= 0)
-    {
-      totalLength += prependNonNegativeIntegerBlock(block, tlv::MaxSuffixComponents,
-                                                    getMaxSuffixComponents());
-    }
-
-  // MinSuffixComponents
-  if (getMinSuffixComponents() >= 0)
-    {
-      totalLength += prependNonNegativeIntegerBlock(block, tlv::MinSuffixComponents,
-                                                    getMinSuffixComponents());
-    }
-
-  totalLength += block.prependVarNumber(totalLength);
-  totalLength += block.prependVarNumber(tlv::Selectors);
-  return totalLength;
-}
-
-inline const Block&
-Selectors::wireEncode() const
-{
-  if (m_wire.hasWire())
-    return m_wire;
-
-  EncodingEstimator estimator;
-  size_t estimatedSize = wireEncode(estimator);
-
-  EncodingBuffer buffer(estimatedSize, 0);
-  wireEncode(buffer);
-
-  m_wire = buffer.block();
-  return m_wire;
-}
-
-inline void
-Selectors::wireDecode(const Block& wire)
-{
-  if (wire.type() != tlv::Selectors)
-    throw tlv::Error("Unexpected TLV type when decoding Selectors");
-
-  *this = Selectors();
-
-  m_wire = wire;
-  m_wire.parse();
-
-  // MinSuffixComponents
-  Block::element_const_iterator val = m_wire.find(tlv::MinSuffixComponents);
-  if (val != m_wire.elements_end())
-    {
-      m_minSuffixComponents = readNonNegativeInteger(*val);
-    }
-
-  // MaxSuffixComponents
-  val = m_wire.find(tlv::MaxSuffixComponents);
-  if (val != m_wire.elements_end())
-    {
-      m_maxSuffixComponents = readNonNegativeInteger(*val);
-    }
-
-  // PublisherPublicKeyLocator
-  val = m_wire.find(tlv::KeyLocator);
-  if (val != m_wire.elements_end())
-    {
-      m_publisherPublicKeyLocator.wireDecode(*val);
-    }
-
-  // Exclude
-  val = m_wire.find(tlv::Exclude);
-  if (val != m_wire.elements_end())
-    {
-      m_exclude.wireDecode(*val);
-    }
-
-  // ChildSelector
-  val = m_wire.find(tlv::ChildSelector);
-  if (val != m_wire.elements_end())
-    {
-      m_childSelector = readNonNegativeInteger(*val);
-    }
-
-  //MustBeFresh aka AnswerOriginKind
-  val = m_wire.find(tlv::MustBeFresh);
-  if (val != m_wire.elements_end())
-    {
-      m_mustBeFresh = true;
-    }
-}
-
 } // namespace ndn
 
 #endif // NDN_SELECTORS_HPP
diff --git a/src/signature-info.cpp b/src/signature-info.cpp
index 1e40b1f..13e5be3 100644
--- a/src/signature-info.cpp
+++ b/src/signature-info.cpp
@@ -21,11 +21,18 @@
 
 #include "signature-info.hpp"
 #include "encoding/block-helpers.hpp"
+#include "util/concepts.hpp"
 
 #include <boost/lexical_cast.hpp>
 
 namespace ndn {
 
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<SignatureInfo>));
+BOOST_CONCEPT_ASSERT((WireEncodable<SignatureInfo>));
+BOOST_CONCEPT_ASSERT((WireDecodable<SignatureInfo>));
+static_assert(std::is_base_of<tlv::Error, SignatureInfo::Error>::value,
+              "SignatureInfo::Error must inherit from tlv::Error");
+
 SignatureInfo::SignatureInfo()
   : m_type(-1)
   , m_hasKeyLocator(false)
diff --git a/src/signature.cpp b/src/signature.cpp
index 5ec68d5..723478c 100644
--- a/src/signature.cpp
+++ b/src/signature.cpp
@@ -23,6 +23,10 @@
 
 namespace ndn {
 
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Signature>));
+static_assert(std::is_base_of<tlv::Error, Signature::Error>::value,
+              "Signature::Error must inherit from tlv::Error");
+
 Signature::Signature(const Block& info, const Block& value)
   : m_info(info)
   , m_value(value)
diff --git a/tests/unit-tests/test-data.cpp b/tests/unit-tests/test-data.cpp
index e370835..5c1c52a 100644
--- a/tests/unit-tests/test-data.cpp
+++ b/tests/unit-tests/test-data.cpp
@@ -31,9 +31,6 @@
 
 BOOST_AUTO_TEST_SUITE(TestData)
 
-BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Data>));
-BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Signature>));
-
 const uint8_t Content1[] = {0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x21};
 
 const uint8_t Data1[] = {
diff --git a/tests/unit-tests/test-interest.cpp b/tests/unit-tests/test-interest.cpp
index 5430bbd..4470674 100644
--- a/tests/unit-tests/test-interest.cpp
+++ b/tests/unit-tests/test-interest.cpp
@@ -32,9 +32,6 @@
 
 BOOST_AUTO_TEST_SUITE(TestInterest)
 
-BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Interest>));
-BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Selectors>));
-
 const uint8_t Interest1[] = {
   0x05,  0x5c, // NDN Interest
       0x07,  0x14, // Name
diff --git a/tests/unit-tests/test-key-locator.cpp b/tests/unit-tests/test-key-locator.cpp
index 3e48233..9ed7849 100644
--- a/tests/unit-tests/test-key-locator.cpp
+++ b/tests/unit-tests/test-key-locator.cpp
@@ -20,17 +20,12 @@
  */
 
 #include "key-locator.hpp"
-#include "util/concepts.hpp"
 #include "encoding/block-helpers.hpp"
 
 #include "boost-test.hpp"
 
 namespace ndn {
 
-BOOST_CONCEPT_ASSERT((boost::EqualityComparable<KeyLocator>));
-BOOST_CONCEPT_ASSERT((WireEncodable<KeyLocator>));
-BOOST_CONCEPT_ASSERT((WireDecodable<KeyLocator>));
-
 BOOST_AUTO_TEST_SUITE(TestKeyLocator)
 
 BOOST_AUTO_TEST_CASE(TypeNone)