You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2016/03/11 22:45:52 UTC

[2/4] qpid-proton git commit: PROTON-1138: c++: Encode/decode of complex types

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/include/proton/unordered_map.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/unordered_map.hpp b/proton-c/bindings/cpp/include/proton/unordered_map.hpp
new file mode 100644
index 0000000..43a84d1
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/unordered_map.hpp
@@ -0,0 +1,40 @@
+#ifndef PROTON_UNORDERED_MAP_HPP
+#define PROTON_UNORDERED_MAP_HPP
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <unordered_map>
+#include <proton/encoder.hpp>
+#include <proton/decoder.hpp>
+
+namespace proton {
+namespace codec {
+
+/// Encode std::unordered_map<K, T> as amqp::UNORDERED_MAP.
+template <class K, class T, class C, class A>
+encoder& operator<<(encoder& e, const std::unordered_map<K, T, C, A>& m) { return e << encoder::map(m); }
+
+/// Decode to std::unordered_map<K, T> from amqp::UNORDERED_MAP.
+template <class K, class T, class C, class A>
+decoder& operator>>(decoder& d, std::unordered_map<K, T, C, A>& m) { return d >> decoder::associative(m); }
+
+} // internal
+} // proton
+
+#endif // PROTON_UNORDERED_MAP_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/include/proton/url.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/url.hpp b/proton-c/bindings/cpp/include/proton/url.hpp
index a5e7ad0..c863971 100644
--- a/proton-c/bindings/cpp/include/proton/url.hpp
+++ b/proton-c/bindings/cpp/include/proton/url.hpp
@@ -20,8 +20,8 @@
  * under the License.
  */
 
-#include "proton/types.hpp"
-#include "proton/error.hpp"
+#include <proton/types_fwd.hpp>
+#include <proton/error.hpp>
 
 #include <iosfwd>
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/include/proton/uuid.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/uuid.hpp b/proton-c/bindings/cpp/include/proton/uuid.hpp
index ec95b34..b1ad316 100644
--- a/proton-c/bindings/cpp/include/proton/uuid.hpp
+++ b/proton-c/bindings/cpp/include/proton/uuid.hpp
@@ -30,9 +30,9 @@ namespace proton {
 /// A 16-byte universally unique identifier.
 class uuid : public byte_array<16> {
   public:
-    /// Return a uuid copied from bytes, bytes must point to at least sizeof(uuid) bytes.
+    /// Return a uuid copied from bytes, bytes must point to at least 16 bytes.
     /// If bytes==0 the UUID is zero initialized.
-    PN_CPP_EXTERN static uuid make(const char* bytes=0);
+    PN_CPP_EXTERN static uuid copy(const char* bytes=0);
 
     /// Return a simple randomly-generated UUID. Used by the proton library to
     /// generate default UUIDs.  For specific security, performance or

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/include/proton/value.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/value.hpp b/proton-c/bindings/cpp/include/proton/value.hpp
index 4c51bf3..359aaeb 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -1,5 +1,5 @@
-#ifndef VALUE_H
-#define VALUE_H
+#ifndef PROTON_VALUE_HPP
+#define PROTON_VALUE_HPP
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -20,20 +20,18 @@
  * under the License.
  */
 
-#include "proton/data.hpp"
-#include "proton/types.hpp"
-#include "proton/timestamp.hpp"
-#include "proton/uuid.hpp"
+#include <proton/encoder.hpp>
+#include <proton/decoder.hpp>
+#include <proton/type_traits.hpp>
+#include <proton/types_fwd.hpp>
+
+#include <iosfwd>
 
 namespace proton {
 
-/// A holder for an AMQP value.
-///
-/// A proton::value can hold any AMQP data value, simple or compound.
-/// It has assignment and conversion operators to convert its contents
-/// easily to and from native C++ types.
+/// A holder for any single AMQP value, simple or complex (can be list, array, map etc.)
 ///
-/// The conversions for scalar types are documented in proton::amqp.
+/// @see proton::amqp for conversions rules between C++ and AMQP types.
 ///
 class value : private comparable<value> {
   public:
@@ -44,17 +42,29 @@ class value : private comparable<value> {
 
     /// Copy a value.
     PN_CPP_EXTERN value(const value&);
-
+    PN_CPP_EXTERN value& operator=(const value&);
 #if PN_CPP_HAS_CPP11
     PN_CPP_EXTERN value(value&&);
+    PN_CPP_EXTERN value& operator=(value&&);
 #endif
 
+    ///@internal
+    PN_CPP_EXTERN explicit value(const codec::data&);
+
     /// Construct from any allowed type T. @see proton::amqp for allowed types.
-    /// Ignore the default parameter, it restricts the template to match only allowed types.
-    template <class T> value(const T& x, typename enable_amqp_type<T>::type* = 0) { encode() << x; }
+    template <class T> value(const T& x, typename codec::assignable<T>::type* = 0) {
+        codec::encoder e(*this);
+        e << x;
+    }
     PN_CPP_EXTERN value& operator=(const null&);
 
-    PN_CPP_EXTERN value& operator=(const value&);
+    /// Assign from any encodable type T. @see proton::amqp for encodable types.
+    template <class T>
+    typename codec::assignable<T, value&>::type operator=(const T& x) {
+        codec::encoder e(*this);
+        e << x;
+        return *this;
+    }
 
     /// Reset the value to null
     PN_CPP_EXTERN void clear();
@@ -72,16 +82,7 @@ class value : private comparable<value> {
     /// @{
 
     /// Get the value.
-    template<class T> void get(T &t) const { decode() >> t; }
-
-    /// Get an AMQP map as any type T that satisfies the map concept.
-    template<class T> void get_map(T& t) const { decode() >> internal::to_map(t); }
-
-    /// Get a map as a as any type T that is a sequence pair-like types with first and second.
-    template<class T> void get_pairs(T& t) const { decode() >> internal::to_pairs(t); }
-
-    /// Get an AMQP array or list as type T that satisfies the sequence concept. */
-    template<class T> void get_sequence(T& t) const { decode() >> internal::to_sequence(t); }
+    template<class T> void get(T &t) const { codec::decoder d(*this); d >> t; }
 
     PN_CPP_EXTERN void get(null&) const;
     /// @}
@@ -104,24 +105,19 @@ class value : private comparable<value> {
   friend PN_CPP_EXTERN void swap(value&, value&);
   friend PN_CPP_EXTERN bool operator==(const value& x, const value& y);
   friend PN_CPP_EXTERN bool operator<(const value& x, const value& y);
-  friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, const value& dv);
-
-    ///@cond INTERNAL
-    PN_CPP_EXTERN internal::encoder encode();
-    PN_CPP_EXTERN internal::decoder decode() const;
-    PN_CPP_EXTERN explicit value(pn_data_t*); ///< Copies the data
-    ///@endcond
+  friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, codec::exact_cref<value>);
 
   private:
-
-    mutable class internal::data data_;
-    internal::data& data() const;   // On-demand access.
+    codec::data& data() const;
+    mutable class codec::data data_;
 
   friend class message;
-  friend class internal::encoder;
-  friend class internal::decoder;
+  friend class codec::encoder;
+  friend class codec::decoder;
 };
 
-}
+template<class T> T get(codec::exact_cref<value> v) { T x; v.ref.get(x); return x; }
+
+} // proton
 
-#endif // VALUE_H
+#endif // PROTON_VALUE_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/include/proton/vector.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/vector.hpp b/proton-c/bindings/cpp/include/proton/vector.hpp
new file mode 100644
index 0000000..350960d
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/vector.hpp
@@ -0,0 +1,55 @@
+#ifndef PROTON_VECTOR_HPP
+#define PROTON_VECTOR_HPP
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <vector>
+#include <utility>
+
+#include <proton/encoder.hpp>
+#include <proton/decoder.hpp>
+
+namespace proton {
+namespace codec {
+
+/// Encode std::vector<T> as amqp::ARRAY (same type elements)
+template <class T, class A> encoder& operator<<(encoder& e, const std::vector<T, A>& x) {
+    return e << encoder::array(x, type_id_of<T>::value);
+}
+
+/// Encode std::vector<value> encode as amqp::LIST (mixed type elements)
+template <class A> encoder& operator<<(encoder& e, const std::vector<value, A>& x) { return e << encoder::list(x); }
+
+/// Encode std::vector<scalar> as amqp::LIST (mixed type elements)
+template <class A> encoder& operator<<(encoder& e, const std::vector<scalar, A>& x) { return e << encoder::list(x); }
+
+/// Encode std::deque<std::pair<k,t> > as amqp::MAP, preserves order of entries.
+template <class A, class K, class T>
+encoder& operator<<(encoder& e, const std::vector<std::pair<K,T>, A>& x) { return e << encoder::map(x); }
+
+/// Decode to std::vector<T> from an amqp::LIST or amqp::ARRAY.
+template <class T, class A> decoder& operator>>(decoder& d, std::vector<T, A>& x) { return d >> decoder::sequence(x); }
+
+/// Decode to std::vector<std::pair<K, T> from an amqp::MAP.
+template <class A, class K, class T> decoder& operator>>(decoder& d, std::vector<std::pair<K, T> , A>& x) { return d >> decoder::pair_sequence(x); }
+
+} // internal
+} // proton
+
+#endif // PROTON_VECTOR_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/codec_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/codec_test.cpp b/proton-c/bindings/cpp/src/codec_test.cpp
index e3b45d7..ec5cf9a 100644
--- a/proton-c/bindings/cpp/src/codec_test.cpp
+++ b/proton-c/bindings/cpp/src/codec_test.cpp
@@ -13,7 +13,7 @@
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
-nn * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
@@ -22,26 +22,19 @@ nn * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 #include "test_bits.hpp"
 
 #include <proton/types.hpp>
-#include <proton/binary.hpp>
-#include <proton/decimal.hpp>
-#include <proton/decoder.hpp>
-#include <proton/encoder.hpp>
-#include <proton/symbol.hpp>
-#include <proton/value.hpp>
-#include <proton/scalar.hpp>
-#include <proton/annotation_key.hpp>
-#include <proton/message_id.hpp>
+#include <proton/data.hpp>
 
 using namespace test;
 using namespace proton;
 
 template <class T> void  simple_type_test(const T& x) {
-    ASSERT(internal::is_encodable<T>::value);
-    ASSERT(internal::is_decodable<T>::value);
+    ASSERT(codec::is_encodable<T>::value);
     value v;
-    v.encode() << x;
+    codec::encoder e(v);
+    e << x;
     T y;
-    v.decode() >> y;
+    codec::decoder d(v);
+    d >> y;
     ASSERT_EQUAL(x, y);
 }
 
@@ -51,8 +44,7 @@ template <class T> T make_fill(const char c) {
 }
 
 template <class T> void  uncodable_type_test() {
-    ASSERT(!internal::is_encodable<T>::value);
-    ASSERT(!internal::is_decodable<T>::value);
+    ASSERT(!codec::is_encodable<T>::value);
 }
 
 int main(int, char**) {
@@ -75,8 +67,7 @@ int main(int, char**) {
     RUN_TEST(failed, simple_type_test(make_fill<decimal32>(0)));
     RUN_TEST(failed, simple_type_test(make_fill<decimal64>(0)));
     RUN_TEST(failed, simple_type_test(make_fill<decimal128>(0)));
-    // FIXME aconway 2016-03-07: 
-    //    RUN_TEST(failed, simple_type_test(uuid::copy("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")));
+    RUN_TEST(failed, simple_type_test(uuid::copy("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")));
     RUN_TEST(failed, simple_type_test(std::string("xxx")));
     RUN_TEST(failed, simple_type_test(symbol("aaa")));
     RUN_TEST(failed, simple_type_test(binary("aaa")));
@@ -108,13 +99,15 @@ int main(int, char**) {
     value v(23);                // Make sure we can take a non-const ref also
     RUN_TEST(failed, simple_type_test(v));
     RUN_TEST(failed, simple_type_test(scalar(23)));
-    RUN_TEST(failed, simple_type_test(static_cast<annotation_key>(42)));
-    RUN_TEST(failed, simple_type_test(static_cast<message_id>(42)));
+    RUN_TEST(failed, simple_type_test(annotation_key(42)));
+    RUN_TEST(failed, simple_type_test(message_id(42)));
 
     // Make sure we reject uncodable types
     RUN_TEST(failed, (uncodable_type_test<std::pair<int, float> >()));
     RUN_TEST(failed, (uncodable_type_test<std::pair<scalar, value> >()));
     RUN_TEST(failed, (uncodable_type_test<std::basic_string<wchar_t> >()));
+    RUN_TEST(failed, (uncodable_type_test<codec::data>()));
+    RUN_TEST(failed, (uncodable_type_test<pn_data_t*>()));
 
     return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/data.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/data.cpp b/proton-c/bindings/cpp/src/data.cpp
index a714cf6..5bbf743 100644
--- a/proton-c/bindings/cpp/src/data.cpp
+++ b/proton-c/bindings/cpp/src/data.cpp
@@ -19,28 +19,35 @@
 
 #include "proton_bits.hpp"
 
-#include "proton/amqp.hpp"
-#include "proton/binary.hpp"
-#include "proton/data.hpp"
-#include "proton/decimal.hpp"
-#include "proton/symbol.hpp"
+#include <proton/binary.hpp>
+#include <proton/data.hpp>
+#include <proton/decimal.hpp>
+#include <proton/encoder.hpp>
+#include <proton/message_id.hpp>
+#include <proton/symbol.hpp>
+#include <proton/timestamp.hpp>
+#include <proton/value.hpp>
 
 #include <proton/codec.h>
 
 #include <ostream>
 
 namespace proton {
-namespace internal {
+namespace codec {
 
-data& data::copy(const data& x) { ::pn_data_copy(pn_object(), x.pn_object()); return *this; }
+data data::create() { return internal::take_ownership(pn_data(0)).get(); }
+
+void data::copy(const data& x) { ::pn_data_copy(pn_object(), x.pn_object()); }
 
 void data::clear() { ::pn_data_clear(pn_object()); }
 
+void data::rewind() { ::pn_data_rewind(pn_object()); }
+
 bool data::empty() const { return ::pn_data_size(pn_object()) == 0; }
 
-uintptr_t data::point() const { return uintptr_t(pn_data_point(pn_object())); }
+void* data::point() const { return pn_data_point(pn_object()); }
 
-void data::restore(uintptr_t h) { pn_data_restore(pn_object(), pn_handle_t(h)); }
+void data::restore(void* h) { pn_data_restore(pn_object(), pn_handle_t(h)); }
 
 void data::narrow() { pn_data_narrow(pn_object()); }
 
@@ -50,123 +57,15 @@ int data::append(data src) { return pn_data_append(pn_object(), src.pn_object())
 
 int data::appendn(data src, int limit) { return pn_data_appendn(pn_object(), src.pn_object(), limit);}
 
-bool data::next() const { return pn_data_next(pn_object()); }
-
+bool data::next() { return pn_data_next(pn_object()); }
 
-namespace {
-struct save_state {
-    data data_;
-    uintptr_t handle;
-    save_state(data d) : data_(d), handle(data_.point()) {}
-    ~save_state() { if (!!data_) data_.restore(handle); }
-};
-}
+bool data::prev() { return pn_data_prev(pn_object()); }
 
 std::ostream& operator<<(std::ostream& o, const data& d) {
-    save_state s(d.pn_object());
-    d.decoder().rewind();
+    state_guard sg(const_cast<data&>(d));
+    const_cast<data&>(d).rewind();
     return o << inspectable(d.pn_object());
 }
 
-data data::create() { return internal::take_ownership(pn_data(0)); }
-
-class encoder data::encoder() { return internal::encoder(pn_object()); }
-class decoder data::decoder() { return internal:: decoder(pn_object()); }
-
-type_id data::type() const { return decoder().type(); }
-
-namespace {
-
-// Compare nodes, return -1 if a<b, 0 if a==b, +1 if a>b
-// Forward-declare so we can use it recursively.
-int compare_next(data& a, data& b);
-
-template <class T> int compare(const T& a, const T& b) {
-    if (a < b) return -1;
-    else if (a > b) return +1;
-    else return 0;
-}
-
-int compare_container(data& a, data& b) {
-    scope sa(a.decoder()), sb(b.decoder());
-    // Compare described vs. not-described.
-    int cmp = compare(sa.is_described, sb.is_described);
-    if (cmp) return cmp;
-    // Lexical sort (including descriptor if there is one)
-    size_t min_size = std::min(sa.size, sb.size) + size_t(sa.is_described);
-    for (size_t i = 0; i < min_size; ++i) {
-        cmp = compare_next(a, b);
-        if (cmp) return cmp;
-    }
-    return compare(sa.size, sb.size);
-}
-
-template <class T> int compare_simple(data& a, data& b) {
-    T va = T();
-    T vb = T();
-    a.decoder() >> va;
-    b.decoder() >> vb;
-    return compare(va, vb);
-}
-
-int compare_next(data& a, data& b) {
-    // Sort by type_id first.
-    type_id ta = a.type(), tb = b.type();
-    int cmp = compare(ta, tb);
-    if (cmp) return cmp;
-
-    switch (ta) {
-      case NULL_TYPE: return 0;
-      case ARRAY:
-      case LIST:
-      case MAP:
-      case DESCRIBED:
-        return compare_container(a, b);
-      case BOOLEAN: return compare_simple<bool>(a, b);
-      case UBYTE: return compare_simple<amqp::ubyte_type>(a, b);
-      case BYTE: return compare_simple<amqp::byte_type>(a, b);
-      case USHORT: return compare_simple<amqp::ushort_type>(a, b);
-      case SHORT: return compare_simple<amqp::short_type>(a, b);
-      case UINT: return compare_simple<amqp::uint_type>(a, b);
-      case INT: return compare_simple<amqp::int_type>(a, b);
-      case CHAR: return compare_simple<amqp::char_type>(a, b);
-      case ULONG: return compare_simple<amqp::ulong_type>(a, b);
-      case LONG: return compare_simple<amqp::long_type>(a, b);
-      case TIMESTAMP: return compare_simple<timestamp>(a, b);
-      case FLOAT: return compare_simple<amqp::float_type>(a, b);
-      case DOUBLE: return compare_simple<amqp::double_type>(a, b);
-      case DECIMAL32: return compare_simple<decimal32>(a, b);
-      case DECIMAL64: return compare_simple<decimal64>(a, b);
-      case DECIMAL128: return compare_simple<decimal128>(a, b);
-      case UUID: return compare_simple<uuid>(a, b);
-      case BINARY: return compare_simple<amqp::binary_type>(a, b);
-      case STRING: return compare_simple<amqp::string_type>(a, b);
-      case SYMBOL: return compare_simple<amqp::symbol_type>(a, b);
-    }
-    // Invalid but equal type_id, treat as equal.
-    return 0;
-}
-
-int compare(data& a, data& b) {
-    save_state s1(a);
-    save_state s2(b);
-    a.decoder().rewind();
-    b.decoder().rewind();
-    while (a.decoder().more() && b.decoder().more()) {
-        int cmp = compare_next(a, b);
-        if (cmp != 0) return cmp;
-    }
-    if (b.decoder().more()) return -1;
-    if (a.decoder().more()) return 1;
-    return 0;
-}
-} // namespace
-
-bool data::equal(const data& x) const {
-    return compare(const_cast<data&>(*this), const_cast<data&>(x)) == 0;
-}
-bool data::less(const data& x) const {
-    return compare(const_cast<data&>(*this), const_cast<data&>(x)) < 0;
-}
-}
-}
+} // codec
+} // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/decimal.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/decimal.cpp b/proton-c/bindings/cpp/src/decimal.cpp
index 65279f4..93fe84c 100644
--- a/proton-c/bindings/cpp/src/decimal.cpp
+++ b/proton-c/bindings/cpp/src/decimal.cpp
@@ -22,6 +22,6 @@
 
 namespace proton {
 std::ostream& operator<<(std::ostream& o, const decimal32& ) { return o << "<decimal32>"; }
-std::ostream& operator<<(std::ostream& o, const decimal64& ) { return o << "<decimal32>"; }
-std::ostream& operator<<(std::ostream& o, const decimal128& ) { return o << "<decimal32>"; }
+std::ostream& operator<<(std::ostream& o, const decimal64& ) { return o << "<decimal64>"; }
+std::ostream& operator<<(std::ostream& o, const decimal128& ) { return o << "<decimal128>"; }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/decoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/decoder.cpp b/proton-c/bindings/cpp/src/decoder.cpp
index f517e36..e724003 100644
--- a/proton-c/bindings/cpp/src/decoder.cpp
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -17,128 +17,99 @@
  * under the License.
  */
 
-#include "proton/data.hpp"
-#include "proton/decoder.hpp"
-#include "proton/decimal.hpp"
-#include "proton/value.hpp"
-#include "proton/message_id.hpp"
-#include "proton/annotation_key.hpp"
-#include "proton/amqp.hpp"
-#include "proton_bits.hpp"
+#include <proton/annotation_key.hpp>
+#include <proton/binary.hpp>
+#include <proton/data.hpp>
+#include <proton/decimal.hpp>
+#include <proton/encoder.hpp>
+#include <proton/message_id.hpp>
+#include <proton/symbol.hpp>
+#include <proton/timestamp.hpp>
+#include <proton/value.hpp>
 
+#include "proton_bits.hpp"
 #include "types_internal.hpp"
 #include "msg.hpp"
 
 #include <proton/codec.h>
 
 namespace proton {
-namespace internal {
+namespace codec {
 
 /**@file
  *
  * Note the pn_data_t "current" node is always pointing *before* the next value
  * to be returned by the decoder.
- *
  */
-namespace {
-struct save_state {
-    pn_data_t* data;
-    pn_handle_t handle;
-    save_state(pn_data_t* d) : data(d), handle(pn_data_point(d)) {}
-    ~save_state() { if (data) pn_data_restore(data, handle); }
-    void cancel() { data = 0; }
-};
-
-struct narrow {
-    data data_;
-    narrow(data d) : data_(d) { data_.narrow(); }
-    ~narrow() { data_.widen(); }
-};
 
+decoder::decoder(exact_cref<value> v) : data(v.ref.data()) { rewind(); }
+
+namespace {
 template <class T> T check(T result) {
     if (result < 0)
-        throw conversion_error("" + error_str(result));
+        throw conversion_error(error_str(result));
     return result;
 }
-
 }
 
 void decoder::decode(const char* i, size_t size) {
-    save_state ss(pn_object());
+    state_guard sg(*this);
     const char* end = i + size;
-    while (i < end) {
+    while (i < end)
         i += check(pn_data_decode(pn_object(), i, size_t(end - i)));
-    }
 }
 
-void decoder::decode(const std::string& buffer) {
-    decode(buffer.data(), buffer.size());
-}
-
-bool decoder::more() const {
-    save_state ss(pn_object());
-    return pn_data_next(pn_object());
-}
-
-void decoder::rewind() { ::pn_data_rewind(pn_object()); }
-
-void decoder::backup() { ::pn_data_prev(pn_object()); }
-
-void decoder::skip() { ::pn_data_next(pn_object()); }
-
-namespace {
+void decoder::decode(const std::string& s) { decode(s.data(), s.size()); }
 
-void bad_type(type_id want, type_id got) {
-    if (want != got) throw make_conversion_error(want, got);
+bool decoder::more() {
+    state_guard sg(*this);
+    return next();
 }
 
-type_id pre_get(pn_data_t* data) {
-    if (!pn_data_next(data)) throw conversion_error("no more data");
-    type_id t = type_id(pn_data_type(data));
+type_id decoder::pre_get() {
+    if (!next()) throw conversion_error("no more data");
+    type_id t = type_id(pn_data_type(pn_object()));
     if (t < 0) throw conversion_error("invalid data");
     return t;
 }
 
+namespace {
+
 template <class T, class U> void assign(T& x, const U& y) { x = y; }
 void assign(uuid& x, const pn_uuid_t y) { byte_copy(x, y); }
 void assign(decimal32& x, const pn_decimal32_t y) { byte_copy(x, y); }
 void assign(decimal64& x, const pn_decimal64_t y)  { byte_copy(x, y); }
 void assign(decimal128& x, const pn_decimal128_t y) { byte_copy(x, y); }
 
-// Simple extract with no type conversion.
-template <class T, class U> void extract(pn_data_t* data, T& x, U (*get)(pn_data_t*)) {
-    save_state ss(data);
-    bad_type(type_id_of<T>::value, pre_get(data));
-    assign(x, get(data));
-    ss.cancel();                // No error, no rewind
-}
+} // namespace
 
-}
 
-void decoder::check_type(type_id want) {
-    type_id got = type();
-    if (want != got) bad_type(want, got);
+// Simple extract with no type conversion.
+template <class T, class U> void decoder::extract(T& x, U (*get)(pn_data_t*)) {
+    state_guard sg(*this);
+    assert_type_equal(type_id_of<T>::value, pre_get());
+    assign(x, get(pn_object()));
+    sg.cancel();                // No error, cancel the reset.
 }
 
-type_id decoder::type() const {
-    save_state ss(pn_object());
-    return pre_get(pn_object());
+type_id decoder::next_type() {
+    state_guard sg(*this);
+    return pre_get();
 }
 
-decoder decoder::operator>>(start& s) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    s.type = pre_get(d);
+decoder& decoder::operator>>(start& s) {
+    state_guard sg(*this);
+    s.type = pre_get();
     switch (s.type) {
       case ARRAY:
-        s.size = pn_data_get_array(d);
-        s.element = type_id(pn_data_get_array_type(d)); s.is_described = pn_data_is_array_described(d);
+        s.size = pn_data_get_array(pn_object());
+        s.element = type_id(pn_data_get_array_type(pn_object())); s.is_described = pn_data_is_array_described(pn_object());
         break;
       case LIST:
-        s.size = pn_data_get_list(d);
+        s.size = pn_data_get_list(pn_object());
         break;
       case MAP:
-        s.size = pn_data_get_map(d);
+        s.size = pn_data_get_map(pn_object());
         break;
       case DESCRIBED:
         s.is_described = true;
@@ -147,41 +118,36 @@ decoder decoder::operator>>(start& s) {
       default:
         throw conversion_error(MSG("" << s.type << " is not a container type"));
     }
-    pn_data_enter(d);
-    ss.cancel();
+    pn_data_enter(pn_object());
+    sg.cancel();
     return *this;
 }
 
-// FIXME aconway 2016-03-08: remove
-decoder decoder::operator>>(struct finish) { pn_data_exit(pn_object()); return *this; }
-
-decoder decoder::operator>>(struct skip) { pn_data_next(pn_object()); return *this; }
-
-decoder decoder::operator>>(struct assert_type a) { bad_type(a.type, type()); return *this; }
-
-decoder decoder::operator>>(struct rewind) { rewind(); return *this; }
+decoder& decoder::operator>>(const finish&) {
+    pn_data_exit(pn_object());
+    return *this;
+}
 
-decoder decoder::operator>>(null&) {
-    save_state ss(pn_object());
-    bad_type(NULL_TYPE, pre_get(pn_object()));
+decoder& decoder::operator>>(null&) {
+    state_guard sg(*this);
+    assert_type_equal(NULL_TYPE, pre_get());
     return *this;
 }
 
-decoder decoder::operator>>(value& v) {
-    data mine(pn_object());
-    if (mine == v.data_)
+decoder& decoder::operator>>(value& v) {
+    if (*this == v.data_)
         throw conversion_error("extract into self");
     v.clear();
     {
-        narrow n(pn_object());
-        check(v.data().appendn(mine, 1));
+        narrow_guard n(*this);
+        check(v.data().appendn(pn_object(), 1));
     }
-    if (!mine.next()) throw conversion_error("no more data");
+    next();
     return *this;
 }
 
-decoder decoder::operator>>(message_id& x) {
-    switch (type()) {
+decoder& decoder::operator>>(message_id& x) {
+    switch (next_type()) {
       case ULONG:
       case UUID:
       case BINARY:
@@ -189,209 +155,190 @@ decoder decoder::operator>>(message_id& x) {
         return *this >> x.scalar_;
       default:
         throw conversion_error(
-            msg() << "expected one of ulong, uuid, binary or string but found " << type());
+            msg() << "expected one of ulong, uuid, binary or string but found " << next_type());
     };
 }
 
-decoder decoder::operator>>(annotation_key& x) {
-    switch (type()) {
+decoder& decoder::operator>>(annotation_key& x) {
+    switch (next_type()) {
       case ULONG:
       case SYMBOL:
         return *this >> x.scalar_;
       default:
-        throw conversion_error("expected one of ulong or symbol but found " + type_name(type()));
+        throw conversion_error("expected one of ulong or symbol but found " + type_name(next_type()));
     };
 }
 
-decoder decoder::operator>>(scalar& x) {
-    save_state ss(pn_object());
-    type_id got = pre_get(pn_object());
+decoder& decoder::operator>>(scalar& x) {
+    state_guard sg(*this);
+    type_id got = pre_get();
     if (!type_id_is_scalar(got))
         throw conversion_error("expected scalar, found "+type_name(got));
     x.set(pn_data_get_atom(pn_object()));
-    ss.cancel();                // No error, no rewind
+    sg.cancel();                // No error, no rewind
     return *this;
 }
 
-decoder decoder::operator>>(amqp::boolean_type &x) {
-    extract(pn_object(), x, pn_data_get_bool);
+decoder& decoder::operator>>(bool &x) {
+    extract(x, pn_data_get_bool);
     return *this;
 }
 
-decoder decoder::operator>>(amqp::ubyte_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case UBYTE: x = pn_data_get_ubyte(d); break;
-      default: bad_type(UBYTE, type_id(type_id(pn_data_type(d))));
+decoder& decoder::operator>>(uint8_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
+      default: assert_type_equal(UBYTE, type_id(type_id(pn_data_type(pn_object()))));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::byte_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case BYTE: x = pn_data_get_byte(d); break;
-      default: bad_type(BYTE, type_id(type_id(pn_data_type(d))));
+decoder& decoder::operator>>(int8_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case BYTE: x = pn_data_get_byte(pn_object()); break;
+      default: assert_type_equal(BYTE, type_id(type_id(pn_data_type(pn_object()))));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::ushort_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case UBYTE: x = pn_data_get_ubyte(d); break;
-      case USHORT: x = pn_data_get_ushort(d); break;
-      default: bad_type(USHORT, type_id(type_id(pn_data_type(d))));
+decoder& decoder::operator>>(uint16_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
+      case USHORT: x = pn_data_get_ushort(pn_object()); break;
+      default: assert_type_equal(USHORT, type_id(type_id(pn_data_type(pn_object()))));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::short_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case BYTE: x = pn_data_get_byte(d); break;
-      case SHORT: x = pn_data_get_short(d); break;
-      default: bad_type(SHORT, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(int16_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case BYTE: x = pn_data_get_byte(pn_object()); break;
+      case SHORT: x = pn_data_get_short(pn_object()); break;
+      default: assert_type_equal(SHORT, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::uint_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case UBYTE: x = pn_data_get_ubyte(d); break;
-      case USHORT: x = pn_data_get_ushort(d); break;
-      case UINT: x = pn_data_get_uint(d); break;
-      default: bad_type(UINT, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(uint32_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
+      case USHORT: x = pn_data_get_ushort(pn_object()); break;
+      case UINT: x = pn_data_get_uint(pn_object()); break;
+      default: assert_type_equal(UINT, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::int_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case BYTE: x = pn_data_get_byte(d); break;
-      case SHORT: x = pn_data_get_short(d); break;
-      case INT: x = pn_data_get_int(d); break;
-      default: bad_type(INT, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(int32_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case BYTE: x = pn_data_get_byte(pn_object()); break;
+      case SHORT: x = pn_data_get_short(pn_object()); break;
+      case INT: x = pn_data_get_int(pn_object()); break;
+      default: assert_type_equal(INT, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::ulong_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case UBYTE: x = pn_data_get_ubyte(d); break;
-      case USHORT: x = pn_data_get_ushort(d); break;
-      case UINT: x = pn_data_get_uint(d); break;
-      case ULONG: x = pn_data_get_ulong(d); break;
-      default: bad_type(ULONG, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(uint64_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
+      case USHORT: x = pn_data_get_ushort(pn_object()); break;
+      case UINT: x = pn_data_get_uint(pn_object()); break;
+      case ULONG: x = pn_data_get_ulong(pn_object()); break;
+      default: assert_type_equal(ULONG, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::long_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case BYTE: x = pn_data_get_byte(d); break;
-      case SHORT: x = pn_data_get_short(d); break;
-      case INT: x = pn_data_get_int(d); break;
-      case LONG: x = pn_data_get_long(d); break;
-      default: bad_type(LONG, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(int64_t &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case BYTE: x = pn_data_get_byte(pn_object()); break;
+      case SHORT: x = pn_data_get_short(pn_object()); break;
+      case INT: x = pn_data_get_int(pn_object()); break;
+      case LONG: x = pn_data_get_long(pn_object()); break;
+      default: assert_type_equal(LONG, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::char_type &x) {
-    extract(pn_object(), x, pn_data_get_char);
+decoder& decoder::operator>>(wchar_t &x) {
+    extract(x, pn_data_get_char);
     return *this;
 }
 
-decoder decoder::operator>>(timestamp &x) {
-    extract(pn_object(), x, pn_data_get_timestamp);
+decoder& decoder::operator>>(timestamp &x) {
+    extract(x, pn_data_get_timestamp);
     return *this;
 }
 
-decoder decoder::operator>>(amqp::float_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case FLOAT: x = pn_data_get_float(d); break;
-      case DOUBLE: x = float(pn_data_get_double(d)); break;
-      default: bad_type(FLOAT, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(float &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case FLOAT: x = pn_data_get_float(pn_object()); break;
+      case DOUBLE: x = float(pn_data_get_double(pn_object())); break;
+      default: assert_type_equal(FLOAT, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(amqp::double_type &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case FLOAT: x = pn_data_get_float(d); break;
-      case DOUBLE: x = pn_data_get_double(d); break;
-      default: bad_type(DOUBLE, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(double &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case FLOAT: x = pn_data_get_float(pn_object()); break;
+      case DOUBLE: x = pn_data_get_double(pn_object()); break;
+      default: assert_type_equal(DOUBLE, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-decoder decoder::operator>>(decimal32 &x) {
-    extract(pn_object(), x, pn_data_get_decimal32);
+decoder& decoder::operator>>(decimal32 &x) {
+    extract(x, pn_data_get_decimal32);
     return *this;
 }
 
-decoder decoder::operator>>(decimal64 &x) {
-    extract(pn_object(), x, pn_data_get_decimal64);
+decoder& decoder::operator>>(decimal64 &x) {
+    extract(x, pn_data_get_decimal64);
     return *this;
 }
 
-decoder decoder::operator>>(decimal128 &x)  {
-    extract(pn_object(), x, pn_data_get_decimal128);
+decoder& decoder::operator>>(decimal128 &x)  {
+    extract(x, pn_data_get_decimal128);
     return *this;
 }
 
-decoder decoder::operator>>(uuid &x)  {
-    extract(pn_object(), x, pn_data_get_uuid);
+decoder& decoder::operator>>(uuid &x)  {
+    extract(x, pn_data_get_uuid);
     return *this;
 }
 
-decoder decoder::operator>>(std::string &x) {
-    pn_data_t* d = pn_object();
-    save_state ss(d);
-    switch (pre_get(d)) {
-      case STRING: x = str(pn_data_get_string(d)); break;
-      case BINARY: x = str(pn_data_get_binary(d)); break;
-      case SYMBOL: x = str(pn_data_get_symbol(d)); break;
-      default: bad_type(STRING, type_id(pn_data_type(d)));
+decoder& decoder::operator>>(std::string &x) {
+    state_guard sg(*this);
+    switch (pre_get()) {
+      case STRING: x = str(pn_data_get_string(pn_object())); break;
+      case BINARY: x = str(pn_data_get_binary(pn_object())); break;
+      case SYMBOL: x = str(pn_data_get_symbol(pn_object())); break;
+      default: assert_type_equal(STRING, type_id(pn_data_type(pn_object())));
     }
-    ss.cancel();
+    sg.cancel();
     return *this;
 }
 
-void assert_map_scope(const scope& s) {
-    if (s.type != MAP)
-        throw conversion_error("cannot decode "+type_name(s.type)+" as map");
-    if (s.size % 2 != 0)
-        throw conversion_error("odd number of elements in map");
-}
-
-
-} // internal
+} // codec
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/duration.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/duration.cpp b/proton-c/bindings/cpp/src/duration.cpp
index 6becb99..15c3369 100644
--- a/proton-c/bindings/cpp/src/duration.cpp
+++ b/proton-c/bindings/cpp/src/duration.cpp
@@ -31,12 +31,6 @@ const duration duration::IMMEDIATE(0);
 const duration duration::SECOND(1000);
 const duration duration::MINUTE(SECOND * 60);
 
-std::ostream& operator<<(std::ostream& o, timestamp ts) {
-    return o << "timestamp:" << ts.ms() << "ms";
-}
-
-std::ostream& operator<<(std::ostream& o, duration d) {
-    return o << d.ms() << "ms";
-}
+std::ostream& operator<<(std::ostream& o, duration d) { return o << d.ms(); }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/encoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/encoder.cpp b/proton-c/bindings/cpp/src/encoder.cpp
index 7db2a99..a8322c8 100644
--- a/proton-c/bindings/cpp/src/encoder.cpp
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -17,44 +17,39 @@
  * under the License.
  */
 
-#include "proton/amqp.hpp"
-#include "proton/annotation_key.hpp"
-#include "proton/binary.hpp"
-#include "proton/data.hpp"
-#include "proton/decimal.hpp"
-#include "proton/encoder.hpp"
-#include "proton/message_id.hpp"
-#include "proton/symbol.hpp"
-#include "proton/value.hpp"
-
 #include "proton_bits.hpp"
 #include "types_internal.hpp"
 #include "msg.hpp"
 
+#include <proton/annotation_key.hpp>
+#include <proton/binary.hpp>
+#include <proton/data.hpp>
+#include <proton/decimal.hpp>
+#include <proton/encoder.hpp>
+#include <proton/message_id.hpp>
+#include <proton/symbol.hpp>
+#include <proton/timestamp.hpp>
+#include <proton/value.hpp>
+
 #include <proton/codec.h>
 
 #include <algorithm>
 
 namespace proton {
-namespace internal {
+namespace codec {
 
-namespace {
-struct save_state {
-    pn_data_t* data;
-    pn_handle_t handle;
-    save_state(pn_data_t* d) : data(d), handle(pn_data_point(d)) {}
-    ~save_state() { if (data) pn_data_restore(data, handle); }
-    void cancel() { data = 0; }
-};
-
-void check(long result, pn_data_t* data) {
+void encoder::check(long result) {
     if (result < 0)
-        throw conversion_error(error_str(pn_data_error(data), result));
+        throw conversion_error(error_str(pn_data_error(pn_object()), result));
 }
+
+
+encoder::encoder(value& v) : data(v.data()) {
+    clear();
 }
 
 bool encoder::encode(char* buffer, size_t& size) {
-    save_state ss(pn_object()); // In case of error
+    state_guard sg(*this); // In case of error
     ssize_t result = pn_data_encode(pn_object(), buffer, size);
     if (result == PN_OVERFLOW) {
         result = pn_data_encoded_size(pn_object());
@@ -63,9 +58,9 @@ bool encoder::encode(char* buffer, size_t& size) {
             return false;
         }
     }
-    check(result, pn_object());
+    check(result);
     size = size_t(result);
-    ss.cancel();                // Don't restore state, all is well.
+    sg.cancel();                // Don't restore state, all is well.
     pn_data_clear(pn_object());
     return true;
 }
@@ -85,7 +80,7 @@ std::string encoder::encode() {
     return s;
 }
 
-encoder encoder::operator<<(const start& s) {
+encoder& encoder::operator<<(const start& s) {
     switch (s.type) {
       case ARRAY: pn_data_put_array(pn_object(), s.is_described, pn_type_t(s.element)); break;
       case MAP: pn_data_put_map(pn_object()); break;
@@ -98,7 +93,7 @@ encoder encoder::operator<<(const start& s) {
     return *this;
 }
 
-encoder encoder::operator<<(const finish&) {
+encoder& encoder::operator<<(const finish&) {
     pn_data_exit(pn_object());
     return *this;
 }
@@ -111,63 +106,51 @@ template <> pn_decimal32_t convert(const decimal32 &x) { pn_decimal32_t y; byte_
 template <> pn_decimal64_t convert(const decimal64 &x) { pn_decimal64_t y; byte_copy(y, x); return  y; }
 template <> pn_decimal128_t convert(const decimal128 &x) { pn_decimal128_t y; byte_copy(y, x); return  y; }
 
-template <class T, class U>
-encoder do_put(encoder e, pn_data_t* data, const T& x, int (*put)(pn_data_t*, U)) {
-    save_state ss(data);         // Save state in case of error.
-    check(put(data, convert<U>(x)), data);
-    ss.cancel();                // Don't restore state, all is good.
-    return e;
-}
+int pn_data_put_amqp_string(pn_data_t *d, const std::string& x) { return pn_data_put_string(d, pn_bytes(x)); }
+int pn_data_put_amqp_binary(pn_data_t *d, const binary& x) { return pn_data_put_binary(d, pn_bytes(x)); }
+int pn_data_put_amqp_symbol(pn_data_t *d, const symbol& x) { return pn_data_put_symbol(d, pn_bytes(x)); }
+} // namespace
 
-int pn_data_put_amqp_string(pn_data_t *d, const amqp::string_type& x) { return pn_data_put_string(d, pn_bytes(x)); }
-int pn_data_put_amqp_binary(pn_data_t *d, const amqp::binary_type& x) { return pn_data_put_binary(d, pn_bytes(x)); }
-int pn_data_put_amqp_symbol(pn_data_t *d, const amqp::symbol_type& x) { return pn_data_put_symbol(d, pn_bytes(x)); }
-}
-
-encoder encoder::operator<<(bool x) { return do_put(*this, pn_object(), x, pn_data_put_bool); }
-encoder encoder::operator<<(uint8_t x) { return do_put(*this, pn_object(), x, pn_data_put_ubyte); }
-encoder encoder::operator<<(int8_t x) { return do_put(*this, pn_object(), x, pn_data_put_byte); }
-encoder encoder::operator<<(uint16_t x) { return do_put(*this, pn_object(), x, pn_data_put_ushort); }
-encoder encoder::operator<<(int16_t x) { return do_put(*this, pn_object(), x, pn_data_put_short); }
-encoder encoder::operator<<(uint32_t x) { return do_put(*this, pn_object(), x, pn_data_put_uint); }
-encoder encoder::operator<<(int32_t x) { return do_put(*this, pn_object(), x, pn_data_put_int); }
-encoder encoder::operator<<(wchar_t x) { return do_put(*this, pn_object(), x, pn_data_put_char); }
-encoder encoder::operator<<(uint64_t x) { return do_put(*this, pn_object(), x, pn_data_put_ulong); }
-encoder encoder::operator<<(int64_t x) { return do_put(*this, pn_object(), x, pn_data_put_long); }
-encoder encoder::operator<<(timestamp x) { return do_put(*this, pn_object(), x.ms(), pn_data_put_timestamp); }
-encoder encoder::operator<<(float x) { return do_put(*this, pn_object(), x, pn_data_put_float); }
-encoder encoder::operator<<(double x) { return do_put(*this, pn_object(), x, pn_data_put_double); }
-encoder encoder::operator<<(decimal32 x) { return do_put(*this, pn_object(), x, pn_data_put_decimal32); }
-encoder encoder::operator<<(decimal64 x) { return do_put(*this, pn_object(), x, pn_data_put_decimal64); }
-encoder encoder::operator<<(decimal128 x) { return do_put(*this, pn_object(), x, pn_data_put_decimal128); }
-encoder encoder::operator<<(const uuid& x) { return do_put(*this, pn_object(), x, pn_data_put_uuid); }
-encoder encoder::operator<<(const std::string& x) { return do_put(*this, pn_object(), x, pn_data_put_amqp_string); }
-encoder encoder::operator<<(const symbol& x) { return do_put(*this, pn_object(), x, pn_data_put_amqp_symbol); }
-encoder encoder::operator<<(const binary& x) { return do_put(*this, pn_object(), x, pn_data_put_amqp_binary); }
-
-encoder encoder::operator<<(const scalar& x) { return do_put(*this, pn_object(), x.atom_, pn_data_put_atom); }
-
-encoder encoder::operator<<(const null&) {
-    save_state ss(pn_object());         // Save state in case of error.
-    check(pn_data_put_null(pn_object()), pn_object());
-    ss.cancel();                // Don't restore state, all is good.
+template <class T, class U>
+encoder& encoder::insert(const T& x, int (*put)(pn_data_t*, U)) {
+    state_guard sg(*this);         // Save state in case of error.
+    check(put(pn_object(), convert<U>(x)));
+    sg.cancel();                // Don't restore state, all is good.
     return *this;
 }
 
-void encoder::insert(const value& v) {
-    data mine(pn_object());
-    if (mine == v.data_)
+encoder& encoder::operator<<(bool x) { return insert(x, pn_data_put_bool); }
+encoder& encoder::operator<<(uint8_t x) { return insert(x, pn_data_put_ubyte); }
+encoder& encoder::operator<<(int8_t x) { return insert(x, pn_data_put_byte); }
+encoder& encoder::operator<<(uint16_t x) { return insert(x, pn_data_put_ushort); }
+encoder& encoder::operator<<(int16_t x) { return insert(x, pn_data_put_short); }
+encoder& encoder::operator<<(uint32_t x) { return insert(x, pn_data_put_uint); }
+encoder& encoder::operator<<(int32_t x) { return insert(x, pn_data_put_int); }
+encoder& encoder::operator<<(wchar_t x) { return insert(x, pn_data_put_char); }
+encoder& encoder::operator<<(uint64_t x) { return insert(x, pn_data_put_ulong); }
+encoder& encoder::operator<<(int64_t x) { return insert(x, pn_data_put_long); }
+encoder& encoder::operator<<(timestamp x) { return insert(x.ms(), pn_data_put_timestamp); }
+encoder& encoder::operator<<(float x) { return insert(x, pn_data_put_float); }
+encoder& encoder::operator<<(double x) { return insert(x, pn_data_put_double); }
+encoder& encoder::operator<<(decimal32 x) { return insert(x, pn_data_put_decimal32); }
+encoder& encoder::operator<<(decimal64 x) { return insert(x, pn_data_put_decimal64); }
+encoder& encoder::operator<<(decimal128 x) { return insert(x, pn_data_put_decimal128); }
+encoder& encoder::operator<<(const uuid& x) { return insert(x, pn_data_put_uuid); }
+encoder& encoder::operator<<(const std::string& x) { return insert(x, pn_data_put_amqp_string); }
+encoder& encoder::operator<<(const symbol& x) { return insert(x, pn_data_put_amqp_symbol); }
+encoder& encoder::operator<<(const binary& x) { return insert(x, pn_data_put_amqp_binary); }
+
+encoder& encoder::operator<<(const scalar& x) { return insert(x.atom_, pn_data_put_atom); }
+
+encoder& encoder::operator<<(exact_cref<value> x) {
+    if (*this == x.ref.data_)
         throw conversion_error("cannot insert into self");
-    if (v.empty()) {
+    if (x.ref.empty())
         pn_data_put_null(pn_object());
-    } else {
-        v.decode();                 // Rewind
-        check(mine.append(v.data()), pn_object());
-    }
+    decoder d(x.ref);                 // Rewind
+    check(append(d));
+    return *this;
 }
 
-std::ostream& operator<<(std::ostream& o, const encoder& e) {
-    return o << data(e.pn_object());
-}
-}
-}
+} // codec
+} // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/engine_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/engine_test.cpp b/proton-c/bindings/cpp/src/engine_test.cpp
index d386d6d..a10842a 100644
--- a/proton-c/bindings/cpp/src/engine_test.cpp
+++ b/proton-c/bindings/cpp/src/engine_test.cpp
@@ -23,7 +23,7 @@
 #include <proton/connection_engine.hpp>
 #include <proton/handler.hpp>
 #include <proton/event.hpp>
-#include <proton/types.hpp>
+#include <proton/types_fwd.hpp>
 #include <proton/link.hpp>
 #include <deque>
 #include <algorithm>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/id_generator.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/id_generator.hpp b/proton-c/bindings/cpp/src/id_generator.hpp
index 867d827..f3df1e8 100644
--- a/proton-c/bindings/cpp/src/id_generator.hpp
+++ b/proton-c/bindings/cpp/src/id_generator.hpp
@@ -18,7 +18,7 @@
  */
 
 ///@internal
-#include "proton/types.hpp"
+#include "proton/types_fwd.hpp"
 
 #ifndef ID_GENERATOR_HPP
 #define ID_GENERATOR_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/interop_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/interop_test.cpp b/proton-c/bindings/cpp/src/interop_test.cpp
index 083e0bc..b05c098 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -19,8 +19,8 @@
 
 #include "proton/decoder.hpp"
 #include "proton/encoder.hpp"
+#include "proton/error.hpp"
 #include "proton/value.hpp"
-#include "proton/amqp.hpp"
 #include "test_bits.hpp"
 #include <string>
 #include <sstream>
@@ -30,7 +30,7 @@
 
 using namespace std;
 using namespace proton;
-using namespace proton::internal;
+using namespace proton::codec;
 using namespace test;
 
 std::string tests_dir;
@@ -43,23 +43,25 @@ string read(string filename) {
 }
 
 template <class T> T get(decoder& d) {
+    assert_type_equal(type_id_of<T>::value, d.next_type());
     T v;
-    d >> assert_type(type_id_of<T>::value) >> v;
+    d >> v;
     return v;
 }
 
 // Test data ostream operator
 void test_data_ostream() {
     value dv;
-    dv.decode().decode(read("primitives"));
+    decoder d(dv);
+    d.decode(read("primitives"));
     ASSERT_EQUAL("true, false, 42, 42, -42, 12345, -12345, 12345, -12345, 0.125, 0.125", str(dv));
 }
 
 // Test extracting to exact AMQP types works corectly, extrating to invalid types fails.
 void test_decoder_primitves_exact() {
     value dv;
-    dv.decode().decode(read("primitives"));
-    decoder d(dv.decode());
+    decoder d(dv);
+    d.decode(read("primitives"));
     ASSERT(d.more());
     try { get< ::int8_t>(d); FAIL("got bool as byte"); } catch(conversion_error){}
     ASSERT_EQUAL(true, get<bool>(d));
@@ -84,7 +86,7 @@ void test_decoder_primitves_exact() {
 // Test inserting primitive sand encoding as AMQP.
 void test_encoder_primitives() {
     value dv;
-    encoder e = dv.encode();
+    encoder e(dv);
     e << true << false;
     e << ::uint8_t(42);
     e << ::uint16_t(42) << ::int16_t(-42);
@@ -100,11 +102,11 @@ void test_encoder_primitives() {
 void test_value_conversions() {
     value v;
     ASSERT_EQUAL(true, (v=true).get<bool>());
-    ASSERT_EQUAL(2, (v=amqp::byte_type(2)).get<int>());
-    ASSERT_EQUAL(3, (v=amqp::byte_type(3)).get<long>());
-    ASSERT_EQUAL(3, (v=amqp::byte_type(3)).get<long>());
-    ASSERT_EQUAL(1.0, (v=amqp::float_type(1.0)).get<double>());
-    ASSERT_EQUAL(1.0, (v=amqp::double_type(1.0)).get<float>());
+    ASSERT_EQUAL(2, (v=int8_t(2)).get<int>());
+    ASSERT_EQUAL(3, (v=int8_t(3)).get<long>());
+    ASSERT_EQUAL(3, (v=int8_t(3)).get<long>());
+    ASSERT_EQUAL(1.0, (v=float(1.0)).get<double>());
+    ASSERT_EQUAL(1.0, (v=double(1.0)).get<float>());
     try { (void)(v = int8_t(1)).get<bool>(); FAIL("got byte as bool"); } catch (conversion_error) {}
     try { (void)(v = true).get<float>(); FAIL("got bool as float"); } catch (conversion_error) {}
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/link_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/link_options.cpp b/proton-c/bindings/cpp/src/link_options.cpp
index dd0febb..534a6b6 100644
--- a/proton-c/bindings/cpp/src/link_options.cpp
+++ b/proton-c/bindings/cpp/src/link_options.cpp
@@ -108,13 +108,13 @@ class link_options::impl {
                     if (lifetime_policy.set) lp = lifetime_policy_symbol(lifetime_policy.value);
                     if (!sender && distribution_mode.set) dm = distribution_mode_symbol(distribution_mode.value);
                     if (lp.size() || dm.size()) {
-                        internal::encoder enc = t.node_properties().encode();
-                        enc << internal::start::map();
+                        codec::encoder enc(t.node_properties());
+                        enc << codec::start::map();
                         if (dm.size())
                             enc << symbol("supported-dist-modes") << std::string(dm);
                         if (lp.size())
-                            enc << symbol("lifetime-policy") << internal::start::described()
-                                << symbol(lp) << internal::start::list() << internal::finish();
+                            enc << symbol("lifetime-policy") << codec::start::described()
+                                << symbol(lp) << codec::start::list() << codec::finish();
                     }
                 }
             }
@@ -126,9 +126,9 @@ class link_options::impl {
                     l.local_source().expiry_policy(terminus::EXPIRE_NEVER);
                 }
                 if (selector.set && selector.value.size()) {
-                    internal::encoder enc = l.local_source().filter().encode();
-                    enc << internal::start::map() << symbol("selector") << internal::start::described()
-                        << symbol("apache.org:selector-filter:string") << binary(selector.value) << internal::finish();
+                    codec::encoder enc(l.local_source().filter());
+                    enc << codec::start::map() << symbol("selector") << codec::start::described()
+                        << symbol("apache.org:selector-filter:string") << binary(selector.value) << codec::finish();
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
index 2b793f8..6d95256 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -19,16 +19,17 @@
  *
  */
 
-#include "proton/data.hpp"
-#include "proton/message.hpp"
+#include "proton/delivery.hpp"
 #include "proton/error.hpp"
 #include "proton/link.hpp"
-#include "proton/delivery.hpp"
-#include "proton/message.h"
-#include "proton/sender.hpp"
-#include "proton/receiver.hpp"
+#include "proton/message.hpp"
 #include "proton/message_id.hpp"
-#include "proton/delivery.h"
+#include "proton/receiver.hpp"
+#include "proton/sender.hpp"
+#include "proton/timestamp.hpp"
+
+#include "proton/message.h"
+
 #include "msg.hpp"
 #include "proton_bits.hpp"
 #include "types_internal.hpp"
@@ -46,8 +47,10 @@ message::message(const message &m) : pn_msg_(0) { *this = m; }
 message::message(message &&m) : pn_msg_(0) { swap(*this, m); }
 #endif
 
+message::message(const value& x) : pn_msg_(0) { body() = x; }
+
 message::~message() {
-    body_.data_ = internal::data(0);      // Must release body before pn_message_free
+    body_.data_ = codec::data(0);      // Must release body before pn_message_free
     pn_message_free(pn_msg_);
 }
 
@@ -126,7 +129,8 @@ std::string message::reply_to() const {
 }
 
 void message::correlation_id(const message_id& id) {
-    internal::data(pn_message_correlation_id(pn_msg())).copy(id.scalar_);
+    codec::encoder e(pn_message_correlation_id(pn_msg()));
+    e << id.scalar_;
 }
 
 message_id message::correlation_id() const {
@@ -187,6 +191,8 @@ bool message::inferred() const { return pn_message_is_inferred(pn_msg()); }
 
 void message::inferred(bool b) { pn_message_set_inferred(pn_msg(), b); }
 
+void message::body(const value& x) { body() = x; }
+
 const value& message::body() const { pn_msg(); return body_; }
 value& message::body() { pn_msg(); return body_; }
 
@@ -197,9 +203,10 @@ value& message::body() { pn_msg(); return body_; }
 
 // Decode a map on demand
 template<class M> M& get_map(pn_message_t* msg, pn_data_t* (*get)(pn_message_t*), M& map) {
-    internal::data d(get(msg));
+    codec::decoder d(get(msg));
     if (map.empty() && !d.empty()) {
-        d.decoder() >> internal::rewind() >> map;
+        d.rewind();
+        d >> map;
         d.clear();              // The map member is now the authority.
     }
     return map;
@@ -207,10 +214,10 @@ template<class M> M& get_map(pn_message_t* msg, pn_data_t* (*get)(pn_message_t*)
 
 // Encode a map if necessary.
 template<class M> M& put_map(pn_message_t* msg, pn_data_t* (*get)(pn_message_t*), M& map) {
-    internal::data d(get(msg));
-    if (d.empty() && !map.empty()) {
-        d.encoder() << map;
-        map.clear();        // The encoded pn_data_t  is now the authority.
+    codec::encoder e(get(msg));
+    if (e.empty() && !map.empty()) {
+        e << map;
+        map.clear();            // The encoded pn_data_t  is now the authority.
     }
     return map;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/msg.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/msg.hpp b/proton-c/bindings/cpp/src/msg.hpp
index 66c01cb..b24b25c 100644
--- a/proton-c/bindings/cpp/src/msg.hpp
+++ b/proton-c/bindings/cpp/src/msg.hpp
@@ -43,7 +43,7 @@ struct msg {
     msg(const msg& m) : os(m.str()) {}
     std::string str() const { return os.str(); }
     operator std::string() const { return str(); }
-    template <class T> msg& operator<<(const T& t) { os <<t; return *this; }
+    template <class T> msg& operator<<(const T& t) { os << t; return *this; }
 };
 
 inline std::ostream& operator<<(std::ostream& o, const msg& m) { return o << m.str(); }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/posix/io.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/posix/io.cpp b/proton-c/bindings/cpp/src/posix/io.cpp
index a85972a..be9db44 100644
--- a/proton-c/bindings/cpp/src/posix/io.cpp
+++ b/proton-c/bindings/cpp/src/posix/io.cpp
@@ -18,10 +18,12 @@
  */
 
 #include "msg.hpp"
+
 #include <proton/io.hpp>
 #include <proton/url.hpp>
 
 #include <errno.h>
+#include <string.h>
 #include <fcntl.h>
 #include <netdb.h>
 #include <sys/socket.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/reactor.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/reactor.hpp b/proton-c/bindings/cpp/src/reactor.hpp
index 6022e7e..3aac8f8 100644
--- a/proton-c/bindings/cpp/src/reactor.hpp
+++ b/proton-c/bindings/cpp/src/reactor.hpp
@@ -28,6 +28,7 @@
 #include "proton/timestamp.hpp"
 
 struct pn_reactor_t;
+struct pn_handler_t;
 struct pn_io_t;
 
 namespace proton {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/scalar.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar.cpp b/proton-c/bindings/cpp/src/scalar.cpp
index 04e5318..2cda8af 100644
--- a/proton-c/bindings/cpp/src/scalar.cpp
+++ b/proton-c/bindings/cpp/src/scalar.cpp
@@ -43,6 +43,7 @@ scalar& scalar::operator=(const scalar& x) {
 }
 
 type_id scalar::type() const { return type_id(atom_.type); }
+
 bool scalar::empty() const { return type() == NULL_TYPE; }
 
 void scalar::set(const std::string& x, pn_type_t t) {
@@ -58,6 +59,28 @@ void scalar::set(const pn_atom_t& atom) {
         atom_ = atom;
 }
 
+scalar::scalar(bool x) { *this = x; }
+scalar::scalar(uint8_t x) { *this = x; }
+scalar::scalar(int8_t x) { *this = x; }
+scalar::scalar(uint16_t x) { *this = x; }
+scalar::scalar(int16_t x) { *this = x; }
+scalar::scalar(uint32_t x) { *this = x; }
+scalar::scalar(int32_t x) { *this = x; }
+scalar::scalar(uint64_t x) { *this = x; }
+scalar::scalar(int64_t x) { *this = x; }
+scalar::scalar(wchar_t x) { *this = x; }
+scalar::scalar(float x) { *this = x; }
+scalar::scalar(double x) { *this = x; }
+scalar::scalar(timestamp x) { *this = x; }
+scalar::scalar(const decimal32& x) { *this = x; }
+scalar::scalar(const decimal64& x) { *this = x; }
+scalar::scalar(const decimal128& x) { *this = x; }
+scalar::scalar(const uuid& x) { *this = x; }
+scalar::scalar(const std::string& x) { *this = x; }
+scalar::scalar(const symbol& x) { *this = x; }
+scalar::scalar(const binary& x) { *this = x; }
+scalar::scalar(const char* x) { *this = x; }
+
 scalar& scalar::operator=(bool x) { atom_.u.as_bool = x; atom_.type = PN_BOOL; return *this; }
 scalar& scalar::operator=(uint8_t x) { atom_.u.as_ubyte = x; atom_.type = PN_UBYTE; return *this; }
 scalar& scalar::operator=(int8_t x) { atom_.u.as_byte = x; atom_.type = PN_BYTE; return *this; }
@@ -193,7 +216,7 @@ template <class T, class F> T type_switch(const scalar& a, F f) {
       case STRING: return f(a.get<std::string>());
       case SYMBOL: return f(a.get<symbol>());
       default:
-        throw error("bad scalar type");
+        throw std::logic_error("bad proton::scalar type");
     }
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/scalar_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar_test.cpp b/proton-c/bindings/cpp/src/scalar_test.cpp
index 2949dcb..9b2df1f 100644
--- a/proton-c/bindings/cpp/src/scalar_test.cpp
+++ b/proton-c/bindings/cpp/src/scalar_test.cpp
@@ -19,8 +19,8 @@
 
 #include "test_bits.hpp"
 
-#include "proton/amqp.hpp"
 #include "proton/binary.hpp"
+#include "proton/error.hpp"
 #include "proton/type_traits.hpp"
 
 #include <proton/scalar.hpp>
@@ -126,25 +126,25 @@ template <class T> T make(const char c) { T x; std::fill(x.begin(), x.end(), c);
 int main(int, char**) {
     int failed = 0;
     RUN_TEST(failed, type_test(false, BOOLEAN, true));
-    RUN_TEST(failed, type_test(amqp::ubyte_type(42), UBYTE, amqp::ubyte_type(50)));
-    RUN_TEST(failed, type_test(amqp::byte_type('x'), BYTE, amqp::byte_type('y')));
-    RUN_TEST(failed, type_test(amqp::ushort_type(4242), USHORT, amqp::ushort_type(5252)));
-    RUN_TEST(failed, type_test(amqp::short_type(-4242), SHORT, amqp::short_type(3)));
-    RUN_TEST(failed, type_test(amqp::uint_type(4242), UINT, amqp::uint_type(5252)));
-    RUN_TEST(failed, type_test(amqp::int_type(-4242), INT, amqp::int_type(3)));
-    RUN_TEST(failed, type_test(amqp::ulong_type(4242), ULONG, amqp::ulong_type(5252)));
-    RUN_TEST(failed, type_test(amqp::long_type(-4242), LONG, amqp::long_type(3)));
+    RUN_TEST(failed, type_test(uint8_t(42), UBYTE, uint8_t(50)));
+    RUN_TEST(failed, type_test(int8_t('x'), BYTE, int8_t('y')));
+    RUN_TEST(failed, type_test(uint16_t(4242), USHORT, uint16_t(5252)));
+    RUN_TEST(failed, type_test(int16_t(-4242), SHORT, int16_t(3)));
+    RUN_TEST(failed, type_test(uint32_t(4242), UINT, uint32_t(5252)));
+    RUN_TEST(failed, type_test(int32_t(-4242), INT, int32_t(3)));
+    RUN_TEST(failed, type_test(uint64_t(4242), ULONG, uint64_t(5252)));
+    RUN_TEST(failed, type_test(int64_t(-4242), LONG, int64_t(3)));
     RUN_TEST(failed, type_test(wchar_t(23), CHAR, wchar_t(24)));
-    RUN_TEST(failed, type_test(amqp::float_type(1.234), FLOAT, amqp::float_type(2.345)));
-    RUN_TEST(failed, type_test(amqp::double_type(11.2233), DOUBLE, amqp::double_type(12)));
+    RUN_TEST(failed, type_test(float(1.234), FLOAT, float(2.345)));
+    RUN_TEST(failed, type_test(double(11.2233), DOUBLE, double(12)));
     RUN_TEST(failed, type_test(timestamp(0), TIMESTAMP, timestamp(1)));
     RUN_TEST(failed, type_test(make<decimal32>(0), DECIMAL32, make<decimal32>(1)));
     RUN_TEST(failed, type_test(make<decimal64>(0), DECIMAL64, make<decimal64>(1)));
     RUN_TEST(failed, type_test(make<decimal128>(0), DECIMAL128, make<decimal128>(1)));
-    RUN_TEST(failed, type_test(uuid::make("a"), UUID, uuid::make("x")));
-    RUN_TEST(failed, type_test(amqp::string_type("aaa"), STRING, amqp::string_type("aaaa")));
-    RUN_TEST(failed, type_test(amqp::symbol_type("aaa"), SYMBOL, amqp::symbol_type("aaaa")));
-    RUN_TEST(failed, type_test(amqp::binary_type("aaa"), BINARY, amqp::binary_type("aaaa")));
+    RUN_TEST(failed, type_test(uuid::copy("a"), UUID, uuid::copy("x")));
+    RUN_TEST(failed, type_test(std::string("aaa"), STRING, std::string("aaaa")));
+    RUN_TEST(failed, type_test(symbol("aaa"), SYMBOL, symbol("aaaa")));
+    RUN_TEST(failed, type_test(binary("aaa"), BINARY, binary("aaaa")));
     RUN_TEST(failed, type_test(std::string("xxx"), STRING, std::string("yyy")));
     RUN_TEST(failed, encode_decode_test());
     RUN_TEST(failed, message_id_test());

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/test_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/test_bits.hpp b/proton-c/bindings/cpp/src/test_bits.hpp
index f6297da..d45739c 100644
--- a/proton-c/bindings/cpp/src/test_bits.hpp
+++ b/proton-c/bindings/cpp/src/test_bits.hpp
@@ -19,13 +19,13 @@
  * under the License.
  */
 
+#include "msg.hpp"
+#include <proton/types.hpp>
+
 #include <stdexcept>
 #include <iostream>
-#include <vector>
-#include <deque>
 #include <iterator>
 #include <sstream>
-#include "msg.hpp"
 
 namespace test {
 
@@ -59,15 +59,17 @@ template<class T> std::string str(const T& x) { std::ostringstream s; s << x; re
 template <class T> struct many : public std::vector<T> {
     many() {}
     template<class S> explicit many(const S& s) : std::vector<T>(s.begin(), s.end()) {}
-    many operator+(const T& t) { many<T> l(*this); l.push_back(t); return l; }
+    many& operator+=(const T& t) { this->push_back(t); return *this; }
+    many& operator<<(const T& t) { return *this += t; }
+    many operator+(const T& t) { many<T> l(*this); return l += t; }
 };
 
 template <class T, class S> bool operator==(const many<T>& m, const S& s) {
-    return S(m.begin(), m.end()) == s;
+    return m.size() == s.size() && S(m.begin(), m.end()) == s;
 }
 
 template <class T, class S> bool operator==(const S& s, const many<T>& m) {
-    return S(m.begin(), m.end()) == s;
+    return m.size() == s.size() && S(m.begin(), m.end()) == s;
 }
 
 template <class T> std::ostream& operator<<(std::ostream& o, const many<T>& m) {
@@ -87,9 +89,27 @@ template <class T> std::ostream& operator<<(std::ostream& o, const std::deque<T>
     return o << test::many<T>(s);
 }
 
+template <class T> std::ostream& operator<<(std::ostream& o, const std::list<T>& s) {
+    return o << test::many<T>(s);
+}
+
+template <class K, class T> std::ostream& operator<<(std::ostream& o, const std::map<K, T>& x) {
+    return o << test::many<std::pair<K, T> >(x);
+}
+
 template <class U, class V> std::ostream& operator<<(std::ostream& o, const std::pair<U, V>& p) {
     return o << "( " << p.first << " , " << p.second << " )";
 }
+
+#if PN_CPP_HAS_CPP11
+template <class K, class T> std::ostream& operator<<(std::ostream& o, const std::unordered_map<K, T>& x) {
+    return o << test::many<std::pair<const K, T> >(x);
+}
+
+template <class T> std::ostream& operator<<(std::ostream& o, const std::forward_list<T>& s) {
+    return o << test::many<T>(s);
+}
+#endif
 }
 
 #endif // TEST_BITS_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/timestamp.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/timestamp.cpp b/proton-c/bindings/cpp/src/timestamp.cpp
index 67ce39b..523b29e 100644
--- a/proton-c/bindings/cpp/src/timestamp.cpp
+++ b/proton-c/bindings/cpp/src/timestamp.cpp
@@ -19,9 +19,14 @@
 
 #include <proton/timestamp.hpp>
 #include <proton/types.h>
+#include <iostream>
 
 namespace proton {
+
 timestamp timestamp::now() {
     return timestamp(pn_timestamp_now());
 }
+
+std::ostream& operator<<(std::ostream& o, timestamp ts) { return o << ts.ms(); }
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/transport.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/transport.cpp b/proton-c/bindings/cpp/src/transport.cpp
index dc608bf..8883806 100644
--- a/proton-c/bindings/cpp/src/transport.cpp
+++ b/proton-c/bindings/cpp/src/transport.cpp
@@ -18,13 +18,18 @@
  * under the License.
  *
  */
+
+#include "proton/error.hpp"
 #include "proton/transport.hpp"
 #include "proton/condition.hpp"
 #include "proton/connection.hpp"
 #include "proton/ssl.hpp"
 #include "proton/sasl.hpp"
-#include "msg.hpp"
 #include "proton/transport.h"
+#include "proton/error.h"
+
+#include "msg.hpp"
+
 
 namespace proton {
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/type_id.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/type_id.cpp b/proton-c/bindings/cpp/src/type_id.cpp
new file mode 100644
index 0000000..57f950a
--- /dev/null
+++ b/proton-c/bindings/cpp/src/type_id.cpp
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "types_internal.hpp"
+
+#include <proton/type_id.hpp>
+
+#include <ostream>
+
+namespace proton {
+
+std::string type_name(type_id t) {
+    switch (t) {
+      case NULL_TYPE: return "null";
+      case BOOLEAN: return "boolean";
+      case UBYTE: return "ubyte";
+      case BYTE: return "byte";
+      case USHORT: return "ushort";
+      case SHORT: return "short";
+      case UINT: return "uint";
+      case INT: return "int";
+      case CHAR: return "char";
+      case ULONG: return "ulong";
+      case LONG: return "long";
+      case TIMESTAMP: return "timestamp";
+      case FLOAT: return "float";
+      case DOUBLE: return "double";
+      case DECIMAL32: return "decimal32";
+      case DECIMAL64: return "decimal64";
+      case DECIMAL128: return "decimal128";
+      case UUID: return "uuid";
+      case BINARY: return "binary";
+      case STRING: return "string";
+      case SYMBOL: return "symbol";
+      case DESCRIBED: return "described";
+      case ARRAY: return "array";
+      case LIST: return "list";
+      case  MAP: return "map";
+    }
+    return "unknown";
+}
+
+std::ostream& operator<<(std::ostream& o, type_id t) { return o << type_name(t); }
+
+void assert_type_equal(type_id want, type_id got) {
+    if (want != got) throw make_conversion_error(want, got);
+}
+
+} // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/types.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/types.cpp b/proton-c/bindings/cpp/src/types.cpp
deleted file mode 100644
index f64d0b6..0000000
--- a/proton-c/bindings/cpp/src/types.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <proton/types.hpp>
-#include <proton/type_traits.hpp>
-#include <proton/codec.h>
-#include <ostream>
-#include <iomanip>
-#include <algorithm>
-#include <sstream>
-
-namespace proton {
-
-std::string type_name(type_id t) {
-    switch (t) {
-      case NULL_TYPE: return "null";
-      case BOOLEAN: return "boolean";
-      case UBYTE: return "ubyte";
-      case BYTE: return "byte";
-      case USHORT: return "ushort";
-      case SHORT: return "short";
-      case UINT: return "uint";
-      case INT: return "int";
-      case CHAR: return "char";
-      case ULONG: return "ulong";
-      case LONG: return "long";
-      case TIMESTAMP: return "timestamp";
-      case FLOAT: return "float";
-      case DOUBLE: return "double";
-      case DECIMAL32: return "decimal32";
-      case DECIMAL64: return "decimal64";
-      case DECIMAL128: return "decimal128";
-      case UUID: return "uuid";
-      case BINARY: return "binary";
-      case STRING: return "string";
-      case SYMBOL: return "symbol";
-      case DESCRIBED: return "described";
-      case ARRAY: return "array";
-      case LIST: return "list";
-      case  MAP: return "map";
-    }
-    return "unknown";
-}
-
-bool type_id_is_signed_int(type_id t) { return t == BYTE || t == SHORT || t == INT || t == LONG; }
-bool type_id_is_unsigned_int(type_id t) { return t == UBYTE || t == USHORT || t == UINT || t == ULONG; }
-bool type_id_is_integral(type_id t) { return t == BOOLEAN || t == CHAR || t == TIMESTAMP || type_id_is_unsigned_int(t) || type_id_is_signed_int(t); }
-bool type_id_is_floating_point(type_id t) { return t == FLOAT || t == DOUBLE; }
-bool type_id_is_decimal(type_id t) { return t == DECIMAL32 || t == DECIMAL64 || t == DECIMAL128; }
-bool type_id_is_signed(type_id t) { return type_id_is_signed_int(t) || type_id_is_floating_point(t) || type_id_is_decimal(t); }
-bool type_id_is_string_like(type_id t) { return t == BINARY || t == STRING || t == SYMBOL; }
-bool type_id_is_container(type_id t) { return t == LIST || t == MAP || t == ARRAY || t == DESCRIBED; }
-bool type_id_is_scalar(type_id t) { return type_id_is_integral(t) || type_id_is_floating_point(t) || type_id_is_decimal(t) || type_id_is_string_like(t) || t == TIMESTAMP || t == UUID; }
-
-
-std::ostream& operator<<(std::ostream& o, type_id t) { return o << type_name(t); }
-
-namespace internal {
-start::start(type_id t, type_id e, bool d, size_t s) : type(t), element(e), is_described(d), size(s) {}
-start start::array(type_id element, bool described) { return start(ARRAY, element, described); }
-start start::list() { return start(LIST); }
-start start::map() { return start(MAP); }
-start start::described() { return start(DESCRIBED, NULL_TYPE, true); }
-}
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/types_internal.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/types_internal.hpp b/proton-c/bindings/cpp/src/types_internal.hpp
index 1c0de8a..3cf775c 100644
--- a/proton-c/bindings/cpp/src/types_internal.hpp
+++ b/proton-c/bindings/cpp/src/types_internal.hpp
@@ -30,7 +30,7 @@ namespace proton {
 
 /// Byte copy between two objects, only enabled if their sizes are equal.
 template <class T, class U>
-typename internal::enable_if<sizeof(T) == sizeof(U)>::type byte_copy(T &to, const U &from) {
+typename codec::enable_if<sizeof(T) == sizeof(U)>::type byte_copy(T &to, const U &from) {
     const char *p = reinterpret_cast<const char*>(&from);
     std::copy(p, p + sizeof(T), reinterpret_cast<char*>(&to));
 }
@@ -52,6 +52,16 @@ inline pn_bytes_t pn_bytes(const std::string& s) {
 /// Convert pn_bytes_t to str
 inline std::string str(const pn_bytes_t& b) { return std::string(b.start, b.size); }
 
+inline bool type_id_is_signed_int(type_id t) { return t == BYTE || t == SHORT || t == INT || t == LONG; }
+inline bool type_id_is_unsigned_int(type_id t) { return t == UBYTE || t == USHORT || t == UINT || t == ULONG; }
+inline bool type_id_is_integral(type_id t) { return t == BOOLEAN || t == CHAR || t == TIMESTAMP || type_id_is_unsigned_int(t) || type_id_is_signed_int(t); }
+inline bool type_id_is_floating_point(type_id t) { return t == FLOAT || t == DOUBLE; }
+inline bool type_id_is_decimal(type_id t) { return t == DECIMAL32 || t == DECIMAL64 || t == DECIMAL128; }
+inline bool type_id_is_signed(type_id t) { return type_id_is_signed_int(t) || type_id_is_floating_point(t) || type_id_is_decimal(t); }
+inline bool type_id_is_string_like(type_id t) { return t == BINARY || t == STRING || t == SYMBOL; }
+inline bool type_id_is_container(type_id t) { return t == LIST || t == MAP || t == ARRAY || t == DESCRIBED; }
+inline bool type_id_is_scalar(type_id t) { return type_id_is_integral(t) || type_id_is_floating_point(t) || type_id_is_decimal(t) || type_id_is_string_like(t) || t == TIMESTAMP || t == UUID; }
+
 }
 
 #endif // CODEC_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/uuid.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/uuid.cpp b/proton-c/bindings/cpp/src/uuid.cpp
index 9e64cca..f224df7 100644
--- a/proton-c/bindings/cpp/src/uuid.cpp
+++ b/proton-c/bindings/cpp/src/uuid.cpp
@@ -17,7 +17,8 @@
  * under the License.
  */
 
-#include "proton/uuid.hpp"
+#include <proton/uuid.hpp>
+#include <proton/types_fwd.hpp>
 
 #include <cstdlib>
 #include <ctime>
@@ -56,7 +57,7 @@ struct ios_guard {
 };
 }
 
-uuid uuid::make(const char* bytes) {
+uuid uuid::copy(const char* bytes) {
     uuid u;
     if (bytes)
         std::copy(bytes, bytes + u.size(), u.begin());
@@ -87,12 +88,13 @@ std::ostream& operator<<(std::ostream& o, const uuid& u) {
     ios_guard restore_flags(o);
     o << std::hex << std::setfill('0');
     static const int segments[] = {4,2,2,2,6}; // 1 byte is 2 hex chars.
-    const char *p = u.begin();
+    const uint8_t *p = reinterpret_cast<const uint8_t*>(u.begin());
     for (size_t i = 0; i < sizeof(segments)/sizeof(segments[0]); ++i) {
         if (i > 0)
             o << '-';
-        for (int j = 0; j < segments[i]; ++j)
+        for (int j = 0; j < segments[i]; ++j) {
             o << std::setw(2) << int(*(p++));
+        }
     }
     return o;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4fa5fa41/proton-c/bindings/cpp/src/value.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/value.cpp b/proton-c/bindings/cpp/src/value.cpp
index dda20f2..44d696d 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -20,19 +20,23 @@
 #include "proton_bits.hpp"
 #include "proton/data.hpp"
 #include "proton/value.hpp"
+#include "proton/types.hpp"
 #include "proton/scalar.hpp"
+#include "proton/error.hpp"
 
 #include <ostream>
 
 namespace proton {
 
+using namespace codec;
+
 value::value() {}
 value::value(const null&) {}
 value::value(const value& x) { *this = x; }
-value::value(pn_data_t* p) { if (p) data().copy(internal::data(p)); }
-
+value::value(const codec::data& x) { if (!x.empty()) data().copy(x); }
 #if PN_CPP_HAS_CPP11
 value::value(value&& x) { swap(*this, x); }
+value& value::operator=(value&& x) { swap(*this, x); return *this; }
 #endif
 
 value& value::operator=(const null&) { clear(); return *this; }
@@ -53,39 +57,135 @@ void value::clear() { if (!!data_) data_.clear(); }
 
 bool value::empty() const { return !data_ || data_.empty(); }
 
+type_id value::type() const {
+    if (empty()) return NULL_TYPE;
+    decoder d(*this);
+    return d.next_type();
+}
+
 // On demand
-internal::data& value::data() const {
-    if (!data_) data_ = internal::data::create(); return data_;
+codec::data& value::data() const {
+    if (!data_)
+        data_ = codec::data::create();
+    return data_;
 }
 
-internal::encoder value::encode() { clear(); return data().encoder(); }
+namespace {
+
+// Compare nodes, return -1 if a<b, 0 if a==b, +1 if a>b
+// Forward-declare so we can use it recursively.
+int compare_next(decoder& a, decoder& b);
 
-internal::decoder value::decode() const { return data().decoder() >> internal::rewind(); }
+template <class T> int compare(const T& a, const T& b) {
+    if (a < b) return -1;
+    else if (a > b) return +1;
+    else return 0;
+}
+
+int compare_container(decoder& a, decoder& b) {
+    start sa, sb;
+    a >> sa;
+    b >> sb;
+    // Compare described vs. not-described.
+    int cmp = compare(sa.is_described, sb.is_described);
+    if (cmp) return cmp;
+    // Lexical sort (including descriptor if there is one)
+    size_t min_size = std::min(sa.size, sb.size) + size_t(sa.is_described);
+    for (size_t i = 0; i < min_size; ++i) {
+        cmp = compare_next(a, b);
+        if (cmp) return cmp;
+    }
+    return compare(sa.size, sb.size);
+}
+
+template <class T> int compare_simple(decoder& a, decoder& b) {
+    T va = T();
+    T vb = T();
+    a >> va;
+    b >> vb;
+    return compare(va, vb);
+}
+
+int compare_next(decoder& a, decoder& b) {
+    // Sort by type_id first.
+    type_id ta = a.next_type(), tb = b.next_type();
+    int cmp = compare(ta, tb);
+    if (cmp) return cmp;
+
+    switch (ta) {
+      case NULL_TYPE: return 0;
+      case ARRAY:
+      case LIST:
+      case MAP:
+      case DESCRIBED:
+        return compare_container(a, b);
+      case BOOLEAN: return compare_simple<bool>(a, b);
+      case UBYTE: return compare_simple<uint8_t>(a, b);
+      case BYTE: return compare_simple<int8_t>(a, b);
+      case USHORT: return compare_simple<uint16_t>(a, b);
+      case SHORT: return compare_simple<int16_t>(a, b);
+      case UINT: return compare_simple<uint32_t>(a, b);
+      case INT: return compare_simple<int32_t>(a, b);
+      case ULONG: return compare_simple<uint64_t>(a, b);
+      case LONG: return compare_simple<int64_t>(a, b);
+      case CHAR: return compare_simple<wchar_t>(a, b);
+      case TIMESTAMP: return compare_simple<timestamp>(a, b);
+      case FLOAT: return compare_simple<float>(a, b);
+      case DOUBLE: return compare_simple<double>(a, b);
+      case DECIMAL32: return compare_simple<decimal32>(a, b);
+      case DECIMAL64: return compare_simple<decimal64>(a, b);
+      case DECIMAL128: return compare_simple<decimal128>(a, b);
+      case UUID: return compare_simple<uuid>(a, b);
+      case BINARY: return compare_simple<binary>(a, b);
+      case STRING: return compare_simple<std::string>(a, b);
+      case SYMBOL: return compare_simple<symbol>(a, b);
+    }
+    // Invalid but equal type_id, treat as equal.
+    return 0;
+}
+
+int compare(const value& x, const value& y) {
+    decoder a(x), b(y);
+    state_guard s1(a), s2(b);
+    a.rewind();
+    b.rewind();
+    while (a.more() && b.more()) {
+        int cmp = compare_next(a, b);
+        if (cmp != 0) return cmp;
+    }
+    if (b.more()) return -1;
+    if (a.more()) return 1;
+    return 0;
+}
 
-type_id value::type() const { return empty() ? NULL_TYPE : decode().type(); }
+} // namespace
 
 bool operator==(const value& x, const value& y) {
     if (x.empty() && y.empty()) return true;
     if (x.empty() || y.empty()) return false;
-    return  x.data().equal(y.data());
+    return compare(x, y) == 0;
 }
 
 bool operator<(const value& x, const value& y) {
     if (x.empty() && y.empty()) return false;
     if (x.empty()) return true; // empty is < !empty
-    return x.data().less(y.data());
+    return compare(x, y) < 0;
 }
 
-std::ostream& operator<<(std::ostream& o, const value& v) {
-    if (v.empty())
+std::ostream& operator<<(std::ostream& o, exact_cref<value> v) {
+    if (v.ref.empty())
         return o << "<null>";
-    // pn_inspect prints strings with quotes which is not normal in C++.
-    switch (v.type()) {
+    switch (v.ref.type()) {
       case STRING:
-      case SYMBOL:
-        return o << v.get<std::string>();
+      case SYMBOL: return o << get<std::string>(v.ref);
+      case DECIMAL32: return o << get<decimal32>(v.ref);
+      case DECIMAL64: return o << get<decimal64>(v.ref);
+      case DECIMAL128: return o << get<decimal128>(v.ref);
+      case UUID: return o << get<uuid>(v.ref);
+      case TIMESTAMP: return o << get<timestamp>(v.ref);
       default:
-        return o << v.data();
+        // Use pn_inspect for other types.
+        return o << decoder(v.ref);
     }
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org