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 2015/06/18 23:58:25 UTC

[47/50] [abbrv] qpid-proton git commit: PROTON-865: cpp encode/decode support for complex types.

PROTON-865: cpp encode/decode support for complex types.

Support for streaming complex AMQP types element by element and for
inserting/extracting C++ containers as AMQP containers.

See examples/cpp/encode_decode.cpp for examples of use.

Described types are not yet fully supported.


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

Branch: refs/heads/cjansen-cpp-client
Commit: 693752d37c918aed97f4b5bde25716f00ff27a8d
Parents: c99be7a
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Jun 12 13:47:48 2015 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Jun 18 17:28:44 2015 -0400

----------------------------------------------------------------------
 examples/cpp/CMakeLists.txt                     |  12 +-
 examples/cpp/encode_decode.cpp                  | 257 ++++++++++++++++
 examples/cpp/example_test.py                    |  41 ++-
 examples/cpp/simple_recv.cpp                    |   2 +-
 proton-c/CMakeLists.txt                         |   5 +-
 proton-c/bindings/cpp/CMakeLists.txt            |   8 +-
 proton-c/bindings/cpp/include/proton/cpp/Data.h |   4 +
 .../bindings/cpp/include/proton/cpp/Decoder.h   | 172 +++++++----
 .../bindings/cpp/include/proton/cpp/Duration.h  |   2 +-
 .../bindings/cpp/include/proton/cpp/Encoder.h   |  84 ++++-
 .../bindings/cpp/include/proton/cpp/Exception.h |  49 ---
 .../cpp/include/proton/cpp/MessagingHandler.h   |   2 +-
 .../bindings/cpp/include/proton/cpp/Value.h     |  63 ++--
 .../bindings/cpp/include/proton/cpp/Values.h    |  56 ++++
 .../bindings/cpp/include/proton/cpp/types.h     | 246 ++++++++++-----
 proton-c/bindings/cpp/src/ConnectionImpl.h      |   2 +-
 proton-c/bindings/cpp/src/ContainerImpl.cpp     |   8 -
 proton-c/bindings/cpp/src/Data.cpp              |   4 +-
 proton-c/bindings/cpp/src/Decoder.cpp           |  83 ++++-
 proton-c/bindings/cpp/src/Encoder.cpp           |  74 ++++-
 proton-c/bindings/cpp/src/Handler.cpp           |   6 +-
 proton-c/bindings/cpp/src/MessagingAdapter.cpp  |  10 +-
 proton-c/bindings/cpp/src/MessagingHandler.cpp  |   2 +-
 proton-c/bindings/cpp/src/Msg.h                 |  22 +-
 proton-c/bindings/cpp/src/ProtonEvent.cpp       |   3 +-
 proton-c/bindings/cpp/src/ProtonHandler.cpp     |   2 +-
 proton-c/bindings/cpp/src/Transport.cpp         |   2 +-
 proton-c/bindings/cpp/src/Value.cpp             | 111 +++++--
 proton-c/bindings/cpp/src/Values.cpp            |  39 +++
 proton-c/bindings/cpp/src/interop_test.cpp      |   8 +-
 proton-c/bindings/cpp/src/proton_bits.cpp       |   8 +
 proton-c/bindings/cpp/src/proton_bits.h         |   5 +
 proton-c/bindings/cpp/src/types.cpp             |  47 ++-
 proton-c/bindings/go/README.md                  |   5 -
 .../proton/go/amqp/interop_test.go              | 308 -------------------
 proton-c/docs/api/index.md                      |   6 +-
 proton-c/docs/api/user.doxygen.in               |   2 +-
 proton-c/include/proton/codec.h                 |   9 +-
 proton-c/src/codec/codec.c                      |  10 +-
 proton-c/src/codec/encoder.c                    |  10 +-
 40 files changed, 1106 insertions(+), 683 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index b1e4a1f..bafcd38 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -17,11 +17,19 @@
 # under the License.
 #
 
-include_directories ("${CMAKE_SOURCE_DIR}/proton-c/bindings/cpp/include")
+include_directories("${CMAKE_SOURCE_DIR}/proton-c/bindings/cpp/include")
 
-foreach(example broker helloworld helloworld_blocking helloworld_direct simple_recv simple_send)
+foreach(example
+    broker
+    helloworld
+    helloworld_blocking
+    helloworld_direct
+    simple_recv
+    simple_send
+    encode_decode)
   add_executable(${example} ${example}.cpp)
   target_link_libraries(${example} qpid-proton-cpp)
+  set_source_files_properties(${example}.cpp PROPERTIES COMPILE_FLAGS "${CXX_WARNING_FLAGS}")
 endforeach()
 
 add_test(

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp
new file mode 100644
index 0000000..5096c40
--- /dev/null
+++ b/examples/cpp/encode_decode.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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/cpp/Values.h>
+#include <proton/cpp/Value.h>
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+
+using namespace std;
+using namespace proton::reactor;
+
+// Examples of how to use the Encoder and Decoder to create and examine AMQP values.
+//
+
+// Print is defined at the end as an example of how to query and extract complex
+// values in terms of their simple components.
+void print(Values& values);
+
+// Inserting and extracting simple C++ values.
+void simple_insert_extract() {
+    Values values;
+    cout << endl << "== Simple values: int, string, bool" << endl;
+    values << 42 << "foo" << true;
+    print(values);
+    int i;
+    std::string s;
+    bool b;
+    values.rewind();
+    values >> i >> s >> b;
+    cout << "Extracted: " << i << ", " << s << ", " << b << endl;
+    cout << "Encoded as AMQP in " << values.encode().size() << " bytes" << endl;
+}
+
+// Inserting values as a specific AMQP type
+void simple_insert_extract_exact_type() {
+    Values values;
+    cout << endl << "== Specific AMQP types: byte, long, symbol" << endl;
+    values << Byte('x') << Long(123456789123456789) << Symbol("bar");
+    print(values);
+    values.rewind();
+    // Check that we encoded the correct types, but note that decoding will
+    // still convert to standard C++ types, in particular any AMQP integer type
+    // can be converted to a long-enough C++ integer type..
+    int64_t i1, i2;
+    std::string s;
+    values >> i1 >> i2 >> s;
+    cout << "Extracted (with conversion) " << i1 << ", " << i2 << ", " << s << endl;
+
+    // Now use the as() function to fail unless we extract the exact AMQP type expected.
+    values.rewind();            // Byte(1) << Long(2) << Symbol("bar");
+    Long l;
+    // Fails, extracting Byte as Long
+    try { values >> as<LONG>(l); throw logic_error("expected error"); } catch (Decoder::Error) {}
+    Byte b;
+    values >> as<BYTE>(b) >> as<LONG>(l); // OK, extract Byte as Byte, Long as Long.
+    std::string str;
+    // Fails, extracting Symbol as String.
+    try { values >> as<STRING>(str); throw logic_error("expected error"); } catch (Decoder::Error) {}
+    values >> as<SYMBOL>(str);       // OK, extract Symbol as Symbol
+    cout << "Extracted (exact) " << b << ", " << l << ", " << str << endl;
+}
+
+// Some helper templates to print map and vector results.
+namespace std {
+template<class T, class U> ostream& operator<<(ostream& o, const pair<T,U>& p) {
+    return o << p.first << ":" << p.second;
+}
+template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
+    o << "[ ";
+    ostream_iterator<T> oi(o, " ");
+    copy(v.begin(), v.end(), oi);
+    return o << "]";
+}
+template<class K, class T> ostream& operator<<(ostream& o, const map<K, T>& m) {
+    o << "{ ";
+    ostream_iterator<pair<K,T> > oi(o, " ");
+    copy(m.begin(), m.end(), oi);
+    return o << "}";
+}
+}
+
+// Insert/extract C++ containers.
+void insert_extract_containers() {
+    cout << endl << "== Array, list and map." << endl;
+
+    vector<int> a;
+    a.push_back(1);
+    a.push_back(2);
+    a.push_back(3);
+    vector<int> l;
+    l.push_back(4);
+    l.push_back(5);
+    map<string, int> m;
+    m["one"] = 1;
+    m["two"] = 2;
+
+    Values values;
+    values << as<ARRAY>(a) << as<LIST>(l) << as<MAP>(m);
+    print(values);
+
+    vector<int> a1, l1;
+    map<string, int> m1;
+    values.rewind();
+    values >> as<ARRAY>(a1) >> as<LIST>(l1) >> as<MAP>(m1);
+    cout << "Extracted: " << a1 << ", " << l1 << ", " << m1 << endl;
+}
+
+// Containers with mixed types, use Value to represent arbitrary AMQP types.
+void mixed_containers() {
+    cout << endl << "== List and map of mixed type values." << endl;
+    vector<Value> l;
+    l.push_back(Value(42));
+    l.push_back(Value(String("foo")));
+    map<Value, Value> m;
+    m[Value("five")] = Value(5);
+    m[Value(4)] = Value("four");
+    Values values;
+    values << as<LIST>(l) << as<MAP>(m);
+    print(values);
+
+    vector<Value> l1;
+    map<Value, Value> m1;
+    values.rewind();
+    values >> as<LIST>(l1) >> as<MAP>(m1);
+    cout << "Extracted: " << l1 << ", " << m1 << endl;
+}
+
+// Insert using stream operators (see printNext for example of extracting with stream ops.)
+void insert_extract_stream_operators() {
+    cout << endl << "== Insert with stream operators." << endl;
+    Values values;
+    // Note: array elements must be encoded with the exact type, they are not
+    // automaticlly converted. Mismatched types for array elements will not
+    // be detected until values.encode() is called.
+    values << Start::array(INT) << Int(1) << Int(2) << Int(3) << finish();
+    print(values);
+
+    values.clear();
+    values << Start::list() << Int(42) << false << Symbol("x") << finish();
+    print(values);
+
+    values.clear();
+    values << Start::map() << "k1" << Int(42) << Symbol("k2") << false << finish();
+    print(values);
+}
+
+int main(int, char**) {
+    try {
+        simple_insert_extract();
+        simple_insert_extract_exact_type();
+        insert_extract_containers();
+        mixed_containers();
+        insert_extract_stream_operators();
+    } catch (const exception& e) {
+        cerr << endl << "error: " << e.what() << endl;
+        return 1;
+    }
+}
+
+// printNext prints the next value from Values by recursively descending into complex values.
+//
+// NOTE this is for example puroses only: There is a built in ostream operator<< for Values.
+//
+//
+void printNext(Values& values) {
+    TypeId type = values.type();
+    Start start;
+    switch (type) {
+      case ARRAY: {
+          values >> start;
+          cout << "array<" << start.element;
+          if (start.isDescribed) {
+              cout  << ", descriptor=";
+              printNext(values);
+          }
+          cout << ">[";
+          for (size_t i = 0; i < start.size; ++i) {
+              if (i) cout << ", ";
+              printNext(values);
+          }
+          cout << "]";
+          values >> finish();
+          break;
+      }
+      case LIST: {
+          values >> start;
+          cout << "list[";
+          for (size_t i = 0; i < start.size; ++i) {
+              if (i) cout << ", ";
+              printNext(values);
+          }
+          cout << "]";
+          values >> finish();
+          break;
+      }
+      case MAP: {
+          values >> start;
+          cout << "map{";
+          for (size_t i = 0; i < start.size/2; ++i) {
+              if (i) cout << ", ";
+              printNext(values);
+              cout << ":";        // key:value
+              printNext(values);
+          }
+          cout << "}";
+          values >> finish();
+          break;
+      }
+      case DESCRIBED: {
+          values >> start;
+          cout << "described(";
+          printNext(values);      // Descriptor
+          printNext(values);      // Value
+          values >> finish();
+          break;
+      }
+      default:
+        // A simple type. We could continue the switch for all AMQP types but
+        // instead we us the `Value` type which can hold and print any AMQP
+        // value.
+        Value v;
+        values >> v;
+        cout << type << "(" << v << ")";
+    }
+}
+
+// Print all the values with printNext
+void print(Values& values) {
+    values.rewind();
+    cout << "Values: ";
+    while (values.more()) {
+        printNext(values);
+        if (values.more()) cout << ", ";
+    }
+    cout << endl;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 9a8ac67..3da1ddb 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -20,7 +20,7 @@
 import unittest
 import os, sys, socket, time
 from  random import randrange
-from subprocess import Popen, check_output, PIPE
+from subprocess import Popen, check_output, PIPE, STDOUT
 
 NULL = open(os.devnull, 'w')
 
@@ -58,7 +58,7 @@ class Broker(object):
 
 
 class ExampleTest(unittest.TestCase):
-    """Test examples"""
+    """Run the examples, verify they behave as expected."""
 
     @classmethod
     def tearDownClass(self):
@@ -89,6 +89,8 @@ class ExampleTest(unittest.TestCase):
         recv_expect += "".join(['[%d]: b"some arbitrary binary data"\n' % (i+1) for i in range(n)])
         self.assertEqual(recv_expect, recv)
 
+        # FIXME aconway 2015-06-16: bug when receiver is started before sender, messages
+        # are not delivered to receiver.
     def FIXME_test_simple_recv_send(self):
         """Start receiver first, then run sender"""
         b = Broker.get()
@@ -101,5 +103,40 @@ class ExampleTest(unittest.TestCase):
         out, err = recv.communicate()
         self.assertEqual(recv_expect, out)
 
+    def call(self, *cmd):
+        p = Popen(cmd, stdout=PIPE, stderr=STDOUT)
+        out, err = p.communicate()
+        self.assertEqual(0, p.returncode,
+                         "%s exit code %s, output:\n%s\n---- end of %s exit code %s" % (
+                             cmd, p.returncode, out, cmd, p.returncode))
+        return out
+
+    def test_encode_decode(self):
+        expect="""
+== Simple values: int, string, bool
+Values: int(42), string("foo"), bool(true)
+Extracted: 42, foo, 1
+Encoded as AMQP in 8 bytes
+
+== Specific AMQP types: byte, long, symbol
+Values: byte(120), long(123456789123456789), symbol(:bar)
+Extracted (with conversion) 120, 123456789123456789, bar
+Extracted (exact) x, 123456789123456789, bar
+
+== Array, list and map.
+Values: array<int>[int(1), int(2), int(3)], list[int(4), int(5)], map{string("one"):int(1), string("two"):int(2)}
+Extracted: [ 1 2 3 ], [ 4 5 ], { one:1 two:2 }
+
+== List and map of mixed type values.
+Values: list[int(42), string("foo")], map{int(4):string("four"), string("five"):int(5)}
+Extracted: [ 42 "foo" ], { 4:"four" "five":5 }
+
+== Insert with stream operators.
+Values: array<int>[int(1), int(2), int(3)]
+Values: list[int(42), bool(false), symbol(:x)]
+Values: map{string("k1"):int(42), symbol(:"k2"):bool(false)}
+"""
+        self.maxDiff = None
+        self.assertMultiLineEqual(expect, self.call("./encode_decode"))
 if __name__ == "__main__":
     unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/examples/cpp/simple_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_recv.cpp b/examples/cpp/simple_recv.cpp
index 42c561b..6612b16 100644
--- a/examples/cpp/simple_recv.cpp
+++ b/examples/cpp/simple_recv.cpp
@@ -46,7 +46,7 @@ class Recv : public MessagingHandler {
     }
 
     void onMessage(Event &e) {
-        uint64_t id = 0;
+        int64_t id = 0;
         Message msg = e.getMessage();
         if (msg.getIdType() == PN_ULONG) {
             id = msg.getId();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 049755e..9276a74 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -213,6 +213,8 @@ if (CMAKE_COMPILER_IS_GNUCC)
     set (WERROR "-Werror")
   endif (ENABLE_WARNING_ERROR)
   set (COMPILE_WARNING_FLAGS "${WERROR} -Wall -pedantic-errors")
+  # C++ allow "%z" format specifier and variadic macros
+  set (CXX_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format -Wno-variadic-macros" CACHE STRING "C++ warning flags")
   if (NOT BUILD_WITH_CXX)
     set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wstrict-prototypes")
     set (COMPILE_LANGUAGE_FLAGS "-std=c99")
@@ -227,8 +229,7 @@ if (CMAKE_COMPILER_IS_GNUCC)
       set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wc++-compat -Wvla -Wsign-compare -Wwrite-strings")
     endif (${GCC_VERSION} VERSION_LESS "4.3.0")
   else (NOT BUILD_WITH_CXX)
-    # allow "%z" format specifier and variadic macros
-    set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format -Wno-variadic-macros")
+    set (COMPILE_WARNING_FLAGS "${CXX_WARNING_FLAGS}")
   endif (NOT BUILD_WITH_CXX)
 
   if (ENABLE_UNDEFINED_ERROR)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index cc1c74a..18533ec 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -22,8 +22,7 @@
 include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/src")
 include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/include")
 
-add_library (
-  qpid-proton-cpp SHARED
+set(qpid-proton-cpp-source
   src/Acceptor.cpp
   src/Acking.cpp
   src/Connection.cpp
@@ -54,6 +53,7 @@ add_library (
   src/Transport.cpp
   src/Url.cpp
   src/Value.cpp
+  src/Values.cpp
   src/proton_bits.cpp
   src/blocking/BlockingConnection.cpp
   src/blocking/BlockingConnectionImpl.cpp
@@ -63,6 +63,10 @@ add_library (
   src/types.cpp
   )
 
+set_source_files_properties(${qpid-proton-cpp-source} PROPERTIES COMPILE_FLAGS "${CXX_WARNING_FLAGS}")
+
+add_library(qpid-proton-cpp SHARED ${qpid-proton-cpp-source})
+
 target_link_libraries (qpid-proton-cpp ${PLATFORM_LIBS} qpid-proton)
 
 set_target_properties (

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Data.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Data.h b/proton-c/bindings/cpp/include/proton/cpp/Data.h
index 2204e8f..ef78a13 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Data.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Data.h
@@ -22,6 +22,10 @@
 #include "proton/cpp/ImportExport.h"
 #include <iosfwd>
 
+/**@file
+ * Base for classes that hold AMQP data.
+ * @internal
+ */
 struct pn_data_t;
 
 namespace proton {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Decoder.h b/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
index 542315e..9b6df6e 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Decoder.h
@@ -29,43 +29,40 @@ namespace reactor {
 
 class Value;
 
+/**@file
+ * Stream-like decoder from AMQP bytes to C++ values.
+ * @ingroup cpp
+ */
+
 /**
+@ingroup cpp
+
 Stream-like decoder from AMQP bytes to a stream of C++ values.
 
-@see types.h defines C++ typedefs and types for AMQP each type. These types can
-all be extracted from the corresponding AMQP type. In additon operator>> will do
-the following conversions from AMQP to C++ types:
-
-+-----------------------------------------+--------------------------------------------------+
-|Target C++ type                          |Allowed AMQP types                                |
-+=========================================+==================================================+
-|bool                                     |Bool                                              |
-|-----------------------------------------+--------------------------------------------------|
-|signed integer type                      |Byte,Short,Int,Long [1]                           |
-+-----------------------------------------+--------------------------------------------------+
-|unsigned integer type                    |UByte,UShort,UInt,ULong [1]                       |
-+-----------------------------------------+--------------------------------------------------+
-|float or double                          |Float or Double                                   |
-+-----------------------------------------+--------------------------------------------------+
-|Value                                    |Any type                                          |
-+-----------------------------------------+--------------------------------------------------+
-|std::string                              |String, Binary, Symbol                            |
-+-----------------------------------------+--------------------------------------------------+
-|wchar_t                                  |Char                                              |
-+-----------------------------------------+--------------------------------------------------+
-|std::map<K, T>                           |Map with keys that convert to K and data that     |
-|                                         |converts to T                                     |
-+-----------------------------------------+--------------------------------------------------+
-|Map                                      |Map may have mixed keys and data types            |
-+-----------------------------------------+--------------------------------------------------+
-|std::vector<T>                           |List or Array if data converts to T               |
-+-----------------------------------------+--------------------------------------------------+
-|List                                     |List, may have mixed types and datas              |
-+-----------------------------------------+--------------------------------------------------+
-
-You can disable conversions and force an exact type match using @see exact()
+types.h defines C++ types corresponding to AMQP types.
+
+Decoder operator>> will extract AMQP types into corresponding C++ types, and do
+simple conversions, e.g. from AMQP integer types to corresponding or larger C++
+integer types.
+
+You can require an exact AMQP type using the `as<type>(value)` helper. E.g.
+
+    Int i;
+    decoder >> as<INT>(i):       // Will throw if decoder does not contain an INT
+
+You can also use the `as` helper to extract an AMQP list, array or map into C++ containers.
+
+    std::vector<Int> v;
+    decoder >> as<LIST>(v);     // Extract a list of INT.
+
+AMQP maps can be inserted/extracted to any container with pair<X,Y> as
+value_type, which includes std::map and std::unordered_map but also for
+example std::vector<std::pair<X,Y> >. This allows you to perserve order when
+extracting AMQP maps.
+
+You can also extract container values element-by-element, see the Start class.
 */
-class Decoder : public virtual Data {
+PN_CPP_EXTERN class Decoder : public virtual Data {
   public:
     /** Raised if a Decoder operation fails  */
     struct Error : public ProtonException {
@@ -95,10 +92,12 @@ class Decoder : public virtual Data {
      */
     PN_CPP_EXTERN TypeId type() const;
 
-    /** @defgroup decoder_simple_types Extract simple types, @see Decoder for details.
-     *@throw Error if the Decoder is empty or the current value has an incompatible type.
-     *@{
+    /** @name Extract simple types
+     * Overloads to extract simple types.
+     * @throw Error if the Decoder is empty or the current value has an incompatible type.
+     * @{
      */
+    PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Null);
     PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Bool&);
     PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Ubyte&);
     PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Byte&);
@@ -120,14 +119,59 @@ class Decoder : public virtual Data {
     PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Value&);
     ///@}
 
-    ///@internal
-    template <class T> struct ExactRef { T& value; ExactRef(T& ref) : value(ref) {} };
+    /** Extract and return a value of type T. */
+    template <class T> T get() { T value; *this >> value; return value; }
+
+    /** Extract and return a value of type T, as AMQP type. */
+    template <class T, TypeId A> T getAs() { T value; *this >> as<A>(value); return value; }
 
-    /** @see exact() */
-  template <class T> friend Decoder& operator>>(Decoder&, ExactRef<T>);
+    /** Call Decoder::start() in constructor, Decoder::finish in destructor() */
+    struct Scope : public Start {
+        Decoder& decoder;
+        Scope(Decoder& d) : decoder(d) { d >> *this; }
+        ~Scope() { decoder >> finish(); }
+    };
+
+    template <TypeId A, class T> friend Decoder& operator>>(Decoder& d, Ref<T, A> ref) {
+        d.checkType(A);
+        d >> ref.value;
+        return d;
+    }
+
+    /** start extracting a container value, one of array, list, map, described.
+     * The basic pattern is:
+     *
+     *     Start s;
+     *     decoder >> 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...
+     *     decoder >> finish();
+     *
+     * The first value of an ARRAY is a descriptor if Start::descriptor is true,
+     * followed by Start::size elemets 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.
+     *
+     * Note Scope automatically calls finish() in its destructor.
+     *
+     *@throw decoder::error if the curent value is not a container type.
+     */
+    PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Start&);
+
+    /** Finish extracting a container value. */
+    PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Finish);
+
+    /** Skip a value */
+    PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Skip);
 
   private:
-    PN_CPP_EXTERN Decoder(pn_data_t*);
     template <class T> Decoder& extract(T& value);
     void checkType(TypeId);
 
@@ -139,26 +183,36 @@ class Decoder : public virtual Data {
   friend class Encoder;
 };
 
-/**
- * exact() disables the conversions allowed by Decoder operator>> and requires exact type match.
- *
- * For example the following will throw Decode::Error unless decoder conntains
- * an AMQP bool and an AMQP ULong.
- *
- * @code
- * Bool b;
- * ULong ul;
- * decoder >> exact(b) >> exact(ul)
- * @code
- */
-template <class T> Decoder::ExactRef<T> exact(T& value) {
-    return Decoder::ExactRef<T>(value);
+template <class T> Decoder& operator>>(Decoder& d, Ref<T, ARRAY> ref)  {
+    Decoder::Scope s(d);
+    if (s.isDescribed) d >> skip();
+    ref.value.clear();
+    ref.value.resize(s.size);
+    for (typename T::iterator i = ref.value.begin(); i != ref.value.end(); ++i) {
+        d >> *i;
+    }
+    return d;
+}
+
+template <class T> Decoder& operator>>(Decoder& d, Ref<T, LIST> ref)  {
+    Decoder::Scope s(d);
+    ref.value.clear();
+    ref.value.resize(s.size);
+    for (typename T::iterator i = ref.value.begin(); i != ref.value.end(); ++i)
+        d >> *i;
+    return d;
 }
 
-///@see exact()
-template <class T> Decoder& operator>>(Decoder& d, Decoder::ExactRef<T> ref) {
-    d.checkType(TypeIdOf<T>::value);
-    d >> ref.value;
+template <class T> Decoder& operator>>(Decoder& d, Ref<T, MAP> ref)  {
+    Decoder::Scope m(d);
+    ref.value.clear();
+    for (size_t i = 0; i < m.size/2; ++i) {
+        typename T::key_type k;
+        typename T::mapped_type v;
+        d >> k >> v;
+        ref.value[k] = v;
+    }
+    return d;
 }
 
 }} // namespace proton::reactor

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Duration.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Duration.h b/proton-c/bindings/cpp/include/proton/cpp/Duration.h
index 08aaf3f..bb2a063 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Duration.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Duration.h
@@ -28,7 +28,7 @@
 namespace proton {
 namespace reactor {
 
-/**   \ingroup C++
+/** @ingroup cpp
  * A duration is a time in milliseconds.
  */
 class Duration

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Encoder.h b/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
index 460bea4..8e92881 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Encoder.h
@@ -31,13 +31,28 @@ namespace reactor {
 
 class Value;
 
+/**@file
+ * Stream-like encoder from C++ values to AMQP bytes.
+ * @ingroup cpp
+*/
+
 /**
-Stream-like encoder from C++ values to AMQP bytes.
+@ingroup cpp
 
-@see types.h defines C++ typedefs and types for AMQP each type. These types
+types.h defines C++ typedefs and types for AMQP each type. These types
 insert as the corresponding AMQP type. Normal C++ conversion rules apply if you
 insert any other type.
 
+C++ containers can be inserted as AMQP containers with the as() helper functions. E.g.
+
+   std::vector<Symbol> v; encoder << as<List>(v);
+
+AMQP maps can be inserted/extracted to any container with pair<X,Y> as
+value_type, which includes std::map and std::unordered_map but also for
+example std::vector<std::pair<X,Y> >. This allows you to perserve order when
+extracting AMQP maps.
+
+You can also insert containers element-by-element, see the Start class.
 */
 class Encoder : public virtual Data {
   public:
@@ -68,9 +83,10 @@ class Encoder : public virtual Data {
     /** Encode the current values into a std::string. Clears the encoder. */
     PN_CPP_EXTERN std::string encode();
 
-    /** @defgroup encoder_simple_types Insert simple types.
+    /** @name Insert simple types.
      *@{
      */
+    PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Null);
     PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Bool);
     PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Ubyte);
     PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, Byte);
@@ -94,8 +110,25 @@ class Encoder : public virtual Data {
     PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, const Value&);
     ///@}
 
+    /** Start a container type. See the Start class. */
+    PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, const Start&);
+
+    /** Finish a container type. */
+    PN_CPP_EXTERN friend Encoder& operator<<(Encoder& e, Finish);
+
+
+    /**@name Insert values returned by the as<TypeId> helper.
+     *@{
+     */
+  template <class T, TypeId A> friend Encoder& operator<<(Encoder&, CRef<T, A>);
+  template <class T> friend Encoder& operator<<(Encoder&, CRef<T, ARRAY>);
+  template <class T> friend Encoder& operator<<(Encoder&, CRef<T, LIST>);
+  template <class T> friend Encoder& operator<<(Encoder&, CRef<T, MAP>);
+    // TODO aconway 2015-06-16: DESCRIBED.
+    ///@}
+
   private:
-    PN_CPP_EXTERN Encoder(pn_data_t* pd); // Does not own.
+    PN_CPP_EXTERN Encoder(pn_data_t* pd);
 
     // Not implemented
     Encoder(const Encoder&);
@@ -104,5 +137,48 @@ class Encoder : public virtual Data {
   friend class Value;
 };
 
+/** Encode const char* as string */
+inline Encoder& operator<<(Encoder& e, const char* s) { return e << String(s); }
+
+/** Encode char* as string */
+inline Encoder& operator<<(Encoder& e, char* s) { return e << String(s); }
+
+/** Encode std::string as string */
+inline Encoder& operator<<(Encoder& e, const std::string& s) { return e << String(s); }
+
+//@internal Convert a Ref to a CRef.
+template <class T, TypeId A> Encoder& operator<<(Encoder& e, Ref<T, A> ref) {
+    return e << CRef<T,A>(ref);
+}
+
+// TODO aconway 2015-06-16: described array insertion.
+
+template <class T> Encoder& operator<<(Encoder& e, CRef<T, ARRAY> a) {
+    e << Start::array(TypeIdOf<typename T::value_type>::value);
+    for (typename T::const_iterator i = a.value.begin(); i != a.value.end(); ++i)
+        e << *i;
+    e << finish();
+    return e;
+}
+
+template <class T> Encoder& operator<<(Encoder& e, CRef<T, LIST> l) {
+    e << Start::list();
+    for (typename T::const_iterator i = l.value.begin(); i != l.value.end(); ++i)
+        e << *i;
+    e << finish();
+    return e;
+}
+
+template <class T> Encoder& operator<<(Encoder& e, CRef<T, MAP> m){
+    e << Start::map();
+    for (typename T::const_iterator i = m.value.begin(); i != m.value.end(); ++i) {
+        e << i->first;
+        e << i->second;
+    }
+    e << finish();
+    return e;
+}
+
+
 }}
 #endif // ENCODER_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Exception.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Exception.h b/proton-c/bindings/cpp/include/proton/cpp/Exception.h
deleted file mode 100644
index d24c8ef..0000000
--- a/proton-c/bindings/cpp/include/proton/cpp/Exception.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef PROTON_CPP_EXCEPTIONS_H
-#define PROTON_CPP_EXCEPTIONS_H
-
-/*
- *
- * 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 <stdexcept>
-
-namespace proton {
-namespace reactor {
-
-class Exception : public std::runtime_error
-{
-  public:
-    explicit Exception(const std::string& msg) throw() : std::runtime_error(msg) {}
-};
-
-class MessageReject : public Exception
-{
-  public:
-    explicit MessageReject(const std::string& msg) throw() : Exception(msg) {}
-};
-
-class MessageRelease : public Exception
-{
-  public:
-    explicit MessageRelease(const std::string& msg) throw() : Exception(msg) {}
-};
-
-}} // namespace proton::reactor
-
-#endif  /*!PROTON_CPP_EXCEPTIONS_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h b/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
index e6c0341..07b0dde 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/MessagingHandler.h
@@ -78,8 +78,8 @@ class PN_CPP_EXTERN MessagingHandler : public ProtonHandler , public Acking
     virtual void onTransportClosed(Event &e);
   protected:
     int prefetch;
-    bool autoSettle;
     bool autoAccept;
+    bool autoSettle;
     bool peerCloseIsError;
     MessagingAdapter *messagingAdapter;
     Handler *flowController;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Value.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Value.h b/proton-c/bindings/cpp/include/proton/cpp/Value.h
index 65ca7ec..9555f29 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/Value.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/Value.h
@@ -19,66 +19,61 @@
  * under the License.
  */
 
-#include "proton/cpp/Encoder.h"
-#include "proton/cpp/Decoder.h"
-#include <iosfwd>
+#include "proton/cpp/Values.h"
 
+/**@file
+ * Holder for an AMQP value.
+ * @ingroup cpp
+ */
 namespace proton {
 namespace reactor {
 
-/** Holds a sequence of AMQP values, allows inserting and extracting.
- *
- * After inserting values, call rewind() to extract them.
- */
-class Values : public Encoder, public Decoder {
-  public:
-    Values();
-    Values(const Values&);
-    ~Values();
-
-    /** Copy data from another Values */
-    Values& operator=(const Values&);
-
-    PN_CPP_EXTERN void rewind();
-
-  private:
-  friend class Value;
-};
-
 /** Holds a single AMQP value. */
-class Value {
+PN_CPP_EXTERN class Value {
   public:
     PN_CPP_EXTERN Value();
     PN_CPP_EXTERN Value(const Value&);
+    /** Converting constructor from any settable value */
+    template <class T> explicit Value(const T& v);
     PN_CPP_EXTERN ~Value();
-
     PN_CPP_EXTERN Value& operator=(const Value&);
 
+
     TypeId type() const;
 
-    /** Set the value */
+    /** Set the value. */
     template<class T> void set(const T& value);
-    /** Get the value */
+    /** Get the value. */
     template<class T> void get(T& value) const;
     /** Get the value */
     template<class T> T get() const;
 
     /** Assignment sets the value */
     template<class T> Value& operator=(const T& value);
+
     /** Conversion operator gets  the value */
     template<class T> operator T() const;
 
-    /** Insert a value into an Encoder. */
+    /** insert a value into an Encoder. */
     PN_CPP_EXTERN friend Encoder& operator<<(Encoder&, const Value&);
 
     /** Extract a value from a decoder. */
-    PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, const Value&);
+    PN_CPP_EXTERN friend Decoder& operator>>(Decoder&, Value&);
+
+    /** Human readable format */
+    PN_CPP_EXTERN friend std::ostream& operator<<(std::ostream&, const Value&);
 
-  friend Decoder& operator>>(Decoder&, Value&);
-  friend Encoder& operator<<(Encoder&, const Value&);
+    bool operator==(const Value&) const;
+    bool operator !=(const Value& v) const{ return !(*this == v); }
 
-    private:
-    Values values;
+    /** operator < makes Value valid for use as a std::map key. */
+    bool operator<(const Value&) const;
+    bool operator>(const Value& v) const { return v < *this; }
+    bool operator<=(const Value& v) const { return !(*this > v); }
+    bool operator>=(const Value& v) const { return !(*this < v); }
+
+  private:
+    mutable Values values;
 };
 
 template<class T> void Value::set(const T& value) {
@@ -88,8 +83,7 @@ template<class T> void Value::set(const T& value) {
 
 template<class T> void Value::get(T& value) const {
     Values& v = const_cast<Values&>(values);
-    v.rewind();
-    v >> value;
+    v.rewind() >> value;
 }
 
 template<class T> T Value::get() const { T value; get(value); return value; }
@@ -98,6 +92,7 @@ template<class T> Value& Value::operator=(const T& value) { set(value); return *
 
 template<class T> Value::operator T() const { return get<T>(); }
 
+template<class T> Value::Value(const T& value) { set(value); }
 }}
 
 #endif // VALUE_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/Values.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/Values.h b/proton-c/bindings/cpp/include/proton/cpp/Values.h
new file mode 100644
index 0000000..5f62dd9
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/cpp/Values.h
@@ -0,0 +1,56 @@
+#ifndef VALUES_H
+#define VALUES_H
+/*
+ * 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/cpp/Encoder.h>
+#include <proton/cpp/Decoder.h>
+
+/**@file
+ * Holder for a sequence of AMQP values.
+ * @ingroup cpp
+ */
+
+namespace proton {
+namespace reactor {
+
+/** Holds a sequence of AMQP values, allows inserting and extracting.
+ *
+ * After inserting values, call rewind() to extract them.
+ */
+PN_CPP_EXTERN class Values : public Encoder, public Decoder {
+  public:
+    Values();
+    Values(const Values&);
+    ~Values();
+
+    /** Copy data from another Values */
+    Values& operator=(const Values&);
+
+    PN_CPP_EXTERN Values& rewind();
+
+  private:
+  friend class Value;
+};
+
+PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const Values&);
+
+}}
+
+#endif // VALUES_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/include/proton/cpp/types.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/cpp/types.h b/proton-c/bindings/cpp/include/proton/cpp/types.h
index 963a330..edd95b9 100644
--- a/proton-c/bindings/cpp/include/proton/cpp/types.h
+++ b/proton-c/bindings/cpp/include/proton/cpp/types.h
@@ -19,61 +19,68 @@
  * under the License.
  */
 
+#include <proton/codec.h>
+#include "proton/cpp/ImportExport.h"
+#include <algorithm>
+#include <bitset>
 #include <string>
 #include <stdint.h>
-#include <proton/codec.h>
-
-namespace proton {
-namespace reactor {
+#include <memory.h>
 
 /**@file
- *
- * C++ types representing simple AMQP types.
- *
+ * C++ types representing AMQP types.
+ * @ingroup cpp
  */
 
+namespace proton {
+namespace reactor {
 
-/** Convert pn_bytes_t to string */
-std::string str(const pn_bytes_t&);
-
-/** Convert string to pn_bytes_t */
-pn_bytes_t bytes(const std::string&);
-
-/** Identifies an AMQP type */
+/** TypeId identifies an AMQP type */
 enum TypeId {
-    NULL_=PN_NULL,
-    BOOL=PN_BOOL,
-    UBYTE=PN_UBYTE,
-    BYTE=PN_BYTE,
-    USHORT=PN_USHORT,
-    SHORT=PN_SHORT,
-    UINT=PN_UINT,
-    INT=PN_INT,
-    CHAR=PN_CHAR,
-    ULONG=PN_ULONG,
-    LONG=PN_LONG,
-    TIMESTAMP=PN_TIMESTAMP,
-    FLOAT=PN_FLOAT,
-    DOUBLE=PN_DOUBLE,
-    DECIMAL32=PN_DECIMAL32,
-    DECIMAL64=PN_DECIMAL64,
-    DECIMAL128=PN_DECIMAL128,
-    UUID=PN_UUID,
-    BINARY=PN_BINARY,
-    STRING=PN_STRING,
-    SYMBOL=PN_SYMBOL,
-    DESCRIBED=PN_DESCRIBED,
-    ARRAY=PN_ARRAY,
-    LIST=PN_LIST,
-    MAP=PN_MAP
+    NULL_=PN_NULL,              ///< The null type, contains no data.
+    BOOL=PN_BOOL,               ///< Boolean true or false.
+    UBYTE=PN_UBYTE,             ///< Unsigned 8 bit integer.
+    BYTE=PN_BYTE,               ///< Signed 8 bit integer.
+    USHORT=PN_USHORT,           ///< Unsigned 16 bit integer.
+    SHORT=PN_SHORT,             ///< Signed 16 bit integer.
+    UINT=PN_UINT,               ///< Unsigned 32 bit integer.
+    INT=PN_INT,                 ///< Signed 32 bit integer.
+    CHAR=PN_CHAR,               ///< 32 bit unicode character.
+    ULONG=PN_ULONG,             ///< Unsigned 64 bit integer.
+    LONG=PN_LONG,               ///< Signed 64 bit integer.
+    TIMESTAMP=PN_TIMESTAMP,     ///< Signed 64 bit milliseconds since the epoch.
+    FLOAT=PN_FLOAT,             ///< 32 bit binary floating point.
+    DOUBLE=PN_DOUBLE,           ///< 64 bit binary floating point.
+    DECIMAL32=PN_DECIMAL32,     ///< 32 bit decimal floating point.
+    DECIMAL64=PN_DECIMAL64,     ///< 64 bit decimal floating point.
+    DECIMAL128=PN_DECIMAL128,   ///< 128 bit decimal floating point.
+    UUID=PN_UUID,               ///< 16 byte UUID.
+    BINARY=PN_BINARY,           ///< Variable length sequence of bytes.
+    STRING=PN_STRING,           ///< Variable length utf8-encoded string.
+    SYMBOL=PN_SYMBOL,           ///< Variable length encoded string.
+    DESCRIBED=PN_DESCRIBED,     ///< A descriptor and a value.
+    ARRAY=PN_ARRAY,             ///< A sequence of values of the same type.
+    LIST=PN_LIST,               ///< A sequence of values, may be of mixed types.
+    MAP=PN_MAP                  ///< A sequence of key:value pairs, may be of mixed types.
 };
 
-/** @defgroup types C++ type definitions for AMQP types.
- *
+///@internal
+template <class T> struct Comparable {};
+template<class T> bool operator<(const Comparable<T>& a, const Comparable<T>& b) {
+    return static_cast<const T&>(a) < static_cast<const T&>(b); // operator < provided by type T
+}
+template<class T> bool operator>(const Comparable<T>& a, const Comparable<T>& b) { return b < a; }
+template<class T> bool operator<=(const Comparable<T>& a, const Comparable<T>& b) { return !(a > b); }
+template<class T> bool operator>=(const Comparable<T>& a, const Comparable<T>& b) { return !(a < b); }
+template<class T> bool operator==(const Comparable<T>& a, const Comparable<T>& b) { return a <= b && b <= a; }
+template<class T> bool operator!=(const Comparable<T>& a, const Comparable<T>& b) { return !(a == b); }
+
+/**
+ * @name C++ types representing AMQP types.
+ * @{
+ * @ingroup cpp
  * These types are all distinct for overloading purposes and will insert as the
  * corresponding AMQP type with Encoder operator<<.
- *
- * @{
  */
 struct Null {};
 typedef bool Bool;
@@ -90,11 +97,14 @@ typedef float Float;
 typedef double Double;
 
 ///@internal
+pn_bytes_t pn_bytes(const std::string&);
+
+///@internal
 #define STRING_LIKE(NAME)                                               \
-    struct NAME : public std::string{                                   \
+    PN_CPP_EXTERN struct NAME : public std::string{                     \
         NAME(const std::string& s=std::string()) : std::string(s) {}    \
-        NAME(const pn_bytes_t& b) : std::string(str(b)) {}              \
-        operator pn_bytes_t() const { return bytes(*this); }            \
+        NAME(const pn_bytes_t& b) : std::string(b.start, b.size) {}     \
+        operator pn_bytes_t() const { return pn_bytes(*this); }         \
     }
 
 /** UTF-8 encoded string */
@@ -104,58 +114,136 @@ STRING_LIKE(Symbol);
 /** Binary data */
 STRING_LIKE(Binary);
 
+///@internal
+pn_uuid_t pn_uuid(const std::string&);
+
+/** UUID is represented as a string but treated as if it always has 16 bytes. */
+PN_CPP_EXTERN struct Uuid : public std::string{
+    Uuid(const std::string& s=std::string()) : std::string(s) {}
+    Uuid(const pn_uuid_t& u) : std::string(&u.bytes[0], sizeof(pn_uuid_t::bytes)) {}
+    operator pn_uuid_t() const { return pn_uuid(*this); }
+};
+
 // TODO aconway 2015-06-11: alternative representation of variable-length data
 // as pointer to existing buffers.
 
-template <class T> struct Decimal {
-    T value;
-    Decimal(T v) : value(v) {}
-    Decimal& operator=(T v) { value = v; }
-    operator T() const { return value; }
+// TODO aconway 2015-06-16: usable representation of decimal types.
+template <class T> struct Decimal : public Comparable<Decimal<T> > {
+    char value[sizeof(T)];
+    Decimal() { ::memset(value, 0, sizeof(T)); }
+    Decimal(const T& v) { ::memcpy(value, &v, sizeof(T)); }
+    operator T() const { return *reinterpret_cast<const T*>(value); }
+    bool operator<(const Decimal<T>& x) {
+        return std::lexicographical_compare(value, value+sizeof(T), x.value, x.value+sizeof(T));
+    }
 };
 typedef Decimal<pn_decimal32_t> Decimal32;
 typedef Decimal<pn_decimal64_t> Decimal64;
 typedef Decimal<pn_decimal128_t> Decimal128;
 
-struct Timestamp {
+PN_CPP_EXTERN struct Timestamp {
     pn_timestamp_t milliseconds; ///< Since the epoch 00:00:00 (UTC), 1 January 1970.
-    Timestamp(int64_t ms) : milliseconds(ms) {}
+    Timestamp(int64_t ms=0) : milliseconds(ms) {}
     operator pn_timestamp_t() const { return milliseconds; }
+    bool operator<(const Timestamp& x) { return milliseconds < x.milliseconds; }
 };
 
-typedef pn_uuid_t Uuid;
-
 ///@}
 
-/** Meta-function to get the type-id from a class */
 template <class T> struct TypeIdOf {};
-template<> struct TypeIdOf<Null> { static const TypeId value; };
-template<> struct TypeIdOf<Bool> { static const TypeId value; };
-template<> struct TypeIdOf<Ubyte> { static const TypeId value; };
-template<> struct TypeIdOf<Byte> { static const TypeId value; };
-template<> struct TypeIdOf<Ushort> { static const TypeId value; };
-template<> struct TypeIdOf<Short> { static const TypeId value; };
-template<> struct TypeIdOf<Uint> { static const TypeId value; };
-template<> struct TypeIdOf<Int> { static const TypeId value; };
-template<> struct TypeIdOf<Char> { static const TypeId value; };
-template<> struct TypeIdOf<Ulong> { static const TypeId value; };
-template<> struct TypeIdOf<Long> { static const TypeId value; };
-template<> struct TypeIdOf<Timestamp> { static const TypeId value; };
-template<> struct TypeIdOf<Float> { static const TypeId value; };
-template<> struct TypeIdOf<Double> { static const TypeId value; };
-template<> struct TypeIdOf<Decimal32> { static const TypeId value; };
-template<> struct TypeIdOf<Decimal64> { static const TypeId value; };
-template<> struct TypeIdOf<Decimal128> { static const TypeId value; };
-template<> struct TypeIdOf<Uuid> { static const TypeId value; };
-template<> struct TypeIdOf<Binary> { static const TypeId value; };
-template<> struct TypeIdOf<String> { static const TypeId value; };
-template<> struct TypeIdOf<Symbol> { static const TypeId value; };
+template<> struct TypeIdOf<Null> { static const TypeId value=NULL_; };
+template<> struct TypeIdOf<Bool> { static const TypeId value=BOOL; };
+template<> struct TypeIdOf<Ubyte> { static const TypeId value=UBYTE; };
+template<> struct TypeIdOf<Byte> { static const TypeId value=BYTE; };
+template<> struct TypeIdOf<Ushort> { static const TypeId value=USHORT; };
+template<> struct TypeIdOf<Short> { static const TypeId value=SHORT; };
+template<> struct TypeIdOf<Uint> { static const TypeId value=UINT; };
+template<> struct TypeIdOf<Int> { static const TypeId value=INT; };
+template<> struct TypeIdOf<Char> { static const TypeId value=CHAR; };
+template<> struct TypeIdOf<Ulong> { static const TypeId value=ULONG; };
+template<> struct TypeIdOf<Long> { static const TypeId value=LONG; };
+template<> struct TypeIdOf<Timestamp> { static const TypeId value=TIMESTAMP; };
+template<> struct TypeIdOf<Float> { static const TypeId value=FLOAT; };
+template<> struct TypeIdOf<Double> { static const TypeId value=DOUBLE; };
+template<> struct TypeIdOf<Decimal32> { static const TypeId value=DECIMAL32; };
+template<> struct TypeIdOf<Decimal64> { static const TypeId value=DECIMAL64; };
+template<> struct TypeIdOf<Decimal128> { static const TypeId value=DECIMAL128; };
+template<> struct TypeIdOf<Uuid> { static const TypeId value=UUID; };
+template<> struct TypeIdOf<Binary> { static const TypeId value=BINARY; };
+template<> struct TypeIdOf<String> { static const TypeId value=STRING; };
+template<> struct TypeIdOf<Symbol> { static const TypeId value=SYMBOL; };
+
+template<class T, TypeId A> struct TypePair {
+    typedef T CppType;
+    TypeId type;
+};
+
+template<class T, TypeId A> struct Ref : public TypePair<T, A> {
+    Ref(T& v) : value(v) {}
+    T& value;
+};
+
+template<class T, TypeId A> struct CRef : public TypePair<T, A> {
+    CRef(const T& v) : value(v) {}
+    CRef(const Ref<T,A>& ref) : value(ref.value) {}
+    const T& value;
+};
+
+/** Create a reference to value as AMQP type A for decoding. For example to decode an array of Int:
+ *
+ *     std::vector<Int> v;
+ *     decoder >> as<ARRAY>(v);
+ */
+template <TypeId A, class T> Ref<T, A> as(T& value) { return Ref<T, A>(value); }
+
+/** Create a const reference to value as AMQP type A for encoding. */
+template <TypeId A, class T> CRef<T, A> as(const T& value) { return CRef<T, A>(value); }
+
+///@}
+
+// TODO aconway 2015-06-16: described types.
 
 /** Return the name of a type. */
-std::string typeName(TypeId);
+PN_CPP_EXTERN std::string typeName(TypeId);
+
+/** Print the name of a type */
+PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, TypeId);
 
 /** Return the name of a type from a class. */
-template<class T> std::string typeName() { return typeName(TypeIdOf<T>::value); }
+PN_CPP_EXTERN template<class T> std::string typeName() { return typeName(TypeIdOf<T>::value); }
+
+/** Information needed to start extracting or inserting a container type.
+ *
+ * With a decoder you can use `Start s = decoder.start()` or `Start s; decoder > s`
+ * to get the Start for the current container.
+ *
+ * With an encoder use one of the member functions startArray, startList, startMap or startDescribed
+ * to create an appropriate Start value, e.g. `encoder << startList() << ...`
+ */
+PN_CPP_EXTERN struct Start {
+    Start(TypeId type=NULL_, TypeId element=NULL_, bool described=false, size_t size=0);
+    TypeId type;            ///< The container type: ARRAY, LIST, MAP or DESCRIBED.
+    TypeId element;         ///< the element type for array only.
+    bool isDescribed;       ///< true if first value is a descriptor.
+    size_t size;            ///< the element count excluding the descriptor (if any)
+
+    /** Return a Start for an array */
+    static Start array(TypeId element, bool described=false);
+    /** Return a Start for a list */
+    static Start list();
+    /** Return a Start for a map */
+    static Start map();
+    /** Return a Start for a described type */
+    static Start described();
+};
+
+/** Finish insterting or extracting a container value. */
+PN_CPP_EXTERN struct Finish {};
+inline Finish finish() { return Finish(); }
+
+/** Skip a value */
+PN_CPP_EXTERN struct Skip{};
+inline Skip skip() { return Skip(); }
 
 }}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ConnectionImpl.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ConnectionImpl.h b/proton-c/bindings/cpp/src/ConnectionImpl.h
index 7add9a0..f16c862 100644
--- a/proton-c/bindings/cpp/src/ConnectionImpl.h
+++ b/proton-c/bindings/cpp/src/ConnectionImpl.h
@@ -41,7 +41,7 @@ class ConnectionImpl : public Endpoint
   public:
     PN_CPP_EXTERN ConnectionImpl(Container &c, pn_connection_t &pnConn);
     PN_CPP_EXTERN ConnectionImpl(Container &c, Handler *h = 0);
-    PN_CPP_EXTERN ~ConnectionImpl();
+    PN_CPP_EXTERN virtual ~ConnectionImpl();
     PN_CPP_EXTERN Transport &getTransport();
     PN_CPP_EXTERN Handler *getOverride();
     PN_CPP_EXTERN void setOverride(Handler *h);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ContainerImpl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ContainerImpl.cpp b/proton-c/bindings/cpp/src/ContainerImpl.cpp
index 61fc860..989bd00 100644
--- a/proton-c/bindings/cpp/src/ContainerImpl.cpp
+++ b/proton-c/bindings/cpp/src/ContainerImpl.cpp
@@ -47,10 +47,6 @@ ConnectionImpl *getImpl(const Connection &c) {
     return PrivateImplRef<Connection>::get(c);
 }
 
-ContainerImpl *getImpl(const Container &c) {
-    return PrivateImplRef<Container>::get(c);
-}
-
 } // namespace
 
 
@@ -253,8 +249,6 @@ Sender ContainerImpl::createSender(Connection &connection, std::string &addr, Ha
         pn_record_set_handler(record, wrapHandler(h));
     }
     snd.open();
-
-    ConnectionImpl *connImpl = getImpl(connection);
     return snd;
 }
 
@@ -266,8 +260,6 @@ Sender ContainerImpl::createSender(std::string &urlString) {
     Sender snd = session.createSender(containerId + '-' + path);
     pn_terminus_set_address(pn_link_target(snd.getPnLink()), path.c_str());
     snd.open();
-
-    ConnectionImpl *connImpl = getImpl(conn);
     return snd;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 6cfc09b..790cecb 100644
--- a/proton-c/bindings/cpp/src/Data.cpp
+++ b/proton-c/bindings/cpp/src/Data.cpp
@@ -41,8 +41,6 @@ void Data::clear() { pn_data_clear(data); }
 
 bool Data::empty() const { return pn_data_size(data) == 0; }
 
-std::ostream& operator<<(std::ostream& o, const Data& d) {
-    o << Object(d.data);
-}
+std::ostream& operator<<(std::ostream& o, const Data& d) { return o << Object(d.data); }
 
 }} // namespace proton::reactor

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 4170378..503db81 100644
--- a/proton-c/bindings/cpp/src/Decoder.cpp
+++ b/proton-c/bindings/cpp/src/Decoder.cpp
@@ -18,8 +18,10 @@
  */
 
 #include "proton/cpp/Decoder.h"
+#include "proton/cpp/Value.h"
 #include <proton/codec.h>
 #include "proton_bits.h"
+#include "Msg.h"
 
 namespace proton {
 namespace reactor {
@@ -44,15 +46,28 @@ struct SaveState {
     ~SaveState() { if (data) pn_data_restore(data, handle); }
     void cancel() { data = 0; }
 };
+
+struct Narrow {
+    pn_data_t* data;
+    Narrow(pn_data_t* d) : data(d) { pn_data_narrow(d); }
+    ~Narrow() { pn_data_widen(data); }
+};
+
+template <class T> T check(T result) {
+    if (result < 0)
+        throw Decoder::Error("decode: " + errorStr(result));
+    return result;
+}
+
+std::string str(const pn_bytes_t& b) { return std::string(b.start, b.size); }
+
 }
 
 void Decoder::decode(const char* i, size_t size) {
     SaveState ss(data);
     const char* end = i + size;
     while (i < end) {
-        int result = pn_data_decode(data, i, end - i);
-        if (result < 0) throw Decoder::Error("decode: " + errorStr(result));
-        i += result;
+        i += check(pn_data_decode(data, i, end - i));
     }
 }
 
@@ -89,11 +104,65 @@ template <class T, class U> void extract(pn_data_t* data, T& value, U (*get)(pn_
 
 }
 
+void Decoder::checkType(TypeId want) {
+    TypeId got = type();
+    if (want != got) badType(want, got);
+}
+
 TypeId Decoder::type() const {
     SaveState ss(data);
     return preGet(data);
 }
 
+Decoder& operator>>(Decoder& d, Start& s) {
+    SaveState ss(d.data);
+    s.type = preGet(d.data);
+    switch (s.type) {
+      case ARRAY:
+        s.size = pn_data_get_array(d.data);
+        s.element = TypeId(pn_data_get_array_type(d.data));
+        s.isDescribed = pn_data_is_array_described(d.data);
+        break;
+      case LIST:
+        s.size = pn_data_get_list(d.data);
+        break;
+      case MAP:
+        s.size = pn_data_get_map(d.data);
+        break;
+      case DESCRIBED:
+        s.isDescribed = true;
+        s.size = 1;
+        break;
+      default:
+        throw Decoder::Error(MSG("decode: " << s.type << " is not a container type"));
+    }
+    pn_data_enter(d.data);
+    ss.cancel();
+    return d;
+}
+
+Decoder& operator>>(Decoder& d, Finish) { pn_data_exit(d.data); return d; }
+
+Decoder& operator>>(Decoder& d, Skip) { pn_data_next(d.data); return d; }
+
+Decoder& operator>>(Decoder& d, Value& v) {
+    if (d.data == v.values.data) throw Decoder::Error("decode: extract into self");
+    pn_data_clear(v.values.data);
+    {
+        Narrow n(d.data);
+        check(pn_data_appendn(v.values.data, d.data, 1));
+    }
+    if (!pn_data_next(d.data)) throw Decoder::Error("decode: no more data");
+    return d;
+}
+
+
+Decoder& operator>>(Decoder& d, Null) {
+    SaveState ss(d.data);
+    badType(NULL_, preGet(d.data));
+    return d;
+}
+
 Decoder& operator>>(Decoder& d, Bool& value) {
     extract(d.data, value, pn_data_get_bool);
     return d;
@@ -112,7 +181,7 @@ Decoder& operator>>(Decoder& d, Ubyte& value) {
 Decoder& operator>>(Decoder& d, Byte& value) {
     SaveState ss(d.data);
     switch (preGet(d.data)) {
-      case BYTE: value = pn_data_get_ubyte(d.data); break;
+      case BYTE: value = pn_data_get_byte(d.data); break;
       default: badType(BYTE, TypeId(TypeId(pn_data_type(d.data))));
     }
     ss.cancel();
@@ -256,10 +325,4 @@ Decoder& operator>>(Decoder& d, std::string& value) {
     return d;
 }
 
-void Decoder::checkType(TypeId want) {
-    TypeId got = type();
-    if (want != got) badType(want, got);
-}
-
-
 }} // namespace proton::reactor

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 81fa365..9182400 100644
--- a/proton-c/bindings/cpp/src/Encoder.cpp
+++ b/proton-c/bindings/cpp/src/Encoder.cpp
@@ -18,8 +18,10 @@
  */
 
 #include "proton/cpp/Encoder.h"
+#include "proton/cpp/Value.h"
 #include <proton/codec.h>
 #include "proton_bits.h"
+#include "Msg.h"
 
 namespace proton {
 namespace reactor {
@@ -33,27 +35,30 @@ struct SaveState {
     pn_handle_t handle;
     SaveState(pn_data_t* d) : data(d), handle(pn_data_point(d)) {}
     ~SaveState() { if (data) pn_data_restore(data, handle); }
+    void cancel() { data = 0; }
 };
 
-template <class T> T check(T result) {
+void check(int result, pn_data_t* data) {
     if (result < 0)
-        throw Encoder::Error("encode: " + errorStr(result));
-    return result;
+        throw Encoder::Error("encode: " + errorStr(pn_data_error(data), result));
 }
 }
 
 bool Encoder::encode(char* buffer, size_t& size) {
     SaveState ss(data);               // In case of error
-    pn_data_rewind(data);
     ssize_t result = pn_data_encode(data, buffer, size);
     if (result == PN_OVERFLOW) {
-        size = pn_data_encoded_size(data);
-        return false;
+        result = pn_data_encoded_size(data);
+        if (result >= 0) {
+            size = result;
+            return false;
+        }
     }
-    check(result);
+    check(result, data);
     size = result;
-    ss.data = 0;                // Don't restore state, all is well.
+    ss.cancel();                // Don't restore state, all is well.
     pn_data_clear(data);
+    return true;
 }
 
 void Encoder::encode(std::string& s) {
@@ -70,16 +75,35 @@ std::string Encoder::encode() {
     return s;
 }
 
+Encoder& operator<<(Encoder& e, const Start& s) {
+    switch (s.type) {
+      case ARRAY: pn_data_put_array(e.data, s.isDescribed, pn_type_t(s.element)); break;
+      case MAP: pn_data_put_map(e.data); break;
+      case LIST: pn_data_put_list(e.data); break;
+      case DESCRIBED: pn_data_put_described(e.data); break;
+      default:
+        throw Encoder::Error(MSG("encode: " << s.type << " is not a container type"));
+    }
+    pn_data_enter(e.data);
+    return e;
+}
+
+Encoder& operator<<(Encoder& e, Finish) {
+    pn_data_exit(e.data);
+    return e;
+}
+
 namespace {
 template <class T, class U>
 Encoder& insert(Encoder& e, pn_data_t* data, T& value, int (*put)(pn_data_t*, U)) {
     SaveState ss(data);         // Save state in case of error.
-    check(put(data, value));
-    ss.data = 0;                // Don't restore state, all is good.
+    check(put(data, value), data);
+    ss.cancel();                // Don't restore state, all is good.
     return e;
 }
 }
 
+Encoder& operator<<(Encoder& e, Null) { pn_data_put_null(e.data); return e; }
 Encoder& operator<<(Encoder& e, Bool value) { return insert(e, e.data, value, pn_data_put_bool); }
 Encoder& operator<<(Encoder& e, Ubyte value) { return insert(e, e.data, value, pn_data_put_ubyte); }
 Encoder& operator<<(Encoder& e, Byte value) { return insert(e, e.data, value, pn_data_put_byte); }
@@ -101,4 +125,34 @@ Encoder& operator<<(Encoder& e, String value) { return insert(e, e.data, value,
 Encoder& operator<<(Encoder& e, Symbol value) { return insert(e, e.data, value, pn_data_put_symbol); }
 Encoder& operator<<(Encoder& e, Binary value) { return insert(e, e.data, value, pn_data_put_binary); }
 
+// Meta-function to get the class from the type ID.
+template <TypeId A> struct ClassOf {};
+template<> struct ClassOf<NULL_> { typedef Null ValueType; };
+template<> struct ClassOf<BOOL> { typedef Bool ValueType; };
+template<> struct ClassOf<UBYTE> { typedef Ubyte ValueType; };
+template<> struct ClassOf<BYTE> { typedef Byte ValueType; };
+template<> struct ClassOf<USHORT> { typedef Ushort ValueType; };
+template<> struct ClassOf<SHORT> { typedef Short ValueType; };
+template<> struct ClassOf<UINT> { typedef Uint ValueType; };
+template<> struct ClassOf<INT> { typedef Int ValueType; };
+template<> struct ClassOf<CHAR> { typedef Char ValueType; };
+template<> struct ClassOf<ULONG> { typedef Ulong ValueType; };
+template<> struct ClassOf<LONG> { typedef Long ValueType; };
+template<> struct ClassOf<TIMESTAMP> { typedef Timestamp ValueType; };
+template<> struct ClassOf<FLOAT> { typedef Float ValueType; };
+template<> struct ClassOf<DOUBLE> { typedef Double ValueType; };
+template<> struct ClassOf<DECIMAL32> { typedef Decimal32 ValueType; };
+template<> struct ClassOf<DECIMAL64> { typedef Decimal64 ValueType; };
+template<> struct ClassOf<DECIMAL128> { typedef Decimal128 ValueType; };
+template<> struct ClassOf<UUID> { typedef Uuid ValueType; };
+template<> struct ClassOf<BINARY> { typedef Binary ValueType; };
+template<> struct ClassOf<STRING> { typedef String ValueType; };
+template<> struct ClassOf<SYMBOL> { typedef Symbol ValueType; };
+
+Encoder& operator<<(Encoder& e, const Value& v) {
+    if (e.data == v.values.data) throw Encoder::Error("encode: cannot insert into self");
+    check(pn_data_appendn(e.data, v.values.data, 1), e.data);
+    return e;
+}
+
 }} // namespace proton::reactor

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Handler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Handler.cpp b/proton-c/bindings/cpp/src/Handler.cpp
index 4d1b581..5c37c8d 100644
--- a/proton-c/bindings/cpp/src/Handler.cpp
+++ b/proton-c/bindings/cpp/src/Handler.cpp
@@ -24,10 +24,10 @@
 namespace proton {
 namespace reactor {
 
-Handler::Handler(){};
-Handler::~Handler(){};
+Handler::Handler() {}
+Handler::~Handler() {}
 
-void Handler::onUnhandled(Event &e){};
+void Handler::onUnhandled(Event &e) {}
 
 void Handler::addChildHandler(Handler &e) {
     childHandlers.push_back(&e);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/MessagingAdapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/MessagingAdapter.cpp b/proton-c/bindings/cpp/src/MessagingAdapter.cpp
index 625485e..f137397 100644
--- a/proton-c/bindings/cpp/src/MessagingAdapter.cpp
+++ b/proton-c/bindings/cpp/src/MessagingAdapter.cpp
@@ -35,10 +35,10 @@ namespace reactor {
 MessagingAdapter::MessagingAdapter(MessagingHandler &delegate_) :
     MessagingHandler(true, delegate_.prefetch, delegate_.autoSettle, delegate_.autoAccept, delegate_.peerCloseIsError),
     delegate(delegate_)
-{};
+{}
 
 
-MessagingAdapter::~MessagingAdapter(){};
+MessagingAdapter::~MessagingAdapter(){}
 
 
 void MessagingAdapter::onReactorInit(Event &e) {
@@ -126,7 +126,7 @@ void MessagingAdapter::onDelivery(Event &e) {
                     MessagingEvent mevent(PN_MESSAGING_ACCEPTED, *pe);
                     delegate.onAccepted(mevent);
                 }
-                else if (rstate = PN_REJECTED) {
+                else if (rstate == PN_REJECTED) {
                     MessagingEvent mevent(PN_MESSAGING_REJECTED, *pe);
                     delegate.onRejected(mevent);
                 }
@@ -164,10 +164,6 @@ bool isRemoteOpen(pn_state_t state) {
     return state & PN_REMOTE_ACTIVE;
 }
 
-bool isRemoteClosed(pn_state_t state) {
-    return state & PN_REMOTE_CLOSED;
-}
-
 } // namespace
 
 void MessagingAdapter::onLinkRemoteClose(Event &e) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/MessagingHandler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/MessagingHandler.cpp b/proton-c/bindings/cpp/src/MessagingHandler.cpp
index 925186a..6e3d2bd 100644
--- a/proton-c/bindings/cpp/src/MessagingHandler.cpp
+++ b/proton-c/bindings/cpp/src/MessagingHandler.cpp
@@ -83,7 +83,7 @@ void MessagingHandler::createHelpers() {
 MessagingHandler::~MessagingHandler(){
     delete flowController;
     delete messagingAdapter;
-};
+}
 
 void MessagingHandler::onAbort(Event &e) { onUnhandled(e); }
 void MessagingHandler::onAccepted(Event &e) { onUnhandled(e); }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Msg.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Msg.h b/proton-c/bindings/cpp/src/Msg.h
index cd8f9e8..2b4c6da 100644
--- a/proton-c/bindings/cpp/src/Msg.h
+++ b/proton-c/bindings/cpp/src/Msg.h
@@ -44,30 +44,10 @@ struct Msg {
     Msg(const Msg& m) : os(m.str()) {}
     std::string str() const { return os.str(); }
     operator std::string() const { return str(); }
-
-    Msg& operator<<(long n) { os << n; return *this; }
-    Msg& operator<<(unsigned long n) { os << n; return *this; }
-    Msg& operator<<(bool n) { os << n; return *this; }
-    Msg& operator<<(short n) { os << n; return *this; }
-    Msg& operator<<(unsigned short n) { os << n; return *this; }
-    Msg& operator<<(int n) { os << n; return *this; }
-    Msg& operator<<(unsigned int n) { os << n; return *this; }
-#ifdef _GLIBCXX_USE_LONG_LONG
-    Msg& operator<<(long long n) { os << n; return *this; }
-    Msg& operator<<(unsigned long long n) { os << n; return *this; }
-#endif
-    Msg& operator<<(double n) { os << n; return *this; }
-    Msg& operator<<(float n) { os << n; return *this; }
-    Msg& operator<<(long double n) { os << n; 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();
-}
+inline std::ostream& operator<<(std::ostream& o, const Msg& m) { return o << m.str(); }
 
 /** Construct a message using operator << and append (file:line) */
 #define QUOTE_(x) #x

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ProtonEvent.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ProtonEvent.cpp b/proton-c/bindings/cpp/src/ProtonEvent.cpp
index 16b92b6..0b0f1d0 100644
--- a/proton-c/bindings/cpp/src/ProtonEvent.cpp
+++ b/proton-c/bindings/cpp/src/ProtonEvent.cpp
@@ -70,11 +70,12 @@ Receiver ProtonEvent::getReceiver() {
 
 Link ProtonEvent::getLink() {
     pn_link_t *lnk = pn_event_link(getPnEvent());
-    if (lnk)
+    if (lnk) {
         if (pn_link_is_sender(lnk))
             return Sender(lnk);
         else
             return Receiver(lnk);
+    }
     throw ProtonException(MSG("No link context for this event"));
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/ProtonHandler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ProtonHandler.cpp b/proton-c/bindings/cpp/src/ProtonHandler.cpp
index 83d9087..f96f5a6 100644
--- a/proton-c/bindings/cpp/src/ProtonHandler.cpp
+++ b/proton-c/bindings/cpp/src/ProtonHandler.cpp
@@ -24,7 +24,7 @@
 namespace proton {
 namespace reactor {
 
-ProtonHandler::ProtonHandler(){};
+ProtonHandler::ProtonHandler(){}
 
 // Everything goes to onUnhandled() unless overriden by subclass
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 7f22b84..91eb8d9 100644
--- a/proton-c/bindings/cpp/src/Transport.cpp
+++ b/proton-c/bindings/cpp/src/Transport.cpp
@@ -27,7 +27,7 @@ namespace proton {
 namespace reactor {
 
 
-Transport::Transport() : connection(0), pnTransport(pn_transport()) {} ;
+Transport::Transport() : connection(0), pnTransport(pn_transport()) {}
 
 Transport::~Transport() { pn_decref(pnTransport); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 8e1e38c..b488481 100644
--- a/proton-c/bindings/cpp/src/Value.cpp
+++ b/proton-c/bindings/cpp/src/Value.cpp
@@ -21,21 +21,15 @@
 #include "proton_bits.h"
 #include <proton/codec.h>
 #include <ostream>
+#include <algorithm>
 
 namespace proton {
 namespace reactor {
 
-Values::Values() {}
-Values::Values(const Values& v) { *this = v; }
-Values::~Values() {}
-Values& Values::operator=(const Values& v) { Data::operator=(v); }
-
-void Values::rewind() { pn_data_rewind(data); }
-
-Value::Value() {}
+Value::Value() { *this = Null(); }
 Value::Value(const Value& v) { *this = v; }
 Value::~Value() {}
-Value& Value::operator=(const Value& v) { values = v.values; }
+Value& Value::operator=(const Value& v) { values = v.values; return *this; }
 
 TypeId Value::type() const {
     const_cast<Values&>(values).rewind();
@@ -50,22 +44,93 @@ template <class T> T check(T result) {
 }
 }
 
-Encoder& operator<<(Encoder& e, const Value& v) {
-    if (e.data == v.values.data) throw Encoder::Error("Values inserted into self");
-    pn_data_narrow(e.data);
-    int result = pn_data_appendn(e.data, v.values.data, 1);
-    pn_data_widen(e.data);
-    check(result);
-    return e;
+std::ostream& operator<<(std::ostream& o, const Value& v) {
+    return o << v.values;
+}
+
+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 compareNext(Values& a, Values& 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 compareContainer(Values& a, Values& b) {
+    Decoder::Scope sa(a), sb(b);
+    // Compare described vs. not-described.
+    int cmp = compare(sa.isDescribed, sb.isDescribed);
+    if (cmp) return cmp;
+    // Lexical sort (including descriptor if there is one)
+    size_t minSize = std::min(sa.size, sb.size) + int(sa.isDescribed);
+    for (size_t i = 0; i < minSize; ++i) {
+        cmp = compareNext(a, b);
+        if (cmp) return cmp;
+    }
+    return compare(sa.size, sb.size);
+}
+
+template <class T> int compareSimple(Values& a, Values& b) {
+    T va, vb;
+    a >> va;
+    b >> vb;
+    return compare(va, vb);
+}
+
+int compareNext(Values& a, Values& b) {
+    // Sort by TypeId first.
+    TypeId ta = a.type(), tb = b.type();
+    int cmp = compare(ta, tb);
+    if (cmp) return cmp;
+
+    switch (ta) {
+      case NULL_: return 0;
+      case ARRAY:
+      case LIST:
+      case MAP:
+      case DESCRIBED:
+        return compareContainer(a, b);
+      case BOOL: return compareSimple<Bool>(a, b);
+      case UBYTE: return compareSimple<Ubyte>(a, b);
+      case BYTE: return compareSimple<Byte>(a, b);
+      case USHORT: return compareSimple<Ushort>(a, b);
+      case SHORT: return compareSimple<Short>(a, b);
+      case UINT: return compareSimple<Uint>(a, b);
+      case INT: return compareSimple<Int>(a, b);
+      case CHAR: return compareSimple<Char>(a, b);
+      case ULONG: return compareSimple<Ulong>(a, b);
+      case LONG: return compareSimple<Long>(a, b);
+      case TIMESTAMP: return compareSimple<Timestamp>(a, b);
+      case FLOAT: return compareSimple<Float>(a, b);
+      case DOUBLE: return compareSimple<Double>(a, b);
+      case DECIMAL32: return compareSimple<Decimal32>(a, b);
+      case DECIMAL64: return compareSimple<Decimal64>(a, b);
+      case DECIMAL128: return compareSimple<Decimal128>(a, b);
+      case UUID: return compareSimple<Uuid>(a, b);
+      case BINARY: return compareSimple<Binary>(a, b);
+      case STRING: return compareSimple<String>(a, b);
+      case SYMBOL: return compareSimple<Symbol>(a, b);
+    }
+    // Invalid but equal TypeId, treat as equal.
+    return 0;
+}
+
+} // namespace
+
+bool Value::operator==(const Value& v) const {
+    values.rewind();
+    v.values.rewind();
+    return compareNext(values, v.values) == 0;
 }
 
-Decoder& operator>>(Decoder& e, Value& v) {
-    if (e.data == v.values.data) throw Decoder::Error("Values extracted from self");
-    pn_data_narrow(e.data);
-    int result = pn_data_appendn(e.data, v.values.data, 1);
-    pn_data_widen(e.data);
-    check(result);
-    return e;
+bool Value::operator<(const Value& v) const {
+    values.rewind();
+    v.values.rewind();
+    return compareNext(values, v.values) < 0;
 }
 
 }}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/Values.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/Values.cpp b/proton-c/bindings/cpp/src/Values.cpp
new file mode 100644
index 0000000..20fb9f1
--- /dev/null
+++ b/proton-c/bindings/cpp/src/Values.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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/cpp/Value.h"
+#include "proton_bits.h"
+#include <proton/codec.h>
+#include <ostream>
+
+namespace proton {
+namespace reactor {
+
+Values::Values() {}
+Values::Values(const Values& v) { *this = v; }
+Values::~Values() {}
+Values& Values::operator=(const Values& v) { Data::operator=(v); return *this; }
+
+Values& Values::rewind() { pn_data_rewind(data); return *this; }
+
+std::ostream& operator<<(std::ostream& o, const Values& v) {
+    return o << static_cast<const Encoder&>(v);
+}
+
+}}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 b344553..d7bef51 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -48,11 +48,7 @@ string read(string filename) {
     return string(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
 }
 
-template <class T> T get(Decoder& d) {
-    T value;
-    d >> exact(value);
-    return value;
-}
+template <class T> T get(Decoder& d) { return d.getAs<T, TypeIdOf<T>::value>(); }
 
 template <class T> std::string str(const T& value) {
     ostringstream oss;
@@ -129,7 +125,7 @@ int run_test(void (*testfn)(), const char* name) {
     return 1;
 }
 
-// FIXME aconway 2015-06-11: not testing all types.
+// TODO aconway 2015-06-11: interop test is not complete.
 
 #define RUN_TEST(T) run_test(&T, #T)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/proton_bits.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proton_bits.cpp b/proton-c/bindings/cpp/src/proton_bits.cpp
index 2e96430..10f7c59 100644
--- a/proton-c/bindings/cpp/src/proton_bits.cpp
+++ b/proton-c/bindings/cpp/src/proton_bits.cpp
@@ -39,6 +39,14 @@ std::string errorStr(int code) {
   }
 }
 
+std::string errorStr(pn_error_t* err, int code) {
+    if (err && pn_error_code(err)) {
+        const char* text = pn_error_text(err);
+        return text ? std::string(text) : errorStr(pn_error_code(err));
+    }
+    return errorStr(code);
+}
+
 std::ostream& operator<<(std::ostream& o, const Object& object) {
     pn_string_t* str = pn_string("");
     pn_inspect(object.value, str);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/cpp/src/proton_bits.h
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proton_bits.h b/proton-c/bindings/cpp/src/proton_bits.h
index a905172..e57f188 100644
--- a/proton-c/bindings/cpp/src/proton_bits.h
+++ b/proton-c/bindings/cpp/src/proton_bits.h
@@ -20,13 +20,18 @@
  */
 
 #include <iosfwd>
+#include <proton/error.h>
 
 /**@file
  *
  * Assorted internal proton utilities.
  */
+
 std::string errorStr(int code);
 
+/** Print the error string from pn_error_t, or from code if pn_error_t has no error. */
+std::string errorStr(pn_error_t*, int code=0);
+
 /** Wrapper for a proton object pointer. */
 struct Object { void* value; Object(void* o) : value(o) {} };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/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 127ee7d..4f2c6ac 100644
--- a/proton-c/bindings/cpp/src/types.cpp
+++ b/proton-c/bindings/cpp/src/types.cpp
@@ -19,32 +19,11 @@
 
 #include "proton/cpp/types.h"
 #include <proton/codec.h>
+#include <ostream>
 
 namespace proton {
 namespace reactor {
 
-const TypeId TypeIdOf<Null>::value = NULL_;
-const TypeId TypeIdOf<Bool>::value = BOOL;
-const TypeId TypeIdOf<Ubyte>::value = UBYTE;
-const TypeId TypeIdOf<Byte>::value = BYTE;
-const TypeId TypeIdOf<Ushort>::value = USHORT;
-const TypeId TypeIdOf<Short>::value = SHORT;
-const TypeId TypeIdOf<Uint>::value = UINT;
-const TypeId TypeIdOf<Int>::value = INT;
-const TypeId TypeIdOf<Char>::value = CHAR;
-const TypeId TypeIdOf<Ulong>::value = ULONG;
-const TypeId TypeIdOf<Long>::value = LONG;
-const TypeId TypeIdOf<Timestamp>::value = TIMESTAMP;
-const TypeId TypeIdOf<Float>::value = FLOAT;
-const TypeId TypeIdOf<Double>::value = DOUBLE;
-const TypeId TypeIdOf<Decimal32>::value = DECIMAL32;
-const TypeId TypeIdOf<Decimal64>::value = DECIMAL64;
-const TypeId TypeIdOf<Decimal128>::value = DECIMAL128;
-const TypeId TypeIdOf<Uuid>::value = UUID;
-const TypeId TypeIdOf<Binary>::value = BINARY;
-const TypeId TypeIdOf<String>::value = STRING;
-const TypeId TypeIdOf<Symbol>::value = SYMBOL;
-
 std::string typeName(TypeId t) {
     switch (t) {
       case NULL_: return "null";
@@ -76,7 +55,27 @@ std::string typeName(TypeId t) {
     }
 }
 
-std::string str(const pn_bytes_t& b) { return std::string(b.start, b.size); }
-pn_bytes_t bytes(const std::string& s) { pn_bytes_t b; b.start = &s[0]; b.size = s.size(); return b; }
+std::ostream& operator<<(std::ostream& o,TypeId t) { return o << typeName(t); }
+
+PN_CPP_EXTERN bool isContainer(TypeId t) {
+    return (t == LIST || t == MAP || t == ARRAY || t == DESCRIBED);
+}
+
+pn_bytes_t pn_bytes(const std::string& s) {
+    pn_bytes_t b = { s.size(), const_cast<char*>(&s[0]) };
+    return b;
+}
+
+pn_uuid_t pn_uuid(const std::string& s) {
+    pn_uuid_t u = {0};          // Zero initialized.
+    std::copy(s.begin(), s.begin() + std::max(s.size(), sizeof(pn_uuid_t::bytes)), &u.bytes[0]);
+    return u;
+}
+
+Start::Start(TypeId t, TypeId e, bool d, size_t s) : type(t), element(e), isDescribed(d), size(s) {}
+Start Start::array(TypeId 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_, true); }
 
 }}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/693752d3/proton-c/bindings/go/README.md
----------------------------------------------------------------------
diff --git a/proton-c/bindings/go/README.md b/proton-c/bindings/go/README.md
deleted file mode 100644
index 0d3a74e..0000000
--- a/proton-c/bindings/go/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# *EXPERIMENTAL* Go binding for proton
-
-Experimental work on the Go language binding has been moved to the `go1` branch
-until it is ready for use. You can `git checkout go1` on your git clone, or
-browse at https://github.com/apache/qpid-proton/blob/go1/proton-c/bindings/go/README.md


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