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/08 16:58:34 UTC

qpid-proton git commit: PROTON-1138: c++: Enable implicit value conversion

Repository: qpid-proton
Updated Branches:
  refs/heads/master 1f4337c4a -> bdaf901a1


PROTON-1138: c++: Enable implicit value conversion

Enable implicit template conversion constructor for proton::value, with
a compile-time enable_amqp_type template test to ensure it only matches
C++ types that can be encoded as AMQP values. Messge constructor and
body setter also use this test.

Type traits is_encodable and is_decodable are true if the << or >>
operators exist on the proton::encoder and proton::decoder. This means
user-defined operators for custom type encodings are respected by value
and message.

Other notes:

- encoder operator<< for value is a template to ensure exact
  match and avoid recursion via implicit conversion in is_encodable

- Moved encoder, decoder, data into proton::internal namespace.

- Cleaned up some friendships (more work to do) Make encoder/decoder operators
  members operators for built-in types (friend of class not free operator function.)


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/bdaf901a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/bdaf901a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/bdaf901a

Branch: refs/heads/master
Commit: bdaf901a13b4d710b9db845b7c102e10c7d88778
Parents: 1f4337c
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Mar 7 15:03:31 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Mar 8 10:43:43 2016 -0500

----------------------------------------------------------------------
 cpp.cmake                                       |  34 ++++
 examples/cpp/encode_decode.cpp                  |  40 ++---
 proton-c/bindings/cpp/CMakeLists.txt            |   5 +-
 .../cpp/include/proton/annotation_key.hpp       |  32 +---
 .../cpp/include/proton/connection_engine.hpp    |   1 -
 proton-c/bindings/cpp/include/proton/data.hpp   |  13 +-
 .../bindings/cpp/include/proton/decoder.hpp     | 136 +++++----------
 .../bindings/cpp/include/proton/encoder.hpp     | 100 +++++------
 .../bindings/cpp/include/proton/message.hpp     |   9 +-
 .../bindings/cpp/include/proton/message_id.hpp  |   9 +-
 proton-c/bindings/cpp/include/proton/scalar.hpp |  12 +-
 .../bindings/cpp/include/proton/type_traits.hpp | 143 +++++++++++----
 proton-c/bindings/cpp/include/proton/types.hpp  |  31 ----
 proton-c/bindings/cpp/include/proton/value.hpp  |  56 +++---
 proton-c/bindings/cpp/src/codec_test.cpp        | 123 +++++++++++++
 proton-c/bindings/cpp/src/data.cpp              |   7 +-
 proton-c/bindings/cpp/src/decoder.cpp           | 174 ++++++++++---------
 proton-c/bindings/cpp/src/encoder.cpp           |  93 +++++-----
 proton-c/bindings/cpp/src/interop_test.cpp      |   3 +-
 proton-c/bindings/cpp/src/link_options.cpp      |  14 +-
 proton-c/bindings/cpp/src/message.cpp           |  10 +-
 proton-c/bindings/cpp/src/types.cpp             |   7 +-
 proton-c/bindings/cpp/src/types_internal.hpp    |   2 +-
 proton-c/bindings/cpp/src/value.cpp             |  12 +-
 24 files changed, 603 insertions(+), 463 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/cpp.cmake
----------------------------------------------------------------------
diff --git a/cpp.cmake b/cpp.cmake
new file mode 100644
index 0000000..0998546
--- /dev/null
+++ b/cpp.cmake
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+# Check C++ capabilities.
+
+include(CheckCXXSourceCompiles)
+
+if (CMAKE_CXX_COMPILER)
+  set(CMAKE_REQUIRED_FLAGS "${CXX_WARNING_FLAGS}")
+  check_cxx_source_compiles("long long ll; int main(int, char**) { return 0; }" HAS_LONG_LONG)
+  if (HAS_LONG_LONG)
+    add_definitions(-DPN_HAS_LONG_LONG=1)
+  endif()
+  check_cxx_source_compiles("#include <memory>\nstd::shared_ptr<int> i; std::unique_ptr<int> u; int main(int, char**) { return 0; }" HAS_STD_PTR)
+  if (HAS_STD_PTR)
+    add_definitions(-DPN_HAS_STD_PTR=1)
+  endif()
+endif()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/examples/cpp/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp
index b2a07ae..8944f6d 100644
--- a/examples/cpp/encode_decode.cpp
+++ b/examples/cpp/encode_decode.cpp
@@ -77,7 +77,7 @@ void uniform_containers() {
     std::cout << a1 << std::endl;
 
     // You can specify that a container should be encoded as an AMQP list instead.
-    v = proton::as<proton::LIST>(a1);
+    v = proton::internal::as<proton::LIST>(a1);
     print(v);
     std::cout << v.get<std::vector<int> >() << std::endl;
 
@@ -94,11 +94,11 @@ void uniform_containers() {
     std::vector<std::pair<std::string, int> > pairs;
     pairs.push_back(std::make_pair("z", 3));
     pairs.push_back(std::make_pair("a", 4));
-    v = proton::as<proton::MAP>(pairs);
+    v = proton::internal::as<proton::MAP>(pairs);
     print(v);
     // You can also decode an AMQP map as a sequence of pairs using decoder() and proton::to_pairs
     std::vector<std::pair<std::string, int> > pairs2;
-    v.decode() >> proton::to_pairs(pairs2);
+    v.decode() >> proton::internal::to_pairs(pairs2);
     std::cout << pairs2 << std::endl;
 }
 
@@ -132,22 +132,22 @@ void insert_stream_operators() {
     proton::value v;
 
     // Create an array of INT with values [1, 2, 3]
-    v.encode() << proton::start::array(proton::INT)
-                << int32_t(1) << int32_t(2) << int32_t(3)
-                << proton::finish();
+    v.encode() << proton::internal::start::array(proton::INT)
+               << int32_t(1) << int32_t(2) << int32_t(3)
+               << proton::internal::finish();
     print(v);
 
     // Create a mixed-type list of the values [42, false, "x"].
-    v.encode() << proton::start::list()
-                << int32_t(42) << false << proton::symbol("x")
-                << proton::finish();
+    v.encode() << proton::internal::start::list()
+               << int32_t(42) << false << proton::symbol("x")
+               << proton::internal::finish();
     print(v);
 
     // Create a map { "k1":42, "k2": false }
-    v.encode() << proton::start::map()
-                << "k1" << int32_t(42)
-                << proton::symbol("k2") << false
-                << proton::finish();
+    v.encode() << proton::internal::start::map()
+               << "k1" << int32_t(42)
+               << proton::symbol("k2") << false
+               << proton::internal::finish();
     print(v);
 }
 
@@ -168,9 +168,9 @@ int main(int, char**) {
 // NOTE this is for example puroses only: There is a built in ostream operator<< for values.
 //
 //
-void print_next(proton::decoder& d) {
+void print_next(proton::internal::decoder& d) {
     proton::type_id type = d.type();
-    proton::start s;
+    proton::internal::start s;
     switch (type) {
       case proton::ARRAY: {
           d >> s;
@@ -185,7 +185,7 @@ void print_next(proton::decoder& d) {
               print_next(d);
           }
           std::cout << "]";
-          d >> proton::finish();
+          d >> proton::internal::finish();
           break;
       }
       case proton::LIST: {
@@ -196,7 +196,7 @@ void print_next(proton::decoder& d) {
               print_next(d);
           }
           std::cout << "]";
-          d >> proton::finish();
+          d >> proton::internal::finish();
           break;
       }
       case proton::MAP: {
@@ -209,7 +209,7 @@ void print_next(proton::decoder& d) {
               print_next(d);
           }
           std::cout << "}";
-          d >> proton::finish();
+          d >> proton::internal::finish();
           break;
       }
       case proton::DESCRIBED: {
@@ -217,7 +217,7 @@ void print_next(proton::decoder& d) {
           std::cout << "described(";
           print_next(d);      // Descriptor
           print_next(d);      // value
-          d >> proton::finish();
+          d >> proton::internal::finish();
           break;
       }
       default:
@@ -231,7 +231,7 @@ void print_next(proton::decoder& d) {
 
 // Print a value, for example purposes. Normal code can use operator<<
 void print(proton::value& v) {
-    proton::decoder d = v.decode();
+    proton::internal::decoder d = v.decode();
     d.rewind();
     while (d.more()) {
         print_next(d);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index c435e20..74a2356 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -168,8 +168,9 @@ macro(add_cpp_test test)
   endif ()
 endmacro(add_cpp_test)
 
+add_cpp_test(codec_test)
+add_cpp_test(engine_test)
 add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
 add_cpp_test(message_test)
-add_cpp_test(value_test)
 add_cpp_test(scalar_test)
-add_cpp_test(engine_test)
+add_cpp_test(value_test)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/annotation_key.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/annotation_key.hpp b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
index 30953cd..cfb883d 100644
--- a/proton-c/bindings/cpp/include/proton/annotation_key.hpp
+++ b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
@@ -20,37 +20,26 @@
  * under the License.
  */
 
-#include "proton/types.hpp"
-#include "proton/scalar.hpp"
-#include "proton/symbol.hpp"
+#include <proton/scalar.hpp>
+#include <proton/symbol.hpp>
+#include <proton/types.hpp>
 
 namespace proton {
 
-class encoder;
-class decoder;
-
 /// A key for use with AMQP annotation maps.
 ///
 /// An annotation_key can contain either a uint64_t or a proton::symbol.
 class annotation_key : public restricted_scalar {
   public:
-    /// Create an empty key.
-    annotation_key() { scalar_ = uint64_t(0); }
+    annotation_key(uint64_t x = 0) { *this = x; }
+    annotation_key(const symbol& x) { *this = x; }
+    /// `char*` is encoded as proton::amqp::symbol.
+    annotation_key(const char *x) { *this = x; }
 
-    /// @name Assignment operators
-    ///
-    /// Assign a C++ value, deducing the AMQP type().
-    ///
-    /// @{
     annotation_key& operator=(uint64_t x) { scalar_ = x; return *this; }
     annotation_key& operator=(const symbol& x) { scalar_ = x; return *this; }
     /// `char*` is encoded as proton::amqp::symbol.
     annotation_key& operator=(const char *x) { scalar_ = symbol(x); return *this; }
-    /// @}
-
-    /// A constructor that converts from any type that we can assign
-    /// from.
-    template <class T> annotation_key(T x) { *this = x; }
 
     /// @name Get methods
     ///
@@ -62,11 +51,8 @@ class annotation_key : public restricted_scalar {
     /// Return the value as type T.
     template<class T> T get() const { T x; get(x); return x; }
 
-    /// @cond INTERNAL
-    PN_CPP_EXTERN friend encoder operator<<(encoder, const annotation_key&);
-    PN_CPP_EXTERN friend decoder operator>>(decoder, annotation_key&);
-    friend class message;
-    /// @endcond
+  friend class message;
+  friend class internal::decoder;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/connection_engine.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/connection_engine.hpp b/proton-c/bindings/cpp/include/proton/connection_engine.hpp
index be6f19c..e6946c7 100644
--- a/proton-c/bindings/cpp/include/proton/connection_engine.hpp
+++ b/proton-c/bindings/cpp/include/proton/connection_engine.hpp
@@ -64,7 +64,6 @@ class connection;
 class
 PN_CPP_CLASS_EXTERN connection_engine {
   public:
-    // FIXME aconway 2016-01-23: DOC
     class container {
       public:
         /// Create a container with id.  Default to random UUID if id

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/data.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/data.hpp b/proton-c/bindings/cpp/include/proton/data.hpp
index 151b9d9..31baf0f 100644
--- a/proton-c/bindings/cpp/include/proton/data.hpp
+++ b/proton-c/bindings/cpp/include/proton/data.hpp
@@ -33,22 +33,25 @@
 struct pn_data_t;
 
 namespace proton {
+namespace internal {
 
 class data;
 
 /// Holds a sequence of AMQP values, allows inserting and extracting
 /// via encoder() and decoder().  Cannot be directly instantiated, use
 /// `value`.
-class data : public internal::object<pn_data_t> {
+class data : public object<pn_data_t> {
   public:
-    data(pn_data_t* d=0) : internal::object<pn_data_t>(d) {}
+    data(pn_data_t* d=0) : object<pn_data_t>(d) {}
 
     PN_CPP_EXTERN static data create();
 
     // Copy the contents of another data object t this one.
     PN_CPP_EXTERN data& copy(const data&);
 
-    template<class T> data& copy(T &t) { clear(); encoder() << t; return *this; }
+    template<class T> typename enable_amqp_type<T, data>::type& copy(T &t) {
+        clear(); encoder() << t; return *this;
+    }
 
     /** Clear the data. */
     PN_CPP_EXTERN void clear();
@@ -93,12 +96,12 @@ class data : public internal::object<pn_data_t> {
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const data&);
   friend class value;
   private:
-    data(internal::pn_ptr<pn_data_t> d) : internal::object<pn_data_t>(d) {}
+    data(pn_ptr<pn_data_t> d) : object<pn_data_t>(d) {}
     class decoder decoder() const { return const_cast<data*>(this)->decoder(); }
 };
 
 }
-
+}
 /// @endcond
 
 #endif // DATA_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/decoder.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/decoder.hpp b/proton-c/bindings/cpp/include/proton/decoder.hpp
index ce84824..e08ac65 100644
--- a/proton-c/bindings/cpp/include/proton/decoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/decoder.hpp
@@ -46,11 +46,13 @@ struct pn_data_t;
 namespace proton {
 
 class scalar;
-class data;
 class message_id;
 class annotation_key;
 class value;
 
+namespace internal {
+class data;
+
 /** Skips a value with `dec >> skip()`. */
 struct skip{};
 
@@ -69,9 +71,9 @@ struct rewind{};
 ///
 /// Internal use only, see proton::value, proton::scalar and proton::amqp
 /// for the recommended ways to manage AMQP data.
-class decoder : public internal::object<pn_data_t> {
+class decoder : public object<pn_data_t> {
   public:
-    decoder(pn_data_t* d) : internal::object<pn_data_t>(d) {}
+    decoder(pn_data_t* d) : object<pn_data_t>(d) {}
 
     /** Copy AMQP data from a byte buffer into the decoder. */
     PN_CPP_EXTERN decoder(const char* buffer, size_t size);
@@ -102,79 +104,49 @@ class decoder : public internal::object<pn_data_t> {
     /** Back up by one value */
     PN_CPP_EXTERN void backup();
 
-    PN_CPP_EXTERN class data data();
-
     /** @name Extract simple types
      * Overloads to extract simple types.
      * @throw error if the decoder is empty or the current value has an incompatible type.
      * @{
      */
-  friend PN_CPP_EXTERN decoder operator>>(decoder, bool&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, uint8_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, int8_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, uint16_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, int16_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, uint32_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, int32_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, wchar_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, uint64_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, int64_t&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, timestamp&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, float&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, double&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, decimal32&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, decimal64&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, decimal128&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, uuid&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, std::string&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, message_id&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, annotation_key&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, value&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, scalar&);
+    PN_CPP_EXTERN decoder operator>>(bool&);
+    PN_CPP_EXTERN decoder operator>>(uint8_t&);
+    PN_CPP_EXTERN decoder operator>>(int8_t&);
+    PN_CPP_EXTERN decoder operator>>(uint16_t&);
+    PN_CPP_EXTERN decoder operator>>(int16_t&);
+    PN_CPP_EXTERN decoder operator>>(uint32_t&);
+    PN_CPP_EXTERN decoder operator>>(int32_t&);
+    PN_CPP_EXTERN decoder operator>>(wchar_t&);
+    PN_CPP_EXTERN decoder operator>>(uint64_t&);
+    PN_CPP_EXTERN decoder operator>>(int64_t&);
+    PN_CPP_EXTERN decoder operator>>(timestamp&);
+    PN_CPP_EXTERN decoder operator>>(float&);
+    PN_CPP_EXTERN decoder operator>>(double&);
+    PN_CPP_EXTERN decoder operator>>(decimal32&);
+    PN_CPP_EXTERN decoder operator>>(decimal64&);
+    PN_CPP_EXTERN decoder operator>>(decimal128&);
+    PN_CPP_EXTERN decoder operator>>(uuid&);
+    PN_CPP_EXTERN decoder operator>>(std::string&);
+    PN_CPP_EXTERN decoder operator>>(message_id&);
+    PN_CPP_EXTERN decoder operator>>(annotation_key&);
+    PN_CPP_EXTERN decoder operator>>(scalar&);
+    PN_CPP_EXTERN decoder operator>>(value&);
     ///@}
 
-    /** Extract and return a value of type T. */
-    template <class T> T extract() { T value; *this >> value; return value; }
-
-    /** start extracting a container value, one of array, list, map, described.
-     * The basic pattern is:
-     *
-     *     start s;
-     *     dec >> s;
-     *     // check s.type() to see if this is an ARRAY, LIST, MAP or DESCRIBED type.
-     *     if (s.described) extract the descriptor...
-     *     for (size_t i = 0; i < s.size(); ++i) Extract each element...
-     *     dec >> finish();
-     *
-     * The first value of an ARRAY is a descriptor if start::descriptor is true,
-     * followed by start.size elements of type start::element.
-     *
-     * A LIST has start.size elements which may be of mixed type.
-     *
-     * A MAP has start.size elements which alternate key, value, key, value...
-     * and may be of mixed type.
-     *
-     * A DESCRIBED contains a descriptor and a single element, so it always has
-     * start.described=true and start.size=1.
-     *
-     * You must always end a complex type by extracting to an instance of `finish`,
-     * the decoder::scope automates this.
-     *
-     *@throw decoder::error if the current value is not a container type.
-     */
-    PN_CPP_EXTERN friend decoder operator>>(decoder, start&);
+    // start extracting complex type.
+    PN_CPP_EXTERN decoder operator>>(start&);
 
-    /** Finish extracting a container value. */
-    PN_CPP_EXTERN friend decoder operator>>(decoder, finish);
+    /// Finish extracting a container value. */
+    PN_CPP_EXTERN decoder operator>>(finish);
 
     /** Skip a value */
-    PN_CPP_EXTERN friend decoder operator>>(decoder, struct skip);
+    PN_CPP_EXTERN decoder operator>>(struct skip);
 
     /** Throw an exception if decoder.type() != assert_type.type */
-    PN_CPP_EXTERN friend decoder operator>>(decoder, assert_type);
+    PN_CPP_EXTERN decoder operator>>(assert_type);
 
     /** Rewind to the beginning */
-    PN_CPP_EXTERN friend decoder operator>>(decoder, struct rewind);
+    PN_CPP_EXTERN decoder operator>>(struct rewind);
 
   private:
     PN_CPP_EXTERN void check_type(type_id);
@@ -190,12 +162,11 @@ struct scope : public start {
 };
 
 // operator >> for integer types that are not covered by the standard overrides.
-template <class T>
-typename enable_if<is_unknown_integer<T>::value, decoder>::type
+template <class T> typename enable_integer<T, decoder>::type
 operator>>(decoder d, T& i)  {
     typename integer_type<sizeof(T), is_signed<T>::value>::type v;
     d >> v;                     // Extract as a known integer type
-    i = v;
+    i = v;                      // C++ conversion to the target type.
     return d;
 }
 
@@ -207,43 +178,13 @@ template <class T> struct ref {
 template <class T> struct sequence_ref : public ref<T> { sequence_ref(T& v) : ref<T>(v) {} };
 template <class T> struct map_ref : public ref<T> { map_ref(T& v) : ref<T>(v) {} };
 template <class T> struct pairs_ref : public ref<T> { pairs_ref(T& v) : ref<T>(v) {} };
-///@endcond
 
-/**
- * Return a wrapper for a C++ container to be decoded as a sequence. The AMQP
- * ARRAY, LIST, and MAP types can all be decoded as a sequence, a map will be
- * decoded as alternating key and value (provided they can both be converted to
- * the container's value_type)
- *
- * The following expressions must be valid for T t;
- *     T::iterator
- *     t.clear()
- *     t.resize()
- *     t.begin()
- *     t.end()
- */
+// FIXME aconway 2016-03-03: rename
+
 template <class T> sequence_ref<T> to_sequence(T& v) { return sequence_ref<T>(v); }
 
-/** Return a wrapper for a C++ map container to be decoded from an AMQP MAP.
- * The following expressions must be valid for T t;
- *     T::key_type
- *     T::mapped_type
- *     t.clear()
- *     T::key_type k; T::mapped_type v; t[k] = v;
- */
 template <class T> map_ref<T> to_map(T& v) { return map_ref<T>(v); }
 
-/** Return a wrapper for a C++ container of std::pair that can be decoded from AMQP maps,
- * preserving the encoded map order.
- *
- * The following expressions must be valid for T t;
- *     T::iterator
- *     t.clear()
- *     t.resize()
- *     t.begin()
- *     t.end()
- *     T::iterator i; i->first; i->second
- */
 template <class T> pairs_ref<T> to_pairs(T& v) { return pairs_ref<T>(v); }
 
 /** Extract any AMQP sequence (ARRAY, LIST or MAP) to a C++ container of T if
@@ -310,6 +251,7 @@ template <class K, class T, class C, class A> decoder operator>>(decoder d, std:
 
 #endif // PN_CPP_HAS_CPP11
 }
+}
 
 /// @endcond
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/encoder.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/encoder.hpp b/proton-c/bindings/cpp/include/proton/encoder.hpp
index 5e08095..79c4ec4 100644
--- a/proton-c/bindings/cpp/include/proton/encoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/encoder.hpp
@@ -48,11 +48,12 @@ struct pn_data_t;
 namespace proton {
 
 class scalar;
-class data;
-class message_id;
-class annotation_key;
 class value;
 
+namespace internal {
+
+class data;
+
 template<class T, type_id A> struct cref {
     typedef T cpp_type;
     static const type_id type;
@@ -72,12 +73,13 @@ template <type_id A, class T> cref<T, A> as(const T& value) { return cref<T, A>(
 ///
 /// Internal use only, see proton::value, proton::scalar and proton::amqp
 /// for the recommended ways to manage AMQP data.
-class encoder : public internal::object<pn_data_t> {
+class encoder : public object<pn_data_t> {
   public:
-    encoder(pn_data_t* e) : internal::object<pn_data_t>(e) {}
+    encoder(pn_data_t* e) : object<pn_data_t>(e) {}
 
     /**
-     * Encode the current values into buffer and update size to reflect the number of bytes encoded.
+     * Encode the current values into buffer and update size to reflect the
+     * number of bytes encoded.
      *
      * Clears the encoder.
      *
@@ -95,45 +97,39 @@ class encoder : public internal::object<pn_data_t> {
     /** Encode the current values into a std::string. Clears the encoder. */
     PN_CPP_EXTERN std::string encode();
 
-    PN_CPP_EXTERN class data data();
-
-    /** @name Insert simple types.
-     *@{
-     */
-  friend PN_CPP_EXTERN encoder operator<<(encoder, bool);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, uint8_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, int8_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, uint16_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, int16_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, uint32_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, int32_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, wchar_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, uint64_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, int64_t);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, timestamp);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, float);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, double);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, decimal32);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, decimal64);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, decimal128);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, uuid);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, std::string);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, symbol);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, binary);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, const message_id&);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, const annotation_key&);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, const value&);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, const scalar&);
-    ///@}
-
-    /**
-     * Start a container type.
-     */
-  friend PN_CPP_EXTERN encoder operator<<(encoder, const start&);
-
-    /** Finish a container type. See operator<<(encoder&, const start&) */
-  friend PN_CPP_EXTERN encoder operator<<(encoder e, finish);
-
+    PN_CPP_EXTERN encoder operator<<(bool);
+    PN_CPP_EXTERN encoder operator<<(uint8_t);
+    PN_CPP_EXTERN encoder operator<<(int8_t);
+    PN_CPP_EXTERN encoder operator<<(uint16_t);
+    PN_CPP_EXTERN encoder operator<<(int16_t);
+    PN_CPP_EXTERN encoder operator<<(uint32_t);
+    PN_CPP_EXTERN encoder operator<<(int32_t);
+    PN_CPP_EXTERN encoder operator<<(wchar_t);
+    PN_CPP_EXTERN encoder operator<<(uint64_t);
+    PN_CPP_EXTERN encoder operator<<(int64_t);
+    PN_CPP_EXTERN encoder operator<<(timestamp);
+    PN_CPP_EXTERN encoder operator<<(float);
+    PN_CPP_EXTERN encoder operator<<(double);
+    PN_CPP_EXTERN encoder operator<<(decimal32);
+    PN_CPP_EXTERN encoder operator<<(decimal64);
+    PN_CPP_EXTERN encoder operator<<(decimal128);
+    PN_CPP_EXTERN encoder operator<<(const uuid&);
+    PN_CPP_EXTERN encoder operator<<(const std::string&);
+    PN_CPP_EXTERN encoder operator<<(const symbol&);
+    PN_CPP_EXTERN encoder operator<<(const binary&);
+    PN_CPP_EXTERN encoder operator<<(const scalar&);
+
+    /// Start encoding a complex type.
+    PN_CPP_EXTERN encoder operator<<(const start&);
+    /// Finish a complex type
+    PN_CPP_EXTERN encoder operator<<(const finish&);
+
+    // FIXME aconway 2016-03-03: hide
+    PN_CPP_EXTERN void insert(const value& v);
+
+  private:
+
+  friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const encoder&);
 
     /**@name Insert values returned by the as<type_id> helper.
      *@{
@@ -150,11 +146,16 @@ class encoder : public internal::object<pn_data_t> {
 inline encoder operator<<(encoder e, char* s) { return e << std::string(s); }
 inline encoder operator<<(encoder e, const char* s) { return e << std::string(s); }
 
+
+// FIXME aconway 2016-03-08: explain
+template <class T> typename enable_if<is_same<T, value>::value, encoder>::type
+operator<<(encoder e, const T& x) { e.insert(x); return e; }
+    ///@}
+
 // operator << for integer types that are not covered by the standard overrides.
-template <class T>
-typename enable_if<is_unknown_integer<T>::value, encoder>::type operator<<(encoder e, T i)  {
-    typename integer_type<sizeof(T), is_signed<T>::value>::type v = i;
-    return e << v;              // Insert as a known integer type
+template <class T> typename enable_integer<T, encoder>::type
+operator<<(encoder e, T i)  {
+    return e << static_cast<typename integer_type<sizeof(T), is_signed<T>::value>::type>(i);
 }
 
 // TODO aconway 2015-06-16: described array insertion.
@@ -213,6 +214,7 @@ template <class K, class T, class C, class A> encoder operator<<(encoder e, cons
 
 #endif // PN_CPP_HAS_CPP11
 }
+}
 
 /// @endcond
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/message.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp
index 1e310a2..88bac15 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -67,8 +67,9 @@ class message {
 #endif
 
     /// Create a message with its body set from any value that can be
-    /// assigned to a proton::value.
-    template <class T> message(const T& x) : pn_msg_(0) { body() = x; }
+    /// assigned to a proton::value. proton::amqp for encoding
+    template <class T> message(const T& x, typename enable_amqp_type<T>::type * = 0) :
+        pn_msg_(0) { body() = x; }
 
     PN_CPP_EXTERN ~message();
 
@@ -109,7 +110,7 @@ class message {
 
     PN_CPP_EXTERN void address(const std::string &addr);
     PN_CPP_EXTERN std::string address() const;
-    
+
     PN_CPP_EXTERN void reply_to(const std::string &addr);
     PN_CPP_EXTERN std::string reply_to() const;
 
@@ -122,7 +123,7 @@ class message {
     /// @{
 
     /// Set the body, equivalent to body() = v
-    template<class T> void body(const T& v) { body() = v; }
+    template<class T> typename enable_amqp_type<T>::type body(const T& v) { body() = v; }
 
     /// Get the body.
     PN_CPP_EXTERN const value& body() const;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/message_id.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message_id.hpp b/proton-c/bindings/cpp/include/proton/message_id.hpp
index 8d74c51..dbc62c3 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -25,9 +25,6 @@
 
 namespace proton {
 
-class encoder;
-class decoder;
-
 /// An AMQP message ID.
 ///
 /// It can contain one of the following types:
@@ -73,15 +70,11 @@ class message_id : public restricted_scalar {
     /// Return the value as type T.
     template<class T> T get() const { T x; get(x); return x; }
 
-    friend PN_CPP_EXTERN encoder operator<<(encoder, const message_id&);
-    friend PN_CPP_EXTERN decoder operator>>(decoder, message_id&);
-
-    /// @cond INTERNAL
   private:
     message_id(const pn_atom_t& a): restricted_scalar(a) {}
 
   friend class message;
-    /// @endcond
+  friend class internal::decoder;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/scalar.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar.hpp b/proton-c/bindings/cpp/include/proton/scalar.hpp
index 56c7177..234d547 100644
--- a/proton-c/bindings/cpp/include/proton/scalar.hpp
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -32,12 +32,15 @@ class binary;
 class decimal128;
 class decimal32;
 class decimal64;
-class decoder;
-class encoder;
 class symbol;
 class timestamp;
 class uuid;
 
+namespace internal {
+class decoder;
+class encoder;
+}
+
 /// A holder for an instance of any scalar AMQP type.
 /// The conversions for scalar types are documented in proton::amqp.
 ///
@@ -137,8 +140,6 @@ class scalar : private comparable<scalar> {
     /// @cond INTERNAL
 
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const scalar&);
-  friend PN_CPP_EXTERN encoder operator<<(encoder, const scalar&);
-  friend PN_CPP_EXTERN decoder operator>>(decoder, scalar&);
 
     /// Scalars with different type() are considered unequal even if the values
     /// are equal as numbers or strings.
@@ -159,6 +160,9 @@ class scalar : private comparable<scalar> {
 
   friend class message;
   friend class restricted_scalar;
+  friend class internal::encoder;
+  friend class internal::decoder;
+
 };
 
 /// @cond INTERNAL

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/type_traits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/type_traits.hpp b/proton-c/bindings/cpp/include/proton/type_traits.hpp
index af62a1d..7c1f6b0 100644
--- a/proton-c/bindings/cpp/include/proton/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/type_traits.hpp
@@ -38,11 +38,17 @@ class binary;
 class decimal128;
 class decimal32;
 class decimal64;
+class scalar;
 class symbol;
 class timestamp;
 class uuid;
 class value;
 
+namespace internal {
+
+class decoder;
+class encoder;
+
 template <bool, class T=void> struct enable_if {};
 template <class T> struct enable_if<true, T> { typedef T type; };
 
@@ -50,6 +56,10 @@ struct true_type { static const bool value = true; };
 struct false_type { static const bool value = false; };
 
 template <class T> struct is_integral : public false_type {};
+template <class T> struct is_signed : public false_type {};
+
+template <> struct is_integral<char> : public true_type {};
+template <> struct is_signed<char> : public false_type {};
 
 template <> struct is_integral<unsigned char> : public true_type {};
 template <> struct is_integral<unsigned short> : public true_type {};
@@ -61,9 +71,6 @@ template <> struct is_integral<signed short> : public true_type {};
 template <> struct is_integral<signed int> : public true_type {};
 template <> struct is_integral<signed long> : public true_type {};
 
-template <class T> struct is_signed : public false_type {};
-
-template <> struct is_signed<unsigned char> : public false_type {};
 template <> struct is_signed<unsigned short> : public false_type {};
 template <> struct is_signed<unsigned int> : public false_type {};
 template <> struct is_signed<unsigned long> : public false_type {};
@@ -83,37 +90,38 @@ template <> struct is_signed<signed long long> : public true_type {};
 template <class T, class U> struct is_same { static const bool value=false; };
 template <class T> struct is_same<T,T> { static const bool value=true; };
 
-
 template< class T > struct remove_const          { typedef T type; };
 template< class T > struct remove_const<const T> { typedef T type; };
 
-// Metafunction returning AMQP type for scalar C++ types
-template <class T, class Enable=void> struct type_id_of;
-template<> struct type_id_of<bool> { static const type_id value=BOOLEAN; };
-template<> struct type_id_of<uint8_t> { static const type_id value=UBYTE; };
-template<> struct type_id_of<int8_t> { static const type_id value=BYTE; };
-template<> struct type_id_of<uint16_t> { static const type_id value=USHORT; };
-template<> struct type_id_of<int16_t> { static const type_id value=SHORT; };
-template<> struct type_id_of<uint32_t> { static const type_id value=UINT; };
-template<> struct type_id_of<int32_t> { static const type_id value=INT; };
-template<> struct type_id_of<wchar_t> { static const type_id value=CHAR; };
-template<> struct type_id_of<uint64_t> { static const type_id value=ULONG; };
-template<> struct type_id_of<int64_t> { static const type_id value=LONG; };
-template<> struct type_id_of<timestamp> { static const type_id value=TIMESTAMP; };
-template<> struct type_id_of<float> { static const type_id value=FLOAT; };
-template<> struct type_id_of<double> { static const type_id value=DOUBLE; };
-template<> struct type_id_of<decimal32> { static const type_id value=DECIMAL32; };
-template<> struct type_id_of<decimal64> { static const type_id value=DECIMAL64; };
-template<> struct type_id_of<decimal128> { static const type_id value=DECIMAL128; };
-template<> struct type_id_of<uuid> { static const type_id value=UUID; };
-template<> struct type_id_of<binary> { static const type_id value=BINARY; };
-template<> struct type_id_of<std::string> { static const type_id value=STRING; };
-template<> struct type_id_of<symbol> { static const type_id value=SYMBOL; };
+template <type_id ID> struct type_id_constant { static const type_id value = ID; };
 
+// Metafunction returning AMQP type for scalar C++ types.
+template <class T, class Enable=void> struct type_id_of;
+template<> struct type_id_of<bool> : public type_id_constant<BOOLEAN> {};
+template<> struct type_id_of<uint8_t> : public type_id_constant<UBYTE> {};
+template<> struct type_id_of<int8_t> : public type_id_constant<BYTE> {};
+template<> struct type_id_of<uint16_t> : public type_id_constant<USHORT> {};
+template<> struct type_id_of<int16_t> : public type_id_constant<SHORT> {};
+template<> struct type_id_of<uint32_t> : public type_id_constant<UINT> {};
+template<> struct type_id_of<int32_t> : public type_id_constant<INT> {};
+template<> struct type_id_of<uint64_t> : public type_id_constant<ULONG> {};
+template<> struct type_id_of<int64_t> : public type_id_constant<LONG> {};
+template<> struct type_id_of<wchar_t> : public type_id_constant<CHAR> {};
+template<> struct type_id_of<timestamp> : public type_id_constant<TIMESTAMP> {};
+template<> struct type_id_of<float> : public type_id_constant<FLOAT> {};
+template<> struct type_id_of<double> : public type_id_constant<DOUBLE> {};
+template<> struct type_id_of<decimal32> : public type_id_constant<DECIMAL32> {};
+template<> struct type_id_of<decimal64> : public type_id_constant<DECIMAL64> {};
+template<> struct type_id_of<decimal128> : public type_id_constant<DECIMAL128> {};
+template<> struct type_id_of<uuid> : public type_id_constant<UUID> {};
+template<> struct type_id_of<binary> : public type_id_constant<BINARY> {};
+template<> struct type_id_of<std::string> : public type_id_constant<STRING> {};
+template<> struct type_id_of<symbol> : public type_id_constant<SYMBOL> {};
+template<> struct type_id_of<const char*> : public type_id_constant<STRING> {};
+
+// Metafunction to test if a class has a type_id.
 template <class T, class Enable=void> struct has_type_id : public false_type {};
-template <class T> struct has_type_id<T, typename enable_if<!!type_id_of<T>::value>::type>  {
-    static const bool value = true;
-};
+template <class T> struct has_type_id<T, typename enable_if<!!type_id_of<T>::value>::type>  : public true_type {};
 
 // Map arbitrary integral types to known AMQP integral types.
 template<size_t SIZE, bool IS_SIGNED> struct integer_type;
@@ -126,12 +134,85 @@ template<> struct integer_type<2, false> { typedef uint16_t type; };
 template<> struct integer_type<4, false> { typedef uint32_t type; };
 template<> struct integer_type<8, false> { typedef uint64_t type; };
 
-// True if T is an integer type that does not have a type_id mapping.
+// True if T is an integer type that does not have an explicit type_id.
 template <class T> struct is_unknown_integer {
     static const bool value = !has_type_id<T>::value && is_integral<T>::value;
 };
 
-}
+// Types for SFINAE tests.
+typedef char yes;
+typedef double no;
+struct wildcard { wildcard(...); };
+
+namespace is_decodable_impl {   // Protected the world from wildcard operator<<
+
+no operator>>(wildcard, wildcard); // Fallback
+
+template<typename T> struct is_decodable {
+    static char test(decoder);
+    static double test(...);         // Failed test, no match.
+    static decoder& d;
+    static T &t;
+    static bool const value = (sizeof(test(d >> t)) == sizeof(yes));
+};
+} // namespace is_decodable_impl
+
+
+namespace is_encodable_impl {   // Protected the world from wildcard operator<<
+
+no operator<<(wildcard, wildcard); // Fallback
+
+template<typename T> struct is_encodable {
+    static yes test(encoder);
+    static no test(...);         // Failed test, no match.
+    static encoder &e;
+    static const T& t;
+    static bool const value = sizeof(test(e << t)) == sizeof(yes);
+};
+
+} // namespace is_encodable_impl
+
+/// is_encodable<T>::value is true if there is an operator<< for encoder and T.
+using is_encodable_impl::is_encodable;
+
+/// Metafunction: is_decodable<T>::value is true if `T t; decoder >> t` is valid.
+using is_decodable_impl::is_decodable;
+
+
+// Start encoding a complex type.
+struct start {
+    PN_CPP_EXTERN start(type_id type=NULL_TYPE, type_id element=NULL_TYPE, bool described=false, size_t size=0);
+    type_id type;            ///< The container type: ARRAY, LIST, MAP or DESCRIBED.
+    type_id element;         ///< the element type for array only.
+    bool is_described;       ///< true if first value is a descriptor.
+    size_t size;             ///< the element count excluding the descriptor (if any)
+
+    /// Return a start for an array.
+    PN_CPP_EXTERN static start array(type_id element, bool described=false);
+
+    /// Return a start for a list.
+    PN_CPP_EXTERN static start list();
+
+    /// Return a start for a map.
+    PN_CPP_EXTERN static start map();
+
+    /// Return a start for a described type.
+    PN_CPP_EXTERN static start described();
+};
+
+/// Finish inserting or extracting a container value.
+struct finish {};
+
+} // namespace internal
+
+/// An enabler template for C++ values that can be converted to AMQP.
+template<class T, class U=void> struct enable_amqp_type :
+        public internal::enable_if<internal::is_encodable<T>::value, U> {};
+
+/// An enabler for integer types.
+template <class T, class U=void> struct enable_integer :
+        public internal::enable_if<internal::is_unknown_integer<T>::value, U> {};
+} // namespace proton
 
 /// @endcond
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/proton-c/bindings/cpp/include/proton/types.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/types.hpp b/proton-c/bindings/cpp/include/proton/types.hpp
index 54b8391..f0667fc 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -125,37 +125,6 @@ PN_CPP_EXTERN bool type_id_is_container(type_id);
 
 /// Print the name of a type.
 PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, type_id);
-
-/// @cond INTERNAL
-/// XXX change namespace
-    
-/// Information needed to start extracting or inserting a container type.
-///
-/// See encoder::operator<<(encoder&, const start&) and
-/// decoder::operator>>(decoder&, start&) for examples of use.
-struct start {
-    PN_CPP_EXTERN start(type_id type=NULL_TYPE, type_id element=NULL_TYPE, bool described=false, size_t size=0);
-    type_id type;            ///< The container type: ARRAY, LIST, MAP or DESCRIBED.
-    type_id element;         ///< the element type for array only.
-    bool is_described;       ///< true if first value is a descriptor.
-    size_t size;             ///< the element count excluding the descriptor (if any)
-
-    /// Return a start for an array.
-    PN_CPP_EXTERN static start array(type_id element, bool described=false);
-
-    /// Return a start for a list.
-    PN_CPP_EXTERN static start list();
-
-    /// Return a start for a map.
-    PN_CPP_EXTERN static start map();
-
-    /// Return a start for a described type.
-    PN_CPP_EXTERN static start described();
-};
-
-/// Finish inserting or extracting a container value.
-struct finish {};
-
 /// @endcond
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 7b7ff26..cf04c43 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -47,17 +47,11 @@ class value : private comparable<value> {
     PN_CPP_EXTERN value(value&&);
 #endif
 
-    /// Copy a value.
-    PN_CPP_EXTERN value& operator=(const value&);
-
-    /// Explicit conversion from from C++ type T.
-    template <class T> explicit value(const T& x) : data_(proton::data::create()) { encode() << x; }
-
-    /// Allow implicit conversion from a proton::scalar.
-    value(const scalar& x) { encode() << x; }
+    /// 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; }
 
-    /// Create a value from C++ type T.
-    template <class T> value& operator=(const T& x) { encode() << x; return *this; }
+    PN_CPP_EXTERN value& operator=(const value&);
 
     /// Remove any contained data.
     PN_CPP_EXTERN void clear();
@@ -65,7 +59,7 @@ class value : private comparable<value> {
     /// True if the value contains no data.
     PN_CPP_EXTERN bool empty() const;
 
-    /// Get the type of the current value.
+    /// Get the type ID for the current value.
     PN_CPP_EXTERN type_id type() const;
 
     /// @name Get methods
@@ -78,13 +72,13 @@ class value : private comparable<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() >> to_map(t); }
+    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() >> to_pairs(t); }
+    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() >> to_sequence(t); }
+    template<class T> void get_sequence(T& t) const { decode() >> internal::to_sequence(t); }
 
     /// @}
 
@@ -103,25 +97,25 @@ class value : private comparable<value> {
     PN_CPP_EXTERN std::string as_string() const; ///< Allowed if `type_id_is_string_like(type())`
     /// @}
 
-    /// @cond INTERNAL
-    /// XXX undiscussed
-    PN_CPP_EXTERN encoder encode();              ///< Clear and return an encoder for this value.
-    PN_CPP_EXTERN decoder decode() const;        ///< Rewind and return an encoder for this value.
-    PN_CPP_EXTERN class data& data() const;      ///< Return a data reference, no clear or rewind.
-    /// @endcond
+  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
 
   private:
-    mutable class data data_;
-
-    /// @cond INTERNAL
-    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 class encoder operator<<(class encoder e, const value& dv);
-    friend PN_CPP_EXTERN class decoder operator>>(class decoder d, value& dv);
-    friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, const value& dv);
-    friend class message;
-    /// @endcond
+
+    mutable class internal::data data_;
+    internal::data& data() const;   // On-demand access.
+
+  friend class message;
+  friend class internal::encoder;
+  friend class internal::decoder;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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
new file mode 100644
index 0000000..e3b45d7
--- /dev/null
+++ b/proton-c/bindings/cpp/src/codec_test.cpp
@@ -0,0 +1,123 @@
+#ifndef CODEC_TEST_HPP
+#define CODEC_TEST_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
+nn * "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 "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>
+
+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);
+    value v;
+    v.encode() << x;
+    T y;
+    v.decode() >> y;
+    ASSERT_EQUAL(x, y);
+}
+
+template <class T> T make_fill(const char c) {
+    T x; std::fill(x.begin(), x.end(), c);
+    return x;
+}
+
+template <class T> void  uncodable_type_test() {
+    ASSERT(!internal::is_encodable<T>::value);
+    ASSERT(!internal::is_decodable<T>::value);
+}
+
+int main(int, char**) {
+    int failed = 0;
+
+    // Basic AMQP types
+    RUN_TEST(failed, simple_type_test(false));
+    RUN_TEST(failed, simple_type_test(uint8_t(42)));
+    RUN_TEST(failed, simple_type_test(int8_t(-42)));
+    RUN_TEST(failed, simple_type_test(uint16_t(4242)));
+    RUN_TEST(failed, simple_type_test(int16_t(-4242)));
+    RUN_TEST(failed, simple_type_test(uint32_t(4242)));
+    RUN_TEST(failed, simple_type_test(int32_t(-4242)));
+    RUN_TEST(failed, simple_type_test(uint64_t(4242)));
+    RUN_TEST(failed, simple_type_test(int64_t(-4242)));
+    RUN_TEST(failed, simple_type_test(wchar_t('X')));
+    RUN_TEST(failed, simple_type_test(float(1.234)));
+    RUN_TEST(failed, simple_type_test(double(11.2233)));
+    RUN_TEST(failed, simple_type_test(timestamp(1234)));
+    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(std::string("xxx")));
+    RUN_TEST(failed, simple_type_test(symbol("aaa")));
+    RUN_TEST(failed, simple_type_test(binary("aaa")));
+
+    // Native int type that may map differently per platform to uint types.
+    RUN_TEST(failed, simple_type_test(char(42)));
+    RUN_TEST(failed, simple_type_test(short(42)));
+    RUN_TEST(failed, simple_type_test(int(42)));
+    RUN_TEST(failed, simple_type_test(long(42)));
+
+    RUN_TEST(failed, simple_type_test(static_cast<signed char>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<signed short>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<signed int>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<signed long>(42)));
+
+    RUN_TEST(failed, simple_type_test(static_cast<unsigned char>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<unsigned short>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<unsigned int>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<unsigned long>(42)));
+
+#if PN_HAS_LONG_LONG
+    RUN_TEST(failed, simple_type_test(static_cast<long>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<signed long>(42)));
+    RUN_TEST(failed, simple_type_test(static_cast<unsigned long>(42)));
+#endif
+
+    // value and scalar types, more tests in value_test and scalar_test.
+    RUN_TEST(failed, simple_type_test(value("foo")));
+    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)));
+
+    // 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> >()));
+
+    return failed;
+}
+
+
+#endif // CODEC_TEST_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 3cd2bc8..a714cf6 100644
--- a/proton-c/bindings/cpp/src/data.cpp
+++ b/proton-c/bindings/cpp/src/data.cpp
@@ -30,6 +30,7 @@
 #include <ostream>
 
 namespace proton {
+namespace internal {
 
 data& data::copy(const data& x) { ::pn_data_copy(pn_object(), x.pn_object()); return *this; }
 
@@ -69,8 +70,8 @@ std::ostream& operator<<(std::ostream& o, const data& d) {
 
 data data::create() { return internal::take_ownership(pn_data(0)); }
 
-encoder data::encoder() { return proton::encoder(pn_object()); }
-decoder data::decoder() { return proton::decoder(pn_object()); }
+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(); }
 
@@ -167,5 +168,5 @@ bool data::equal(const data& x) const {
 bool data::less(const data& x) const {
     return compare(const_cast<data&>(*this), const_cast<data&>(x)) < 0;
 }
-
+}
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 17f85da..ceaca77 100644
--- a/proton-c/bindings/cpp/src/decoder.cpp
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -32,6 +32,7 @@
 #include <proton/codec.h>
 
 namespace proton {
+namespace internal {
 
 /**@file
  *
@@ -85,8 +86,6 @@ void decoder::backup() { ::pn_data_prev(pn_object()); }
 
 void decoder::skip() { ::pn_data_next(pn_object()); }
 
-data decoder::data() { return proton::data(pn_object()); }
-
 namespace {
 
 void bad_type(type_id want, type_id got) {
@@ -126,8 +125,8 @@ type_id decoder::type() const {
     return pre_get(pn_object());
 }
 
-decoder operator>>(decoder d0, start& s) {
-    pn_data_t* d = d0.pn_object();
+decoder decoder::operator>>(start& s) {
+    pn_data_t* d = pn_object();
     save_state ss(d);
     s.type = pre_get(d);
     switch (s.type) {
@@ -150,91 +149,93 @@ decoder operator>>(decoder d0, start& s) {
     }
     pn_data_enter(d);
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d, finish) { pn_data_exit(d.pn_object()); return d; }
+// FIXME aconway 2016-03-08: remove
+decoder decoder::operator>>(struct finish) { pn_data_exit(pn_object()); return *this; }
 
-decoder operator>>(decoder d, skip) { pn_data_next(d.pn_object()); return d; }
+decoder decoder::operator>>(struct skip) { pn_data_next(pn_object()); return *this; }
 
-decoder operator>>(decoder d, assert_type a) { bad_type(a.type, d.type()); return d; }
+decoder decoder::operator>>(struct assert_type a) { bad_type(a.type, type()); return *this; }
 
-decoder operator>>(decoder d, rewind) { d.rewind(); return d; }
+decoder decoder::operator>>(struct rewind) { rewind(); return *this; }
 
-decoder operator>>(decoder d, value& v) {
-    data ddata = d.data();
-    data vdata = v.encode().data();
-    if (d.data() == v.data_) throw conversion_error("extract into self");
+decoder decoder::operator>>(value& v) {
+    data mine(pn_object());
+    if (mine == v.data_)
+        throw conversion_error("extract into self");
+    v.clear();
     {
-        narrow n(ddata);
-        check(vdata.appendn(ddata, 1));
+        narrow n(pn_object());
+        check(v.data().appendn(mine, 1));
     }
-    if (!ddata.next()) throw conversion_error("no more data");
-    return d;
+    if (!mine.next()) throw conversion_error("no more data");
+    return *this;
 }
 
-decoder operator>>(decoder d, message_id& x) {
-    switch (d.type()) {
+decoder decoder::operator>>(message_id& x) {
+    switch (type()) {
       case ULONG:
       case UUID:
       case BINARY:
       case STRING:
-        return d >> x.scalar_;
+        return *this >> x.scalar_;
       default:
-        throw conversion_error("expected one of ulong, uuid, binary or string but found " +
-                           type_name(d.type()));
+        throw conversion_error(
+            msg() << "expected one of ulong, uuid, binary or string but found " << type());
     };
 }
 
-decoder operator>>(decoder d, annotation_key& x) {
-    switch (d.type()) {
+decoder decoder::operator>>(annotation_key& x) {
+    switch (type()) {
       case ULONG:
       case SYMBOL:
-        return d >> x.scalar_;
+        return *this >> x.scalar_;
       default:
-        throw conversion_error("expected one of ulong or symbol but found " + type_name(d.type()));
+        throw conversion_error("expected one of ulong or symbol but found " + type_name(type()));
     };
 }
 
-decoder operator>>(decoder d, scalar& x) {
-    save_state ss(d.pn_object());
-    type_id got = pre_get(d.pn_object());
+decoder decoder::operator>>(scalar& x) {
+    save_state ss(pn_object());
+    type_id got = pre_get(pn_object());
     if (!type_id_is_scalar(got))
         throw conversion_error("expected scalar, found "+type_name(got));
-    x.set(pn_data_get_atom(d.pn_object()));
+    x.set(pn_data_get_atom(pn_object()));
     ss.cancel();                // No error, no rewind
-    return d;
+    return *this;
 }
 
-decoder operator>>(decoder d, amqp::boolean_type &x) {
-    extract(d.pn_object(), x, pn_data_get_bool);
-    return d;
+decoder decoder::operator>>(amqp::boolean_type &x) {
+    extract(pn_object(), x, pn_data_get_bool);
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::ubyte_type &x) {
-    pn_data_t* d = d0.pn_object();
+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))));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::byte_type &x) {
-    pn_data_t* d = d0.pn_object();
+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))));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::ushort_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -242,11 +243,11 @@ decoder operator>>(decoder d0, amqp::ushort_type &x) {
       default: bad_type(USHORT, type_id(type_id(pn_data_type(d))));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::short_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -254,11 +255,11 @@ decoder operator>>(decoder d0, amqp::short_type &x) {
       default: bad_type(SHORT, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::uint_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -267,11 +268,11 @@ decoder operator>>(decoder d0, amqp::uint_type &x) {
       default: bad_type(UINT, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::int_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -280,11 +281,11 @@ decoder operator>>(decoder d0, amqp::int_type &x) {
       default: bad_type(INT, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::ulong_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -294,11 +295,11 @@ decoder operator>>(decoder d0, amqp::ulong_type &x) {
       default: bad_type(ULONG, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::long_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -308,21 +309,21 @@ decoder operator>>(decoder d0, amqp::long_type &x) {
       default: bad_type(LONG, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d, amqp::char_type &x) {
-    extract(d.pn_object(), x, pn_data_get_char);
-    return d;
+decoder decoder::operator>>(amqp::char_type &x) {
+    extract(pn_object(), x, pn_data_get_char);
+    return *this;
 }
 
-decoder operator>>(decoder d, timestamp &x) {
-    extract(d.pn_object(), x, pn_data_get_timestamp);
-    return d;
+decoder decoder::operator>>(timestamp &x) {
+    extract(pn_object(), x, pn_data_get_timestamp);
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::float_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -330,11 +331,11 @@ decoder operator>>(decoder d0, amqp::float_type &x) {
       default: bad_type(FLOAT, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d0, amqp::double_type &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -342,31 +343,31 @@ decoder operator>>(decoder d0, amqp::double_type &x) {
       default: bad_type(DOUBLE, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
-decoder operator>>(decoder d, decimal32 &x) {
-    extract(d.pn_object(), x, pn_data_get_decimal32);
-    return d;
+decoder decoder::operator>>(decimal32 &x) {
+    extract(pn_object(), x, pn_data_get_decimal32);
+    return *this;
 }
 
-decoder operator>>(decoder d, decimal64 &x) {
-    extract(d.pn_object(), x, pn_data_get_decimal64);
-    return d;
+decoder decoder::operator>>(decimal64 &x) {
+    extract(pn_object(), x, pn_data_get_decimal64);
+    return *this;
 }
 
-decoder operator>>(decoder d, decimal128 &x)  {
-    extract(d.pn_object(), x, pn_data_get_decimal128);
-    return d;
+decoder decoder::operator>>(decimal128 &x)  {
+    extract(pn_object(), x, pn_data_get_decimal128);
+    return *this;
 }
 
-decoder operator>>(decoder d, uuid &x)  {
-    extract(d.pn_object(), x, pn_data_get_uuid);
-    return d;
+decoder decoder::operator>>(uuid &x)  {
+    extract(pn_object(), x, pn_data_get_uuid);
+    return *this;
 }
 
-decoder operator>>(decoder d0, std::string &x) {
-    pn_data_t* d = d0.pn_object();
+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;
@@ -375,7 +376,7 @@ decoder operator>>(decoder d0, std::string &x) {
       default: bad_type(STRING, type_id(pn_data_type(d)));
     }
     ss.cancel();
-    return d0;
+    return *this;
 }
 
 void assert_map_scope(const scope& s) {
@@ -386,4 +387,5 @@ void assert_map_scope(const scope& s) {
 }
 
 
-}
+} // internal
+} // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 a7f1498..0da0994 100644
--- a/proton-c/bindings/cpp/src/encoder.cpp
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -36,6 +36,7 @@
 #include <algorithm>
 
 namespace proton {
+namespace internal {
 
 namespace {
 struct save_state {
@@ -84,24 +85,22 @@ std::string encoder::encode() {
     return s;
 }
 
-data encoder::data() { return proton::data(pn_object()); }
-
-encoder operator<<(encoder e, const start& s) {
+encoder encoder::operator<<(const start& s) {
     switch (s.type) {
-      case ARRAY: pn_data_put_array(e.pn_object(), s.is_described, pn_type_t(s.element)); break;
-      case MAP: pn_data_put_map(e.pn_object()); break;
-      case LIST: pn_data_put_list(e.pn_object()); break;
-      case DESCRIBED: pn_data_put_described(e.pn_object()); break;
+      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;
+      case LIST: pn_data_put_list(pn_object()); break;
+      case DESCRIBED: pn_data_put_described(pn_object()); break;
       default:
         throw conversion_error(MSG("" << s.type << " is not a container type"));
     }
-    pn_data_enter(e.pn_object());
-    return e;
+    pn_data_enter(pn_object());
+    return *this;
 }
 
-encoder operator<<(encoder e, finish) {
-    pn_data_exit(e.pn_object());
-    return e;
+encoder encoder::operator<<(const finish&) {
+    pn_data_exit(pn_object());
+    return *this;
 }
 
 namespace {
@@ -113,7 +112,7 @@ template <> pn_decimal64_t convert(const decimal64 &x) { pn_decimal64_t y; byte_
 template <> pn_decimal128_t convert(const decimal128 &x) { pn_decimal128_t y; byte_copy(y, x); return  y; }
 
 template <class T, class U>
-encoder insert(encoder e, pn_data_t* data, const T& x, int (*put)(pn_data_t*, 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.
@@ -125,41 +124,41 @@ int pn_data_put_amqp_binary(pn_data_t *d, const amqp::binary_type& x) { return p
 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 operator<<(encoder e, amqp::boolean_type x) { return insert(e, e.pn_object(), x, pn_data_put_bool); }
-encoder operator<<(encoder e, amqp::ubyte_type x) { return insert(e, e.pn_object(), x, pn_data_put_ubyte); }
-encoder operator<<(encoder e, amqp::byte_type x) { return insert(e, e.pn_object(), x, pn_data_put_byte); }
-encoder operator<<(encoder e, amqp::ushort_type x) { return insert(e, e.pn_object(), x, pn_data_put_ushort); }
-encoder operator<<(encoder e, amqp::short_type x) { return insert(e, e.pn_object(), x, pn_data_put_short); }
-encoder operator<<(encoder e, amqp::uint_type x) { return insert(e, e.pn_object(), x, pn_data_put_uint); }
-encoder operator<<(encoder e, amqp::int_type x) { return insert(e, e.pn_object(), x, pn_data_put_int); }
-encoder operator<<(encoder e, amqp::char_type x) { return insert(e, e.pn_object(), x, pn_data_put_char); }
-encoder operator<<(encoder e, amqp::ulong_type x) { return insert(e, e.pn_object(), x, pn_data_put_ulong); }
-encoder operator<<(encoder e, amqp::long_type x) { return insert(e, e.pn_object(), x, pn_data_put_long); }
-encoder operator<<(encoder e, timestamp x) { return insert(e, e.pn_object(), x.ms(), pn_data_put_timestamp); }
-encoder operator<<(encoder e, amqp::float_type x) { return insert(e, e.pn_object(), x, pn_data_put_float); }
-encoder operator<<(encoder e, amqp::double_type x) { return insert(e, e.pn_object(), x, pn_data_put_double); }
-
-encoder operator<<(encoder e, decimal32 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal32); }
-encoder operator<<(encoder e, decimal64 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal64); }
-encoder operator<<(encoder e, decimal128 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal128); }
-encoder operator<<(encoder e, uuid x) { return insert(e, e.pn_object(), x, pn_data_put_uuid); }
-encoder operator<<(encoder e, amqp::string_type x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_string); }
-encoder operator<<(encoder e, amqp::symbol_type x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_symbol); }
-encoder operator<<(encoder e, amqp::binary_type x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_binary); }
-
-encoder operator<<(encoder e, const value& v) {
-    data edata = e.data();
-    if (edata == v.data_) throw conversion_error("cannot insert into self");
-    data vdata = v.decode().data();
-    check(edata.append(vdata), e.pn_object());
-    return e;
+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); }
+
+void encoder::insert(const value& v) {
+    data mine(pn_object());
+    if (mine == v.data_)
+        throw conversion_error("cannot insert into self");
+    if (v.empty())
+        throw conversion_error("cannot insert empty value");
+    v.decode();                 // Rewind
+    check(mine.append(v.data()), pn_object());
 }
 
-encoder operator<<(encoder e, const scalar& x) {
-    return insert(e, e.pn_object(), x.atom_, pn_data_put_atom);
+std::ostream& operator<<(std::ostream& o, const encoder& e) {
+    return o << data(e.pn_object());
+}
 }
-
-encoder operator<<(encoder e, const message_id& x) { return e << x.scalar_; }
-encoder operator<<(encoder e, const annotation_key& x) { return e << x.scalar_; }
-
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 c25dedc..083e0bc 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -30,6 +30,7 @@
 
 using namespace std;
 using namespace proton;
+using namespace proton::internal;
 using namespace test;
 
 std::string tests_dir;
@@ -90,7 +91,7 @@ void test_encoder_primitives() {
     e << ::uint32_t(12345) << ::int32_t(-12345);
     e << ::uint64_t(12345) << ::int64_t(-12345);
     e << float(0.125) << double(0.125);
-    ASSERT_EQUAL("true, false, 42, 42, -42, 12345, -12345, 12345, -12345, 0.125, 0.125", str(e.data()));
+    ASSERT_EQUAL("true, false, 42, 42, -42, 12345, -12345, 12345, -12345, 0.125, 0.125", str(str(e)));
     std::string data = e.encode();
     ASSERT_EQUAL(read("primitives"), data);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 6dd32d7..dd0febb 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()) {
-                        encoder enc = t.node_properties().encode();
-                        enc << start::map();
+                        internal::encoder enc = t.node_properties().encode();
+                        enc << internal::start::map();
                         if (dm.size())
                             enc << symbol("supported-dist-modes") << std::string(dm);
                         if (lp.size())
-                            enc << symbol("lifetime-policy") << start::described()
-                                << symbol(lp) << start::list() << finish();
+                            enc << symbol("lifetime-policy") << internal::start::described()
+                                << symbol(lp) << internal::start::list() << internal::finish();
                     }
                 }
             }
@@ -126,9 +126,9 @@ class link_options::impl {
                     l.local_source().expiry_policy(terminus::EXPIRE_NEVER);
                 }
                 if (selector.set && selector.value.size()) {
-                    encoder enc = l.local_source().filter().encode();
-                    enc << start::map() << symbol("selector") << start::described()
-                        << symbol("apache.org:selector-filter:string") << binary(selector.value) << finish();
+                    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();
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 fcce408..2b793f8 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -47,7 +47,7 @@ message::message(message &&m) : pn_msg_(0) { swap(*this, m); }
 #endif
 
 message::~message() {
-    body_.data_ = data(0);      // Must release body before pn_message_free
+    body_.data_ = internal::data(0);      // Must release body before pn_message_free
     pn_message_free(pn_msg_);
 }
 
@@ -126,7 +126,7 @@ std::string message::reply_to() const {
 }
 
 void message::correlation_id(const message_id& id) {
-    data(pn_message_correlation_id(pn_msg())).copy(id.scalar_);
+    internal::data(pn_message_correlation_id(pn_msg())).copy(id.scalar_);
 }
 
 message_id message::correlation_id() const {
@@ -197,9 +197,9 @@ 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) {
-    data d(get(msg));
+    internal::data d(get(msg));
     if (map.empty() && !d.empty()) {
-        d.decoder() >> rewind() >> map;
+        d.decoder() >> internal::rewind() >> map;
         d.clear();              // The map member is now the authority.
     }
     return map;
@@ -207,7 +207,7 @@ 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) {
-    data d(get(msg));
+    internal::data d(get(msg));
     if (d.empty() && !map.empty()) {
         d.encoder() << map;
         map.clear();        // The encoded pn_data_t  is now the authority.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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
index 4f12696..f64d0b6 100644
--- a/proton-c/bindings/cpp/src/types.cpp
+++ b/proton-c/bindings/cpp/src/types.cpp
@@ -17,7 +17,8 @@
  * under the License.
  */
 
-#include "proton/types.hpp"
+#include <proton/types.hpp>
+#include <proton/type_traits.hpp>
 #include <proton/codec.h>
 #include <ostream>
 #include <iomanip>
@@ -70,11 +71,11 @@ bool type_id_is_scalar(type_id t) { return type_id_is_integral(t) || type_id_is_
 
 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/bdaf901a/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 f17f68c..1c0de8a 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 enable_if<sizeof(T) == sizeof(U)>::type byte_copy(T &to, const U &from) {
+typename internal::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));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bdaf901a/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 32cfa9b..1de0516 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -28,6 +28,8 @@ namespace proton {
 
 value::value() {}
 value::value(const value& x) { *this = x; }
+value::value(pn_data_t* p) { if (p) data().copy(internal::data(p)); }
+
 #if PN_CPP_HAS_CPP11
 value::value(value&& x) { swap(*this, x); }
 #endif
@@ -37,7 +39,7 @@ value& value::operator=(const value& x) {
         if (x.empty())
             clear();
         else
-            encode() << x;
+            data().copy(x.data());
     }
     return *this;
 }
@@ -49,11 +51,13 @@ void value::clear() { if (!!data_) data_.clear(); }
 bool value::empty() const { return !data_ || data_.empty(); }
 
 // On demand
-inline data& value::data() const { if (!data_) data_ = proton::data::create(); return data_; }
+internal::data& value::data() const {
+    if (!data_) data_ = internal::data::create(); return data_;
+}
 
-class encoder value::encode() { clear(); return data().encoder(); }
+internal::encoder value::encode() { clear(); return data().encoder(); }
 
-class decoder value::decode() const { return data().decoder() >> rewind(); }
+internal::decoder value::decode() const { return data().decoder() >> internal::rewind(); }
 
 type_id value::type() const { return decode().type(); }
 


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