encoding: Optimized encoding of Interest and related data structures

Change-Id: I0609b40565835568e09c3cc0330db441fd9243b6
refs: #1172
diff --git a/src/detail/registered-prefix.hpp b/src/detail/registered-prefix.hpp
index aeb6c66..02a0ed7 100644
--- a/src/detail/registered-prefix.hpp
+++ b/src/detail/registered-prefix.hpp
@@ -8,6 +8,7 @@
 #define NDN_DETAIL_REGISTERED_PREFIX_HPP
 
 #include "../common.hpp"
+#include "../name.hpp"
 #include "../interest.hpp"
 
 namespace ndn {
diff --git a/src/encoding/encoding-buffer.hpp b/src/encoding/encoding-buffer.hpp
index fe5dc3a..7385c65 100644
--- a/src/encoding/encoding-buffer.hpp
+++ b/src/encoding/encoding-buffer.hpp
@@ -496,6 +496,44 @@
   return prependVarNumber(varNumber);
 }
 
+/// helper methods
+
+template<bool P>
+inline size_t
+prependNonNegativeIntegerBlock(EncodingImpl<P>& blk, uint32_t type, uint64_t number)
+{
+  size_t var_len = blk.prependNonNegativeInteger(number);
+  size_t total_len = var_len;
+  total_len += blk.prependVarNumber(var_len);
+  total_len += blk.prependVarNumber(type);
+
+  return total_len;
+}
+
+template<bool P>
+inline size_t
+prependBooleanBlock(EncodingImpl<P>& blk, uint32_t type)
+{
+  size_t total_len = blk.prependVarNumber(0);
+  total_len += blk.prependVarNumber(type);
+
+  return total_len;
+}
+
+
+template<bool P, class U>
+inline size_t
+prependNestedBlock(EncodingImpl<P>& blk, uint32_t type, U& nestedBlock)
+{
+  size_t var_len = nestedBlock.wireEncode(blk);
+  size_t total_len = var_len;
+  total_len += blk.prependVarNumber(var_len);
+  total_len += blk.prependVarNumber(type);
+
+  return total_len;
+}
+
+
 } // ndn
 
 #endif // NDN_ENCODING_BUFFER_HPP
diff --git a/src/exclude.cpp b/src/exclude.cpp
index 983daaf..bc1f9d5 100644
--- a/src/exclude.cpp
+++ b/src/exclude.cpp
@@ -32,7 +32,7 @@
 // lower_bound (/d) -> /d (true) <- excluded
 // lower_bound (/e) -> /d (true) <- excluded
 bool
-Exclude::isExcluded (const Name::Component &comp) const
+Exclude::isExcluded (const name::Component &comp) const
 {
   const_iterator lowerBound = m_exclude.lower_bound (comp);
   if (lowerBound == end ())
@@ -47,7 +47,7 @@
 }
 
 Exclude &
-Exclude::excludeOne (const Name::Component &comp)
+Exclude::excludeOne (const name::Component &comp)
 {
   if (!isExcluded (comp))
     {
@@ -85,7 +85,7 @@
 //                          /f0 (false); /d0 (true); /c0 (false); /b1 (true); /b0 (false); / (true)
 
 Exclude &
-Exclude::excludeRange (const Name::Component &from, const Name::Component &to)
+Exclude::excludeRange (const name::Component &from, const name::Component &to)
 {
   if (from >= to)
     {
@@ -127,7 +127,7 @@
 }
 
 Exclude &
-Exclude::excludeAfter (const Name::Component &from)
+Exclude::excludeAfter (const name::Component &from)
 {
   iterator newFrom = m_exclude.lower_bound (from);
   if (newFrom == end () || !newFrom->second /*without ANY*/)
@@ -174,78 +174,5 @@
   return os;
 }
 
-const Block&
-Exclude::wireEncode() const
-{
-  if (wire_.hasWire())
-    return wire_;
-
-  wire_ = Block(Tlv::Exclude);
-
-  for (Exclude::const_reverse_iterator i = m_exclude.rbegin (); i != m_exclude.rend (); i++)
-    {
-      if (!i->first.empty())
-        {
-          OBufferStream os;
-          Tlv::writeVarNumber(os, Tlv::NameComponent);
-          Tlv::writeVarNumber(os, i->first.value_size());
-          os.write(reinterpret_cast<const char *>(i->first.value()), i->first.value_size());
-          
-          wire_.push_back(Block(os.buf()));
-
-        }
-      if (i->second)
-        {
-          OBufferStream os;
-          Tlv::writeVarNumber(os, Tlv::Any);
-          Tlv::writeVarNumber(os, 0);
-          wire_.push_back(Block(os.buf()));
-        }
-    }
-
-  wire_.encode();
-  return wire_;
-}
-  
-void 
-Exclude::wireDecode(const Block &wire)
-{
-  wire_ = wire;
-  wire_.parse();
-
-  Block::element_const_iterator i = wire_.elements_begin();
-  if (i->type() == Tlv::Any)
-    {
-      appendExclude(name::Component(), true);
-      ++i;
-    }
-
-  while (i != wire_.elements_end())
-    {
-      if (i->type() != Tlv::NameComponent)
-        throw Error("Incorrect format of Exclude filter");
-
-      Name::Component excludedComponent (i->value(), i->value_size());
-      ++i;
-
-      if (i != wire_.elements_end())
-        {
-          if (i->type() == Tlv::Any)
-            {
-              appendExclude(excludedComponent, true);
-              ++i;
-            }
-          else
-            {
-              appendExclude(excludedComponent, false);
-            }
-        }
-      else
-        {
-          appendExclude(excludedComponent, false);
-        }
-    }
-}
-
 
 } // ndn
diff --git a/src/exclude.hpp b/src/exclude.hpp
index 62ce672..22dc929 100644
--- a/src/exclude.hpp
+++ b/src/exclude.hpp
@@ -11,7 +11,7 @@
 #ifndef NDN_EXCLUDE_H
 #define NDN_EXCLUDE_H
 
-#include "name.hpp"
+#include "name-component.hpp"
 
 namespace ndn {
 
@@ -24,7 +24,7 @@
   struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
 
   
-  typedef std::map< Name::Component, bool /*any*/, std::greater<Name::Component> > exclude_type;
+  typedef std::map< name::Component, bool /*any*/, std::greater<name::Component> > exclude_type;
 
   typedef exclude_type::iterator iterator;
   typedef exclude_type::const_iterator const_iterator;
@@ -37,11 +37,33 @@
   Exclude ();
 
   /**
+   * @brief Fast encoding or block size estimation
+   */
+  template<bool T>
+  inline size_t
+  wireEncode(EncodingImpl<T> &block) const;
+  
+  /**
+   * @brief Encode to a wire format
+   */
+  inline const Block&
+  wireEncode() const;
+
+  /**
+   * @brief Decode from the wire format
+   */
+  inline void 
+  wireDecode(const Block &wire);
+  
+  ///////////////////////////////////////////////////////////////////////////////
+
+
+  /**
    * @brief Check if name component is excluded
    * @param comp Name component to check against exclude filter
    */
   bool
-  isExcluded (const Name::Component &comp) const;
+  isExcluded (const name::Component &comp) const;
 
   /**
    * @brief Exclude specific name component
@@ -49,7 +71,7 @@
    * @returns *this to allow chaining
    */
   Exclude &
-  excludeOne (const Name::Component &comp);
+  excludeOne (const name::Component &comp);
 
   /**
    * @brief Exclude components from range [from, to]
@@ -58,7 +80,7 @@
    * @returns *this to allow chaining
    */
   Exclude &
-  excludeRange (const Name::Component &from, const Name::Component &to);
+  excludeRange (const name::Component &from, const name::Component &to);
 
   /**
    * @brief Exclude all components from range [/, to]
@@ -66,7 +88,7 @@
    * @returns *this to allow chaining
    */
   inline Exclude &
-  excludeBefore (const Name::Component &to);
+  excludeBefore (const name::Component &to);
 
   /**
    * @brief Exclude all components from range [from, +Inf]
@@ -74,7 +96,7 @@
    * @returns *this to allow chaining
    */
   Exclude &
-  excludeAfter (const Name::Component &from);
+  excludeAfter (const name::Component &from);
 
   /**
    * @brief Method to directly append exclude element
@@ -86,7 +108,7 @@
    * If there is an error with ranges (e.g., order of components is wrong) an exception is thrown
    */
   inline void
-  appendExclude (const Name::Component &name, bool any);
+  appendExclude (const name::Component &name, bool any);
 
   /**
    * @brief Check if exclude filter is empty
@@ -136,20 +158,6 @@
   inline std::string
   toUri () const;
 
-  /**
-   * Encode this Interest for a particular wire format.
-   * @return The encoded byte array.
-   */
-  const Block&
-  wireEncode() const;
-  
-  /**
-   * Decode the input using a particular wire format and update this Interest.
-   * @param input The input byte array to be decoded.
-   */
-  void 
-  wireDecode(const Block &wire);
-  
 private:
   Exclude &
   excludeRange (iterator fromLowerBound, iterator toLowerBound);
@@ -164,13 +172,13 @@
 operator << (std::ostream &os, const Exclude &name);
 
 inline Exclude &
-Exclude::excludeBefore (const Name::Component &to)
+Exclude::excludeBefore (const name::Component &to)
 {
-  return excludeRange (Name::Component (), to);
+  return excludeRange (name::Component (), to);
 }
 
 inline void
-Exclude::appendExclude (const Name::Component &name, bool any)
+Exclude::appendExclude (const name::Component &name, bool any)
 {
   m_exclude[name] = any;
 }
@@ -226,6 +234,92 @@
   return os.str();
 }
 
+template<bool T>
+inline size_t
+Exclude::wireEncode(EncodingImpl<T> &block) const
+{
+  size_t total_len = 0;
+
+  // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
+  // Any     ::= ANY-TYPE TLV-LENGTH(=0)
+  
+  for (Exclude::const_iterator i = m_exclude.begin (); i != m_exclude.end (); i++)
+    {
+      if (i->second)
+        {
+          total_len += prependBooleanBlock(block, Tlv::Any);
+        }
+      if (!i->first.empty())
+        {
+          total_len += i->first.wireEncode(block);
+        }
+    }
+
+  total_len += block.prependVarNumber(total_len);
+  total_len += block.prependVarNumber(Tlv::Exclude);
+  return total_len;
+}
+
+inline const Block &
+Exclude::wireEncode() const
+{
+  if (wire_.hasWire())
+    return wire_;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+  
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  wire_ = buffer.block();
+  return wire_;
+}
+
+inline void
+Exclude::wireDecode(const Block &wire) 
+{
+  wire_ = wire;
+  wire_.parse();
+
+  // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
+  // Any     ::= ANY-TYPE TLV-LENGTH(=0)
+  
+  Block::element_const_iterator i = wire_.elements_begin();
+  if (i->type() == Tlv::Any)
+    {
+      appendExclude(name::Component(), true);
+      ++i;
+    }
+
+  while (i != wire_.elements_end())
+    {
+      if (i->type() != Tlv::NameComponent)
+        throw Error("Incorrect format of Exclude filter");
+
+      name::Component excludedComponent (i->value(), i->value_size());
+      ++i;
+
+      if (i != wire_.elements_end())
+        {
+          if (i->type() == Tlv::Any)
+            {
+              appendExclude(excludedComponent, true);
+              ++i;
+            }
+          else
+            {
+              appendExclude(excludedComponent, false);
+            }
+        }
+      else
+        {
+          appendExclude(excludedComponent, false);
+        }
+    }
+}
+
+
 } // ndn
 
 #endif // NDN_EXCLUDE_H
diff --git a/src/helper/command-interest-generator.cpp b/src/helper/command-interest-generator.cpp
index c216680..006d440 100644
--- a/src/helper/command-interest-generator.cpp
+++ b/src/helper/command-interest-generator.cpp
@@ -28,8 +28,12 @@
       usleep(1000); //Guarantee unqiueness of timestamp
       timestamp = time::now();
     }
-  
-  interest.getName().append(name::Component::fromNumber(timestamp)).append(name::Component::fromNumber(random::generateWord64()));
+
+  Name commandInterestName = interest.getName();
+  commandInterestName
+    .append(name::Component::fromNumber(timestamp))
+    .append(name::Component::fromNumber(random::generateWord64()));
+  interest.setName(commandInterestName);
 
   if(certificateName == DEFAULT_CERTIFICATE_NAME)
     m_keyChain.sign(interest);
@@ -45,8 +49,12 @@
   int64_t timestamp = time::now() / 1000000;
   if(timestamp <= m_lastTimestamp)
     timestamp = m_lastTimestamp + 1;
-  
-  interest.getName().append(name::Component::fromNumber(timestamp)).append(name::Component::fromNumber(random::generateWord64()));
+
+  Name commandInterestName = interest.getName();
+  commandInterestName
+    .append(name::Component::fromNumber(timestamp))
+    .append(name::Component::fromNumber(random::generateWord64()));
+  interest.setName(commandInterestName);
 
   m_keyChain.signByIdentity(interest, identity);
 
diff --git a/src/interest.cpp b/src/interest.cpp
index 99e5040..942a5f7 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -14,36 +14,34 @@
 
 namespace ndn {
 
-const Milliseconds DEFAULT_INTEREST_LIFETIME = 4000;
-
 const uint32_t&
 Interest::getNonce() const
 {
-  if (nonce_ == 0)
-    nonce_ = random::generateWord32();
+  if (m_nonce == 0)
+    m_nonce = random::generateWord32();
 
-  return nonce_;
+  return m_nonce;
 }
 
 
 bool
 Interest::matchesName(const Name &name) const
 {
-  if (!name_.isPrefixOf(name))
+  if (!m_name.isPrefixOf(name))
     return false;
   
-  if (minSuffixComponents_ >= 0 &&
+  if (getMinSuffixComponents() >= 0 &&
     // Add 1 for the implicit digest.
-      !(name.size() + 1 - name_.size() >= minSuffixComponents_))
+      !(name.size() + 1 - m_name.size() >= getMinSuffixComponents()))
     return false;
 
-  if (maxSuffixComponents_ >= 0 &&
+  if (getMaxSuffixComponents() >= 0 &&
     // Add 1 for the implicit digest.
-    !(name.size() + 1 - name_.size() <= maxSuffixComponents_))
+      !(name.size() + 1 - m_name.size() <= getMaxSuffixComponents()))
     return false;
 
-  if (!exclude_.empty() && name.size() > name_.size() &&
-      exclude_.isExcluded(name[name_.size()]))
+  if (!getExclude().empty() && name.size() > m_name.size() &&
+      getExclude().isExcluded(name[m_name.size()]))
     return false;
 
   return true;
@@ -93,159 +91,4 @@
   return os;
 }
 
-const Block&
-Interest::wireEncode() const
-{
-  if (wire_.hasWire())
-    return wire_;
-
-  // Interest ::= INTEREST-TYPE TLV-LENGTH
-  //                Name
-  //                Selectors?
-  //                Nonce
-  //                Scope?
-  //                InterestLifetime?  
-  
-  wire_ = Block(Tlv::Interest);
-  wire_.push_back(getName().wireEncode());
-
-  // selectors
-  {
-    Block selectors(Tlv::Selectors);
-    
-    if (getMinSuffixComponents() >= 0) {
-      selectors.push_back
-        (nonNegativeIntegerBlock(Tlv::MinSuffixComponents, getMinSuffixComponents()));
-    }
-    if (getMaxSuffixComponents() >= 0) {
-      selectors.push_back
-        (nonNegativeIntegerBlock(Tlv::MaxSuffixComponents, getMaxSuffixComponents()));
-    }
-    if (!getExclude().empty()) {
-      selectors.push_back
-        (getExclude().wireEncode());
-    }
-    if (getChildSelector() >= 0) {
-      selectors.push_back
-        (nonNegativeIntegerBlock(Tlv::ChildSelector, getChildSelector()));
-    }
-    if (getMustBeFresh()) {
-      selectors.push_back
-        (booleanBlock(Tlv::MustBeFresh));
-    }
-
-    if (!selectors.elements().empty())
-      {
-        selectors.encode();
-        wire_.push_back(selectors);
-      }
-  }
-
-  // Nonce
-  {
-    wire_.push_back
-      (nonNegativeIntegerBlock(Tlv::Nonce, getNonce()));
-  }
-
-  // Scope
-  if (getScope() >= 0) {
-    wire_.push_back
-      (nonNegativeIntegerBlock(Tlv::Scope, getScope()));
-  }
-
-  // InterestLifetime
-  if (getInterestLifetime() >= 0 && getInterestLifetime() != DEFAULT_INTEREST_LIFETIME) {
-    wire_.push_back
-      (nonNegativeIntegerBlock(Tlv::InterestLifetime, getInterestLifetime()));
-  }
-  
-  wire_.encode();
-  return wire_;
-}
-  
-void 
-Interest::wireDecode(const Block &wire) 
-{
-  wire_ = wire;
-  wire_.parse();
-
-  // Interest ::= INTEREST-TYPE TLV-LENGTH
-  //                Name
-  //                Selectors?
-  //                Nonce
-  //                Scope?
-  //                InterestLifetime?  
-  
-  // Name
-  name_.wireDecode(wire_.get(Tlv::Name));
-
-  // Selectors
-  Block::element_const_iterator selectors = wire_.find(Tlv::Selectors);
-  if (selectors != wire_.elements_end())
-    {
-      selectors->parse();
-
-      // MinSuffixComponents
-      Block::element_const_iterator val = selectors->find(Tlv::MinSuffixComponents);
-      if (val != selectors->elements_end())
-        {
-          minSuffixComponents_ = readNonNegativeInteger(*val);
-        }
-
-      // MaxSuffixComponents
-      val = selectors->find(Tlv::MaxSuffixComponents);
-      if (val != selectors->elements_end())
-        {
-          maxSuffixComponents_ = readNonNegativeInteger(*val);
-        }
-
-      // Exclude
-      val = selectors->find(Tlv::Exclude);
-      if (val != selectors->elements_end())
-        {
-          exclude_.wireDecode(*val);
-        }
-
-      // ChildSelector
-      val = selectors->find(Tlv::ChildSelector);
-      if (val != selectors->elements_end())
-        {
-          childSelector_ = readNonNegativeInteger(*val);
-        }
-
-      //MustBeFresh aka AnswerOriginKind
-      val = selectors->find(Tlv::MustBeFresh);
-      if (val != selectors->elements_end())
-        {
-          mustBeFresh_ = true;
-        }
-    }
-  
-  // Nonce
-  Block::element_const_iterator val = wire_.find(Tlv::Nonce);
-  if (val != wire_.elements_end())
-    {
-      nonce_ = readNonNegativeInteger(*val);
-    }
-
-  // Scope
-  val = wire_.find(Tlv::Scope);
-  if (val != wire_.elements_end())
-    {
-      scope_ = readNonNegativeInteger(*val);
-    }
-  
-  // InterestLifetime
-  val = wire_.find(Tlv::InterestLifetime);
-  if (val != wire_.elements_end())
-    {
-      interestLifetime_ = readNonNegativeInteger(*val);
-    }
-  else
-    {
-      interestLifetime_ = DEFAULT_INTEREST_LIFETIME;
-    }
-}
-
-
 }
diff --git a/src/interest.hpp b/src/interest.hpp
index 168cad1..842c427 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -1,7 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
 /**
  * Copyright (C) 2013 Regents of the University of California.
- * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  * See COPYING for copyright and distribution information.
  */
 
@@ -10,17 +9,68 @@
 
 #include "common.hpp"
 #include "name.hpp"
-#include "exclude.hpp"
-#include "encoding/block.hpp"
+#include "selectors.hpp"
 
 namespace ndn {
-  
+
+const Milliseconds DEFAULT_INTEREST_LIFETIME = 4000;
+
 /**
  * An Interest holds a Name and other fields for an interest.
  */
-class Interest : public enable_shared_from_this<Interest> {
+class Interest : public enable_shared_from_this<Interest>
+{
 public:    
   /**
+   * @brief Create a new Interest with an empty name and "none" for all values.
+   */
+  Interest()
+    : m_nonce(0)
+    , m_scope(-1)
+    , m_interestLifetime(-1.0)
+  {
+  }
+
+  /**
+   * @brief Create a new Interest with the given name and "none" for other values.
+   * 
+   * @param name The name for the interest.
+   */
+  Interest(const Name& name) 
+    : m_name(name)
+    , m_nonce(0)
+    , m_scope(-1)
+    , m_interestLifetime(-1.0)
+  {
+  }
+
+  /**
+   * Create a new Interest with the given name and interest lifetime and "none" for other values.
+   * @param name The name for the interest.
+   * @param interestLifetimeMilliseconds The interest lifetime in milliseconds, or -1 for none.
+   */
+  Interest(const Name& name, Milliseconds interestLifetime) 
+    : m_name(name)
+    , m_nonce(0)
+    , m_scope(-1)
+    , m_interestLifetime(interestLifetime)
+  {
+  }
+  
+  Interest(const Name& name,
+           const Selectors& selectors, 
+           int scope,
+           Milliseconds interestLifetime,
+           uint32_t nonce = 0) 
+    : m_name(name)
+    , m_selectors(selectors)
+    , m_nonce(nonce)
+    , m_scope(scope)
+    , m_interestLifetime(interestLifetime)
+  {
+  }
+  
+  /**
    * Create a new Interest for the given name and values.
    * @param name
    * @param minSuffixComponents
@@ -40,59 +90,31 @@
            int scope,
            Milliseconds interestLifetime,
            uint32_t nonce = 0) 
-  : name_(name)
-  , minSuffixComponents_(minSuffixComponents)
-  , maxSuffixComponents_(maxSuffixComponents)
-  , exclude_(exclude), childSelector_(childSelector)
-  , mustBeFresh_(mustBeFresh)
-  , scope_(scope)
-  , interestLifetime_(interestLifetime)
-  , nonce_(nonce)
+    : m_name(name)
+    , m_selectors(minSuffixComponents, maxSuffixComponents, exclude, childSelector, mustBeFresh)
+    , m_nonce(nonce)
+    , m_scope(scope)
+    , m_interestLifetime(interestLifetime)
   {
   }
 
   /**
-   * Create a new Interest with the given name and interest lifetime and "none" for other values.
-   * @param name The name for the interest.
-   * @param interestLifetimeMilliseconds The interest lifetime in milliseconds, or -1 for none.
+   * @brief Fast encoding or block size estimation
    */
-  Interest(const Name& name, Milliseconds interestLifetime) 
-  : name_(name)
-  {
-    construct();
-    interestLifetime_ = interestLifetime;
-  }
-
-  /**
-   * Create a new Interest with the given name and "none" for other values.
-   * @param name The name for the interest.
-   */
-  Interest(const Name& name) 
-  : name_(name)
-  {
-    construct();
-  }
-
-  /**
-   * Create a new Interest with an empty name and "none" for all values.
-   */
-  Interest() 
-  {
-    construct();
-  }
+  template<bool T>
+  inline size_t
+  wireEncode(EncodingImpl<T> &block) const;
   
   /**
-   * Encode this Interest for a particular wire format.
-   * @return The encoded byte array.
+   * @brief Encode to a wire format
    */
-  const Block&
+  inline const Block&
   wireEncode() const;
-  
+
   /**
-   * Decode the input using a particular wire format and update this Interest.
-   * @param input The input byte array to be decoded.
+   * @brief Decode from the wire format
    */
-  void 
+  inline void 
   wireDecode(const Block &wire);
   
   /**
@@ -103,79 +125,6 @@
   inline std::string
   toUri() const;
 
-  Name& 
-  getName() { return name_; }
-  
-  const Name& 
-  getName() const { return name_; }
-  
-  int 
-  getMinSuffixComponents() const { return minSuffixComponents_; }
-  
-  int 
-  getMaxSuffixComponents() const { return maxSuffixComponents_; }
-
-  Exclude& 
-  getExclude() { return exclude_; }
-  
-  const Exclude& 
-  getExclude() const { return exclude_; }
-  
-  int 
-  getChildSelector() const { return childSelector_; }
-
-  int 
-  getMustBeFresh() const { return mustBeFresh_; }
-
-  int 
-  getScope() const { return scope_; }
-
-  Milliseconds 
-  getInterestLifetime() const { return interestLifetime_; }
-
-  /**
-   * @brief Get Interest's nonce
-   *
-   * If nonce was not set before this call, it will be automatically assigned to a random value
-   *
-   * Const reference needed for C decoding
-   */
-  const uint32_t&
-  getNonce() const;
-
-  uint64_t
-  getIncomingFaceId() const { return m_incomingFaceId; }
-    
-  void
-  setName(const Name& name) { name_ = name; }
-  
-  void 
-  setMinSuffixComponents(int minSuffixComponents) { minSuffixComponents_ = minSuffixComponents; }
-  
-  void 
-  setMaxSuffixComponents(int maxSuffixComponents) { maxSuffixComponents_ = maxSuffixComponents; }
-  
-  void
-  setExclude(const Exclude& exclude) { exclude_ = exclude; }
-
-  void 
-  setChildSelector(int childSelector) { childSelector_ = childSelector; }
-
-  void 
-  setMustBeFresh(bool mustBeFresh) { mustBeFresh_ = mustBeFresh; }
-
-  void 
-  setScope(int scope) { scope_ = scope; }
-
-  void 
-  setInterestLifetime(Milliseconds interestLifetime) { interestLifetime_ = interestLifetime; }
-
-  void 
-  setNonce(uint32_t nonce) { nonce_ = nonce; }
-
-  void
-  setIncomingFaceId(uint64_t incomingFaceId) { m_incomingFaceId = incomingFaceId; }
-
   inline bool
   hasSelectors() const;
 
@@ -191,31 +140,205 @@
    */
   bool
   matchesName(const Name &name) const;
+
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  // Gettest/setters
   
-private:
-  void 
-  construct() 
+  const Name& 
+  getName() const
   {
-    minSuffixComponents_ = -1;
-    maxSuffixComponents_ = -1;  
-    childSelector_ = -1;
-    mustBeFresh_ = false; // default
-    scope_ = -1;
-    interestLifetime_ = -1.0;
-    nonce_ = 0;
+    return m_name;
+  }
+
+  Interest&
+  setName(const Name& name)
+  {
+    m_name = name;
+    m_wire.reset();
+    return *this;
   }
   
-  Name name_;
-  int minSuffixComponents_;
-  int maxSuffixComponents_;  
-  Exclude exclude_;
-  int childSelector_;
-  bool mustBeFresh_;
-  int scope_;
-  Milliseconds interestLifetime_;
-  mutable uint32_t nonce_;
+  //
 
-  mutable Block wire_;
+  const Selectors&
+  getSelectors() const
+  {
+    return m_selectors;
+  }
+
+  Interest&
+  setSelectors(const Selectors& selectors)
+  {
+    m_selectors = selectors;
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+
+  int 
+  getScope() const
+  {
+    return m_scope;
+  }
+
+  Interest&
+  setScope(int scope)
+  {
+    m_scope = scope;
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+  
+  Milliseconds 
+  getInterestLifetime() const
+  {
+    return m_interestLifetime;
+  }
+
+  Interest&
+  setInterestLifetime(Milliseconds interestLifetime)
+  {
+    m_interestLifetime = interestLifetime;
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+  
+  /**
+   * @brief Get Interest's nonce
+   *
+   * If nonce was not set before this call, it will be automatically assigned to a random value
+   *
+   * Const reference needed for C decoding
+   */
+  const uint32_t&
+  getNonce() const;
+
+  Interest&
+  setNonce(uint32_t nonce)
+  {
+    m_nonce = nonce;
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+  
+  uint64_t
+  getIncomingFaceId() const
+  {
+    return m_incomingFaceId;
+  }
+    
+  Interest&
+  setIncomingFaceId(uint64_t incomingFaceId)
+  {
+    m_incomingFaceId = incomingFaceId;
+    return *this;
+  }
+
+  //
+  
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  // Wrappers for Selectors
+  //
+  
+  int
+  getMinSuffixComponents() const
+  {
+    return m_selectors.getMinSuffixComponents();
+  }
+  
+  Interest&
+  setMinSuffixComponents(int minSuffixComponents)
+  {
+    m_selectors.setMinSuffixComponents(minSuffixComponents);
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+  
+  int
+  getMaxSuffixComponents() const
+  {
+    return m_selectors.getMaxSuffixComponents();
+  }
+
+  Interest&
+  setMaxSuffixComponents(int maxSuffixComponents)
+  {
+    m_selectors.setMaxSuffixComponents(maxSuffixComponents);
+    m_wire.reset();
+    return *this;
+  }
+  
+  //
+
+  const Exclude&
+  getExclude() const
+  {
+    return m_selectors.getExclude();
+  }
+
+  Interest&
+  setExclude(const Exclude& exclude)
+  {
+    m_selectors.setExclude(exclude);
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+  
+  int 
+  getChildSelector() const
+  {
+    return m_selectors.getChildSelector();
+  }
+
+  Interest&
+  setChildSelector(int childSelector)
+  {
+    m_selectors.setChildSelector(childSelector);
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+
+  int 
+  getMustBeFresh() const
+  {
+    return m_selectors.getMustBeFresh();
+  }
+
+  Interest&
+  setMustBeFresh(bool mustBeFresh)
+  {
+    m_selectors.setMustBeFresh(mustBeFresh);
+    m_wire.reset();
+    return *this;
+  }
+
+  //
+  
+private:
+  Name m_name;
+  Selectors m_selectors;
+  mutable uint32_t m_nonce;
+  int m_scope;
+  Milliseconds m_interestLifetime;
+
+  mutable Block m_wire;
 
   uint64_t m_incomingFaceId;
 };
@@ -234,22 +357,136 @@
 inline bool
 Interest::hasSelectors() const
 {
-  return minSuffixComponents_ >= 0 ||
-    maxSuffixComponents_ >= 0 ||
-    !exclude_.empty() ||
-    childSelector_ >= 0 ||
-    mustBeFresh_ == true ||
-    scope_ >= 0;
+  return !m_selectors.empty();
 }
 
 inline bool
 Interest::hasGuiders() const
 {
-  return scope_ >= 0 ||
-    interestLifetime_ >= 0 ||
-    nonce_ > 0;
+  return m_scope >= 0 ||
+    m_interestLifetime >= 0 ||
+    m_nonce > 0;
 }
 
+template<bool T>
+inline size_t
+Interest::wireEncode(EncodingImpl<T> &block) const
+{
+  size_t total_len = 0;
+
+  // Interest ::= INTEREST-TYPE TLV-LENGTH
+  //                Name
+  //                Selectors?
+  //                Nonce
+  //                Scope?
+  //                InterestLifetime?  
+
+  // (reverse encoding)
+
+  // InterestLifetime
+  if (getInterestLifetime() >= 0 && getInterestLifetime() != DEFAULT_INTEREST_LIFETIME)
+    {
+      total_len += prependNonNegativeIntegerBlock(block, Tlv::InterestLifetime, getInterestLifetime());
+    }
+
+  // Scope
+  if (getScope() >= 0)
+    {
+      total_len += prependNonNegativeIntegerBlock(block, Tlv::Scope, getScope());
+    }
+
+  // Nonce
+  total_len += prependNonNegativeIntegerBlock(block, Tlv::Nonce, getNonce());
+
+  // Selectors
+  if (!getSelectors().empty())
+    {
+      total_len += getSelectors().wireEncode(block);
+    }
+
+  // Name
+  total_len += getName().wireEncode(block);
+  
+  total_len += block.prependVarNumber (total_len);
+  total_len += block.prependVarNumber (Tlv::Interest);
+  return total_len;
 }
 
-#endif
+inline const Block &
+Interest::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
+Interest::wireDecode(const Block &wire) 
+{
+  m_wire = wire;
+  m_wire.parse();
+
+  // Interest ::= INTEREST-TYPE TLV-LENGTH
+  //                Name
+  //                Selectors?
+  //                Nonce
+  //                Scope?
+  //                InterestLifetime?  
+
+  if (m_wire.type() != Tlv::Interest)
+    throw Tlv::Error("Unexpected TLV number when decoding Interest");
+  
+  // Name
+  m_name.wireDecode(m_wire.get(Tlv::Name));
+
+  // Selectors
+  Block::element_const_iterator val = m_wire.find(Tlv::Selectors);
+  if (val != m_wire.elements_end())
+    {
+      m_selectors.wireDecode(*val);
+    }
+  else
+    m_selectors = Selectors();
+
+  // Nonce
+  val = m_wire.find(Tlv::Nonce);
+  if (val != m_wire.elements_end())
+    {
+      m_nonce = readNonNegativeInteger(*val);
+    }
+  else
+    m_nonce = 0;
+
+  // Scope
+  val = m_wire.find(Tlv::Scope);
+  if (val != m_wire.elements_end())
+    {
+      m_scope = readNonNegativeInteger(*val);
+    }
+  else
+    m_scope = -1;
+  
+  // InterestLifetime
+  val = m_wire.find(Tlv::InterestLifetime);
+  if (val != m_wire.elements_end())
+    {
+      m_interestLifetime = readNonNegativeInteger(*val);
+    }
+  else
+    {
+      m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
+    }
+}
+
+
+} // namespace ndn
+
+#endif // NDN_INTEREST_HPP
diff --git a/src/meta-info.hpp b/src/meta-info.hpp
index fc5458e..ff71570 100644
--- a/src/meta-info.hpp
+++ b/src/meta-info.hpp
@@ -33,6 +33,19 @@
   {
     wireDecode(block);
   }
+
+  template<bool T>
+  size_t
+  wireEncode(EncodingImpl<T> &block) const;
+
+  const Block& 
+  wireEncode() const;
+  
+  void
+  wireDecode(const Block &wire);  
+  
+  ///////////////////////////////////////////////////////////////////////////////
+  // Gettest/setters
   
   uint32_t 
   getType() const
@@ -76,16 +89,6 @@
     return *this;
   }
   
-  template<bool T>
-  size_t
-  wireEncode(EncodingImpl<T> &block) const;
-
-  const Block& 
-  wireEncode() const;
-  
-  void
-  wireDecode(const Block &wire);  
-  
 private:
   uint32_t m_type;
   Milliseconds m_freshnessPeriod;
@@ -108,28 +111,19 @@
   // FinalBlockId
   if (!m_finalBlockId.empty())
     {
-      size_t var_len = m_finalBlockId.wireEncode (blk);
-      total_len += var_len;
-      total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (Tlv::FinalBlockId);
+      total_len += prependNestedBlock(blk, Tlv::FinalBlockId, m_finalBlockId);
     }
   
   // FreshnessPeriod
   if (m_freshnessPeriod >= 0)
     {
-      size_t var_len = blk.prependNonNegativeInteger (m_freshnessPeriod);
-      total_len += var_len;
-      total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (Tlv::FreshnessPeriod);
+      total_len += prependNonNegativeIntegerBlock(blk, Tlv::FreshnessPeriod, m_freshnessPeriod);
     }
 
   // ContentType
   if (m_type != TYPE_DEFAULT)
     {
-      size_t var_len = blk.prependNonNegativeInteger (m_type);
-      total_len += var_len;
-      total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (Tlv::ContentType);
+      total_len += prependNonNegativeIntegerBlock(blk, Tlv::ContentType, m_type);
     }
 
   total_len += blk.prependVarNumber (total_len);
diff --git a/src/name.hpp b/src/name.hpp
index f95bef5..1f52868 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -503,6 +503,9 @@
 inline void
 Name::wireDecode(const Block &wire)
 {
+  if (wire.type() != Tlv::Name)
+    throw Tlv::Error("Unexpected TLV type when decoding Name");
+  
   m_nameBlock = wire;
   m_nameBlock.parse();
 }
diff --git a/src/security/key-chain.hpp b/src/security/key-chain.hpp
index ca732d8..d9d475d 100644
--- a/src/security/key-chain.hpp
+++ b/src/security/key-chain.hpp
@@ -223,14 +223,14 @@
     SignatureSha256WithRsa signature;
     signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
 
-    Name& interestName = interest.getName().append(signature.getInfo());
+    Name signedName = Name(interest.getName()).append(signature.getInfo());
 
-    signature.setValue(Tpm::signInTpm(interestName.wireEncode().value(), 
-                                      interestName.wireEncode().value_size(), 
+    signature.setValue(Tpm::signInTpm(signedName.wireEncode().value(), 
+                                      signedName.wireEncode().value_size(), 
                                       cert->getPublicKeyName(),
                                       DIGEST_ALGORITHM_SHA256));
-    
-    interest.getName().append(signature.getValue());
+    signedName.append(signature.getValue());
+    interest.setName(signedName);
   }
   
   /**
@@ -402,14 +402,15 @@
     SignatureSha256WithRsa signature;
     signature.setKeyLocator(certificate.getName().getPrefix(-1)); // implicit conversion should take care
 
-    Name& interestName = interest.getName().append(signature.getInfo());
+    Name signedName = Name(interest.getName()).append(signature.getInfo());
 
-    signature.setValue(Tpm::signInTpm(interestName.wireEncode().value(), 
-                                      interestName.wireEncode().value_size(), 
+    signature.setValue(Tpm::signInTpm(signedName.wireEncode().value(), 
+                                      signedName.wireEncode().value_size(), 
                                       certificate.getPublicKeyName(), 
                                       DIGEST_ALGORITHM_SHA256));
     
-    interestName.append(signature.getValue());
+    signedName.append(signature.getValue());
+    interest.setName(signedName);
   }
 
   /**
diff --git a/src/security/signature-sha256-with-rsa.hpp b/src/security/signature-sha256-with-rsa.hpp
index cfcef90..b1dd6e1 100644
--- a/src/security/signature-sha256-with-rsa.hpp
+++ b/src/security/signature-sha256-with-rsa.hpp
@@ -9,6 +9,7 @@
 #define NDN_SIGNATURE_SHA256_WITH_RSA_HPP
 
 #include "../data.hpp"
+#include "../encoding/tlv.hpp"
 
 namespace ndn {
 
diff --git a/src/selectors.hpp b/src/selectors.hpp
new file mode 100644
index 0000000..19a996b
--- /dev/null
+++ b/src/selectors.hpp
@@ -0,0 +1,294 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Jeff Thompson <jefft0@remap.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_SELECTORS_HPP
+#define NDN_SELECTORS_HPP
+
+#include "common.hpp"
+#include "exclude.hpp"
+#include "encoding/encoding-buffer.hpp"
+
+namespace ndn {
+  
+/**
+ * @brief Abstraction implementing Interest selectors
+ */
+class Selectors
+{
+public:    
+  Selectors() 
+  : m_minSuffixComponents(-1)
+  , m_maxSuffixComponents(-1)
+  , m_childSelector(-1)
+  , m_mustBeFresh(false)
+  {
+  }
+
+  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(const Block& wire) 
+  {
+    wireDecode(wire);
+  }
+
+  bool
+  empty() const;
+    
+  /**
+   * @brief Fast encoding or block size estimation
+   */
+  template<bool T>
+  size_t
+  wireEncode(EncodingImpl<T> &block) const;
+  
+  /**
+   * @brief Encode to a wire format
+   */
+  const Block&
+  wireEncode() const;
+
+  /**
+   * @brief Decode the input from wire format
+   */
+  void 
+  wireDecode(const Block &wire);
+
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  
+  int 
+  getMinSuffixComponents() const
+  {
+    return m_minSuffixComponents;
+  }
+  
+  Selectors& 
+  setMinSuffixComponents(int minSuffixComponents)
+  {
+    m_minSuffixComponents = minSuffixComponents;
+    wire_.reset();
+    return *this;
+  }
+
+  //
+  
+  int 
+  getMaxSuffixComponents() const
+  {
+    return m_maxSuffixComponents;
+  }
+
+  Selectors& 
+  setMaxSuffixComponents(int maxSuffixComponents)
+  {
+    m_maxSuffixComponents = maxSuffixComponents;
+    wire_.reset();
+    return *this;
+  }
+  
+  //
+
+  const Exclude& 
+  getExclude() const
+  {
+    return m_exclude;
+  }
+
+  Selectors& 
+  setExclude(const Exclude& exclude)
+  {
+    m_exclude = exclude;
+    wire_.reset();
+    return *this;
+  }
+
+  //
+  
+  int 
+  getChildSelector() const
+  {
+    return m_childSelector;
+  }
+
+  Selectors& 
+  setChildSelector(int childSelector)
+  {
+    m_childSelector = childSelector;
+    wire_.reset();
+    return *this;
+  }
+
+  //
+
+  int 
+  getMustBeFresh() const
+  {
+    return m_mustBeFresh;
+  }
+
+  Selectors& 
+  setMustBeFresh(bool mustBeFresh)
+  {
+    m_mustBeFresh = mustBeFresh;
+    wire_.reset();
+    return *this;
+  }
+
+private:
+  int m_minSuffixComponents;
+  int m_maxSuffixComponents;  
+  Exclude m_exclude;
+  int m_childSelector;
+  bool m_mustBeFresh;
+
+  mutable Block wire_;
+};
+
+inline bool
+Selectors::empty() const
+{
+  return
+    (m_minSuffixComponents < 0 &&
+     m_maxSuffixComponents < 0 &&
+     m_exclude.empty() &&
+     m_childSelector < 0 &&
+     !m_mustBeFresh);
+}
+
+template<bool T>
+inline size_t
+Selectors::wireEncode(EncodingImpl<T> &block) const
+{
+  size_t total_len = 0;
+
+  // Selectors ::= SELECTORS-TYPE TLV-LENGTH
+  //                 MinSuffixComponents?
+  //                 MaxSuffixComponents?
+  //                 PublisherPublicKeyLocator?
+  //                 Exclude?
+  //                 ChildSelector?
+  //                 MustBeFresh?  
+
+  // (reverse encoding)
+
+  // MustBeFresh
+  if (getMustBeFresh())
+    {
+      total_len += prependBooleanBlock(block, Tlv::MustBeFresh);
+    }
+
+  // ChildSelector
+  if (getChildSelector() >= 0)
+    {
+      total_len += prependNonNegativeIntegerBlock(block, Tlv::ChildSelector, getChildSelector());
+    }
+
+  // Exclude
+  if (!getExclude().empty())
+    {
+      total_len += getExclude().wireEncode(block);
+    }
+  
+  // PublisherPublicKeyLocator
+  /// @todo Implement PublisherPublicKeyLocator selector
+  
+  // MaxSuffixComponents
+  if (getMaxSuffixComponents() >= 0)
+    {
+      total_len += prependNonNegativeIntegerBlock(block, Tlv::MaxSuffixComponents,
+                                                  getMaxSuffixComponents());
+    }
+
+  // MinSuffixComponents
+  if (getMinSuffixComponents() >= 0)
+    {
+      total_len += prependNonNegativeIntegerBlock(block, Tlv::MinSuffixComponents,
+                                                  getMinSuffixComponents());
+    }
+  
+  total_len += block.prependVarNumber(total_len);
+  total_len += block.prependVarNumber(Tlv::Selectors);
+  return total_len;
+}
+
+inline const Block &
+Selectors::wireEncode() const
+{
+  if (wire_.hasWire())
+    return wire_;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+  
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  wire_ = buffer.block();
+  return wire_;
+}
+
+inline void
+Selectors::wireDecode(const Block &wire) 
+{
+  if (wire.type() != Tlv::Selectors)
+    throw Tlv::Error("Unexpected TLV type when decoding Selectors");
+
+  *this = Selectors();
+  
+  wire_ = wire;
+  wire_.parse();
+
+  // MinSuffixComponents
+  Block::element_const_iterator val = wire_.find(Tlv::MinSuffixComponents);
+  if (val != wire_.elements_end())
+    {
+      m_minSuffixComponents = readNonNegativeInteger(*val);
+    }
+
+  // MaxSuffixComponents
+  val = wire_.find(Tlv::MaxSuffixComponents);
+  if (val != wire_.elements_end())
+    {
+      m_maxSuffixComponents = readNonNegativeInteger(*val);
+    }
+
+  // Exclude
+  val = wire_.find(Tlv::Exclude);
+  if (val != wire_.elements_end())
+    {
+      m_exclude.wireDecode(*val);
+    }
+
+  // ChildSelector
+  val = wire_.find(Tlv::ChildSelector);
+  if (val != wire_.elements_end())
+    {
+      m_childSelector = readNonNegativeInteger(*val);
+    }
+
+  //MustBeFresh aka AnswerOriginKind
+  val = wire_.find(Tlv::MustBeFresh);
+  if (val != wire_.elements_end())
+    {
+      m_mustBeFresh = true;
+    }
+}
+  
+} // namespace ndn
+
+#endif // NDN_SELECTORS_HPP
diff --git a/tests/test-command-interest.cpp b/tests/test-command-interest.cpp
index 59619ca..fb447d9 100644
--- a/tests/test-command-interest.cpp
+++ b/tests/test-command-interest.cpp
@@ -63,7 +63,12 @@
   shared_ptr<Interest> commandInterest2 = make_shared<Interest>("/TestCommandInterest/Validation/Command2");
   int64_t timestamp = time::now() / 1000000;
   timestamp -= 5000;
-  commandInterest2->getName().append(name::Component::fromNumber(timestamp)).append(name::Component::fromNumber(random::generateWord64()));
+  Name commandName = commandInterest2->getName();
+  commandName
+    .append(name::Component::fromNumber(timestamp))
+    .append(name::Component::fromNumber(random::generateWord64()));
+  commandInterest2->setName(commandName);
+  
   keyChain.signByIdentity(*commandInterest2, identity);
   validator.validate(*commandInterest2,
   		     bind(&TestCore::validated, &core, _1),
diff --git a/tests/test-interest.cpp b/tests/test-interest.cpp
index 2c8f772..df0cdf3 100644
--- a/tests/test-interest.cpp
+++ b/tests/test-interest.cpp
@@ -89,9 +89,11 @@
   i.setMaxSuffixComponents(1);
   i.setChildSelector(1);
   i.setMustBeFresh(false);
-  i.getExclude()
+  Exclude exclude;
+  exclude
     .excludeOne(name::Component("alex"))
     .excludeRange(name::Component("xxxx"), name::Component("yyyy"));
+  i.setExclude(exclude);
   i.setNonce(1);
 
   const Block &wire = i.wireEncode();