qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acon...@apache.org
Subject [3/4] qpid-proton git commit: PROTON-1085: c++: clean up access to message properties, instructions and annotations.
Date Tue, 29 Dec 2015 21:00:54 GMT
PROTON-1085: c++: clean up access to message properties, instructions and annotations.

- Use proton::value& as message::body() type.
- Create pn_message on demand for empty message.
- Use proton::scalar as basis for messsage_id and annotation_key
  - message_id restricted to be one of: uint64_t, amqp_uuid, amqp_binary or amqp_string.
  - annotation_key restricted to be on of: uint64_t or amqp_symbol.
- Decode and cache application properties, annotations and instructions on demand as std::map.
  - message::properties() returns std::map<std::string, scalar>&
  - message::instructions()/annotations() returns std::map<annotation_key, value>&


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

Branch: refs/heads/master
Commit: 1622d0e608738da7b603b7e497bc3a8166325865
Parents: d2c5a5f
Author: Alan Conway <aconway@redhat.com>
Authored: Fri Dec 18 09:33:58 2015 -0500
Committer: Alan Conway <aconway@redhat.com>
Committed: Tue Dec 29 15:56:44 2015 -0500

----------------------------------------------------------------------
 examples/cpp/client.cpp                         |   2 +-
 examples/cpp/example_test.py                    |  18 +-
 proton-c/CMakeLists.txt                         |   2 +-
 .../cpp/include/proton/annotation_key.hpp       |  58 +++++
 proton-c/bindings/cpp/include/proton/data.hpp   |   2 -
 .../bindings/cpp/include/proton/decoder.hpp     |  27 +--
 .../bindings/cpp/include/proton/encoder.hpp     |  26 +-
 proton-c/bindings/cpp/include/proton/error.hpp  |   6 +
 .../bindings/cpp/include/proton/message.hpp     |  81 +++----
 .../bindings/cpp/include/proton/message_id.hpp  |  67 ++---
 proton-c/bindings/cpp/include/proton/scalar.hpp | 117 +++++----
 proton-c/bindings/cpp/include/proton/ssl.hpp    |   2 +-
 .../bindings/cpp/include/proton/type_traits.hpp |   2 +-
 proton-c/bindings/cpp/include/proton/types.hpp  |  77 +++---
 proton-c/bindings/cpp/include/proton/value.hpp  |  16 +-
 proton-c/bindings/cpp/src/decoder.cpp           | 138 ++++++-----
 .../bindings/cpp/src/encode_decode_test.cpp     |  39 ++-
 proton-c/bindings/cpp/src/encoder.cpp           |  56 +++--
 proton-c/bindings/cpp/src/error.cpp             |   2 +
 proton-c/bindings/cpp/src/event.cpp             |   2 +-
 proton-c/bindings/cpp/src/message.cpp           | 242 ++++++++-----------
 proton-c/bindings/cpp/src/message_test.cpp      | 102 +++++---
 proton-c/bindings/cpp/src/scalar.cpp            |  97 +++++---
 proton-c/bindings/cpp/src/scalar_test.cpp       |  80 ++++--
 proton-c/bindings/cpp/src/types.cpp             |  20 +-
 proton-c/bindings/cpp/src/value.cpp             |  14 ++
 26 files changed, 751 insertions(+), 544 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/examples/cpp/client.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/client.cpp b/examples/cpp/client.cpp
index 4dee119..3f5c4ab 100644
--- a/examples/cpp/client.cpp
+++ b/examples/cpp/client.cpp
@@ -58,7 +58,7 @@ class client : public proton::messaging_handler {
     void on_message(proton::event &e) {
         if (requests.empty()) return; // Spurious extra message!
         proton::message& response = e.message();
-        std::cout << '"' << requests.front() << '"' << " => " << response.body() << std::endl;
+        std::cout << requests.front() << " => " << response.body() << std::endl;
         requests.erase(requests.begin());
         if (!requests.empty()) {
             send_request();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 1f800c0..c1e7ac5 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -125,17 +125,17 @@ class ExampleTest(unittest.TestCase):
     def test_helloworld(self):
         b = Broker.get()
         hw = execute("helloworld", b.addr)
-        self.assertEqual('"Hello World!"\n', hw)
+        self.assertEqual('Hello World!\n', hw)
 
     def test_helloworld_blocking(self):
         b = Broker.get()
         hw = execute("helloworld_blocking", b.addr)
-        self.assertEqual('"Hello World!"\n', hw)
+        self.assertEqual('Hello World!\n', hw)
 
     def test_helloworld_direct(self):
         addr = pick_addr()
         hw = execute("helloworld_direct", addr)
-        self.assertEqual('"Hello World!"\n', hw)
+        self.assertEqual('Hello World!\n', hw)
 
     def test_simple_send_recv(self):
         b = Broker.get()
@@ -165,10 +165,10 @@ class ExampleTest(unittest.TestCase):
         send_expect = "direct_send listening on amqp://%s\nall messages confirmed\n" % (addr)
         self.assertEqual(send_expect, verify(send))
 
-    CLIENT_EXPECT=""""Twas brillig, and the slithy toves" => "TWAS BRILLIG, AND THE SLITHY TOVES"
-"Did gire and gymble in the wabe." => "DID GIRE AND GYMBLE IN THE WABE."
-"All mimsy were the borogroves," => "ALL MIMSY WERE THE BOROGROVES,"
-"And the mome raths outgrabe." => "AND THE MOME RATHS OUTGRABE."
+    CLIENT_EXPECT="""Twas brillig, and the slithy toves => TWAS BRILLIG, AND THE SLITHY TOVES
+Did gire and gymble in the wabe. => DID GIRE AND GYMBLE IN THE WABE.
+All mimsy were the borogroves, => ALL MIMSY WERE THE BOROGROVES,
+And the mome raths outgrabe. => AND THE MOME RATHS OUTGRABE.
 """
     def test_simple_recv_send(self):
         # Start receiver first, then run sender"""
@@ -247,7 +247,7 @@ Tock...
     def test_ssl(self):
         # SSL without SASL
         expect="""Outgoing client connection connected via SSL.  Server certificate identity CN=test_server
-"Hello World!"
+Hello World!
 """
         addr = "amqps://" + pick_addr() + "/examples"
         ignore_first_line, ignore_nl, ssl_hw = execute("ssl", addr, ssl_certs_dir()).partition('\n')
@@ -257,7 +257,7 @@ Tock...
         # SSL with SASL EXTERNAL
         expect="""Inbound client certificate identity CN=test_client
 Outgoing client connection connected via SSL.  Server certificate identity CN=test_server
-"Hello World!"
+Hello World!
 """
         addr = "amqps://" + pick_addr() + "/examples"
         ignore_first_line, ignore_nl, ssl_hw = execute("ssl_client_cert", addr, ssl_certs_dir()).partition('\n')

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 3d2f457..b645563 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -246,7 +246,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
   if (ENABLE_WARNING_ERROR)
     set (WERROR "-Werror")
   endif (ENABLE_WARNING_ERROR)
-  set (CXX_WARNING_FLAGS "${WERROR} -pedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32")
+  set (CXX_WARNING_FLAGS "${WERROR} -pedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32 -Wno-documentation -Wno-documentation-unknown-command")
 endif()
 
 if (MSVC)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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
new file mode 100644
index 0000000..edd63b1
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
@@ -0,0 +1,58 @@
+#ifndef ANNOTATION_KEY_HPP
+#define ANNOTATION_KEY_HPP
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton/types.hpp"
+#include "proton/scalar.hpp"
+
+namespace proton {
+class encoder;
+class decoder;
+
+/** An annotation_key can contain one of the following types: uint64_t or amqp_symbol. */
+class annotation_key : public restricted_scalar {
+  public:
+    annotation_key() { scalar_ = uint64_t(0); }
+
+    ///@name Assign a C++ value, deduce the AMQP type()
+    ///@{
+    annotation_key& operator=(uint64_t x) { scalar_ = x; return *this; }
+    annotation_key& operator=(const amqp_symbol& x) { scalar_ = x; return *this; }
+    /// std::string is encoded as amqp_symbol
+    annotation_key& operator=(const std::string& x) { scalar_ = amqp_symbol(x); return *this; }
+    /// char* is encoded as amqp_symbol
+    annotation_key& operator=(const char *x) { scalar_ = amqp_symbol(x); return *this; }
+    ///@}
+
+    /// Converting constructor from any type that we can assign from.
+    template <class T> annotation_key(T x) { *this = x; }
+
+    void get(uint64_t& x) const { scalar_.get(x); }
+    void get(amqp_symbol& x) const { scalar_.get(x); }
+
+    template<class T> T get() const { T x; get(x); return x; }
+
+  friend PN_CPP_EXTERN encoder operator<<(encoder, const annotation_key&);
+  friend PN_CPP_EXTERN decoder operator>>(decoder, annotation_key&);
+  friend class message;
+};
+
+}
+#endif // ANNOTATION_KEY_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 37e1a61..7581ac7 100644
--- a/proton-c/bindings/cpp/include/proton/data.hpp
+++ b/proton-c/bindings/cpp/include/proton/data.hpp
@@ -39,8 +39,6 @@ class data;
 class data : public object<pn_data_t> {
   public:
     data(pn_data_t* d) : object<pn_data_t>(d) {}
-    data(const data& d) : object<pn_data_t>(d) {}
-    data& operator=(const data&);
 
     PN_CPP_EXTERN static data create();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 3073989..5dae3c3 100644
--- a/proton-c/bindings/cpp/include/proton/decoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/decoder.hpp
@@ -44,11 +44,11 @@ struct pn_data_t;
 
 namespace proton {
 
+class scalar;
 class data;
 class message_id;
-
-/** Raised by decoder operations on error.*/
-struct decode_error : public error { PN_CPP_EXTERN explicit decode_error(const std::string&); };
+class annotation_key;
+class value;
 
 /** Skips a value with `dec >> skip()`. */
 struct skip{};
@@ -208,7 +208,9 @@ class decoder : public object<pn_data_t> {
     PN_CPP_EXTERN friend decoder operator>>(decoder, amqp_uuid&);
     PN_CPP_EXTERN friend decoder operator>>(decoder, std::string&);
     PN_CPP_EXTERN friend decoder operator>>(decoder, message_id&);
+    PN_CPP_EXTERN friend decoder operator>>(decoder, annotation_key&);
     PN_CPP_EXTERN friend decoder operator>>(decoder, value&);
+    PN_CPP_EXTERN friend decoder operator>>(decoder, scalar&);
     ///@}
 
     /** Extract and return a value of type T. */
@@ -256,8 +258,6 @@ class decoder : public object<pn_data_t> {
 
   private:
     PN_CPP_EXTERN void check_type(type_id);
-
-  friend class encoder;
 };
 
 /** Call decoder::start() in constructor, decoder::finish in destructor().
@@ -280,20 +280,13 @@ operator>>(decoder d, T& i)  {
 }
 
 ///@cond INTERNAL
-template <class T> struct sequence_ref {
-    sequence_ref(T& v) : value(v) {}
-    T& value;
-};
-
-template <class T> struct map_ref {
-    map_ref(T& v) : value(v) {}
-    T& value;
-};
-
-template <class T> struct pairs_ref {
-    pairs_ref(T& v) : value(v) {}
+template <class T> struct ref {
+    ref(T& v) : value(v) {}
     T& value;
 };
+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
 
 /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 940064d..e521922 100644
--- a/proton-c/bindings/cpp/include/proton/encoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/encoder.hpp
@@ -44,11 +44,31 @@ struct pn_data_t;
 
 namespace proton {
 
+class scalar;
 class data;
 class message_id;
+class annotation_key;
+class value;
 
-/** Raised by encoder operations on error */
-struct encode_error : public error { PN_CPP_EXTERN explicit encode_error(const std::string&); };
+///@cond INTERNAL
+template<class T, type_id A> struct cref {
+    typedef T cpp_type;
+    static const type_id type;
+
+    cref(const T& v) : value(v) {}
+    const T& value;
+};
+template <class T, type_id A> const type_id cref<T, A>::type = A;
+///@endcond INTERNAL
+
+/**
+ * Indicate the desired AMQP type to use when encoding T.
+ * For example to encode a vector as a list:
+ *
+ *     std::vector<amqp_int> v;
+ *     encoder << as<LIST>(v);
+ */
+template <type_id A, class T> cref<T, A> as(const T& value) { return cref<T, A>(value); }
 
 /**
  * Stream-like encoder from C++ values to AMQP values.
@@ -139,7 +159,9 @@ class encoder : public object<pn_data_t> {
   friend PN_CPP_EXTERN encoder operator<<(encoder, amqp_symbol);
   friend PN_CPP_EXTERN encoder operator<<(encoder, amqp_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&);
     ///@}
 
     /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/include/proton/error.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/error.hpp b/proton-c/bindings/cpp/include/proton/error.hpp
index d2f57c6..f3475cf 100644
--- a/proton-c/bindings/cpp/include/proton/error.hpp
+++ b/proton-c/bindings/cpp/include/proton/error.hpp
@@ -34,6 +34,12 @@ struct error : public std::runtime_error { PN_CPP_EXTERN explicit error(const st
 /** Raised if timeout expires */
 struct timeout_error : public error { PN_CPP_EXTERN explicit timeout_error(const std::string&); };
 
+/** Raised if there is an error decoding AMQP data as a C++ value. */
+struct decode_error : public error { PN_CPP_EXTERN explicit decode_error(const std::string&); };
+
+/** Raised if there is an error encoding a C++ value as AMQP data. */
+struct encode_error : public error { PN_CPP_EXTERN explicit encode_error(const std::string&); };
+
 }
 
 #endif  /*!PROTON_CPP_EXCEPTIONS_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 52195aa..8bd1f85 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -22,9 +22,10 @@
  *
  */
 
-#include "proton/data.hpp"
 #include "proton/export.hpp"
 #include "proton/message_id.hpp"
+#include "proton/annotation_key.hpp"
+#include "proton/pn_unique_ptr.hpp"
 #include "proton/value.hpp"
 #include "proton/duration.hpp"
 
@@ -38,22 +39,28 @@ namespace proton {
 class link;
 class delivery;
 class message_id;
+class annotation_key;
 
 /** An AMQP message. Value semantics, can be copied or assigned to make a new message. */
 class message
 {
   public:
+    typedef std::map<std::string, scalar> property_map;
+    typedef std::map<annotation_key, value> annotation_map;
+
     PN_CPP_EXTERN message();
     PN_CPP_EXTERN message(const message&);
-    PN_CPP_EXTERN message(const value&);
-
 #if PN_HAS_CPP11
     PN_CPP_EXTERN message(message&&);
 #endif
+    /// Constructor that sets the body from any type that can be assigned to a value.
+    template <class T> explicit message(const T& body_) { body() = body_; }
+
     PN_CPP_EXTERN ~message();
+
     PN_CPP_EXTERN message& operator=(const message&);
 
-    void swap(message& x);
+    PN_CPP_EXTERN void swap(message& x);
 
     /** Clear the message content and properties. */
     PN_CPP_EXTERN void clear();
@@ -99,47 +106,28 @@ class message
 
     ///@}
 
-    /** Set the body. */
-    PN_CPP_EXTERN void body(const value&);
+    /** Set the body, equivalent to body() = v */
+    template<class T> void body(const T& v) { body() = v; }
 
-    /** Get the body. Note data can be copied to a proton::value */
-    PN_CPP_EXTERN const data body() const;
+    /** Get the body. */
+    PN_CPP_EXTERN const value& body() const;
 
-    /** Get a reference to the body data, can be modified in-place. */
-    PN_CPP_EXTERN data body();
+    /** Get a reference to the body that can be modified in-place. */
+    PN_CPP_EXTERN value& body();
 
-    /** Set the application properties. Must be a map with string keys or an
-     * empty value. You can assign to a proton::value from a standard C++ map
-     * of std::string to proton::value.
-     */
-    PN_CPP_EXTERN void properties(const value&);
+    /** Application properties map, can be modified in place. */
+    PN_CPP_EXTERN property_map& properties();
+    PN_CPP_EXTERN const property_map& properties() const;
 
-    /** Get the application properties, which will be a map with string keys or
-     * an empty value. You can assign proton::value containing a map to a
-     * standard C++ map of std::string to proton::value.
-     */
-    PN_CPP_EXTERN const data properties() const;
+    /** Message annotations map, can be modified in place. */
+    PN_CPP_EXTERN annotation_map& annotations();
+    PN_CPP_EXTERN const annotation_map& annotations() const;
 
-    /** Get a reference to the application properties, can be modified in-place.*/
-    PN_CPP_EXTERN data properties();
+    /** Delivery instructions map, can be modified in place. */
+    PN_CPP_EXTERN annotation_map& instructions();
+    PN_CPP_EXTERN const annotation_map& instructions() const;
 
-    /** Set an individual application property. */
-    PN_CPP_EXTERN void property(const std::string &name, const value &);
-
-    /** Get an individual application property. Returns an empty value if not found. */
-    PN_CPP_EXTERN value property(const std::string &name) const;
-
-    /** Erase an application property. Returns false if there was no such property. */
-    PN_CPP_EXTERN bool erase_property(const std::string &name);
-
-    PN_CPP_EXTERN void annotations(const value&);
-    PN_CPP_EXTERN const data annotations() const;
-    PN_CPP_EXTERN data annotations();
-    PN_CPP_EXTERN void annotation(const proton::amqp_symbol &key, const value &val);
-    PN_CPP_EXTERN value annotation(const proton::amqp_symbol &key) const;
-    PN_CPP_EXTERN bool erase_annotation(const proton::amqp_symbol &key);
-
-    /** Encode into a string, growing the string if necessary. */
+    /** Encode entire message into a string, growing the string if necessary. */
     PN_CPP_EXTERN void encode(std::string &bytes) const;
 
     /** Return encoded message as a string */
@@ -148,7 +136,7 @@ class message
     /** Decode from string data into the message. */
     PN_CPP_EXTERN void decode(const std::string &bytes);
 
-    /// Decode the message from link corresponding to delivery.
+    /** Decode the message corresponding to a delivery from a link. */
     PN_CPP_EXTERN void decode(proton::link, proton::delivery);
 
     /**
@@ -160,8 +148,6 @@ class message
      * and AMQP SEQUENCE sections, respectively. If inferred is false,
      * then all values in the body of the message will be encoded as AMQP
      * VALUE sections regardless of their type.
-     *
-     * @return the value of the inferred flag for the message
      */
     PN_CPP_EXTERN bool inferred() const;
     /** Get the inferred flag for a message. */
@@ -247,7 +233,16 @@ class message
     PN_CPP_EXTERN void sequence(int32_t);
 
   private:
-    pn_message_t *message_;
+    pn_message_t *pn_msg() const;
+    struct impl {
+        PN_CPP_EXTERN impl();
+        PN_CPP_EXTERN ~impl();
+        mutable pn_message_t *msg;
+        mutable value body;
+    } impl_;
+    mutable property_map properties_;
+    mutable annotation_map annotations_;
+    mutable annotation_map instructions_;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 4734dff..b08482f 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -20,63 +20,44 @@
  */
 
 #include "proton/types.hpp"
-#include "proton/value.hpp"
+#include "proton/scalar.hpp"
 
 namespace proton {
+class encoder;
+class decoder;
+
 /** A message_id can contain one of the following types:
- * uint64_t (aka amqp_ulong), amqp_uuid, amqp_binary or amqp_string.
+ * uint64_t, amqp_uuid, amqp_binary or amqp_string.
  */
-class message_id : public comparable<message_id> {
+class message_id : public restricted_scalar {
   public:
-    message_id() {}
-    message_id(const message_id& x) : value_(x.value_) {}
-    message_id(const uint64_t& x) : value_(x) {}
-    message_id(const amqp_uuid& x) : value_(x) {}
-    message_id(const amqp_binary& x) : value_(x) {}
-    message_id(const amqp_string& x) : value_(x) {}
-    /// string is encoded as amqp_string
-    message_id(const std::string& x) : value_(x) {}
-    message_id(const char *x) : value_(x) {}
+    message_id() { scalar_ = uint64_t(0); }
 
-    message_id& operator=(const message_id& x) { value_ = x.value_; return *this; }
-    message_id& operator=(const uint64_t& x) { value_ = x; return *this; }
-    message_id& operator=(const amqp_uuid& x) { value_ = x; return *this; }
-    message_id& operator=(const amqp_binary& x) { value_ = x; return *this; }
-    message_id& operator=(const amqp_string& x) { value_ = x; return *this; }
-    /// string is encoded as amqp_string
-    message_id& operator=(const std::string& x) { value_ = x; return *this; }
-    message_id& operator=(const char *x) { value_ = x; return *this; }
+    ///@name Assign a C++ value, deduce the AMQP type()
+    ///@{
+    message_id& operator=(uint64_t x) { scalar_ = x; return *this; }
+    message_id& operator=(const amqp_uuid& x) { scalar_ = x; return *this; }
+    message_id& operator=(const amqp_binary& x) { scalar_ = x; return *this; }
+    message_id& operator=(const amqp_string& x) { scalar_ = x; return *this; }
+    /// std::string is encoded as amqp_string
+    message_id& operator=(const std::string& x) { scalar_ = amqp_string(x); return *this; }
+    /// char* is encoded as amqp_string
+    message_id& operator=(const char *x) { scalar_ = amqp_string(x); return *this; }
+    ///@}
 
-    void clear() { value_.clear(); }
-    bool empty() const { return value_.empty(); }
-    type_id type() { return value_.type(); }
+    /// Converting constructor from any type that we can assign from.
+    template <class T> message_id(T x) { *this = x; }
 
-    void get(uint64_t& x) const { value_.get(x); }
-    void get(amqp_uuid& x) const { value_.get(x); }
-    void get(amqp_binary& x) const { value_.get(x); }
-    void get(amqp_string& x) const { value_.get(x); }
-    /// Both amqp_binary and amqp_string can be converted to std::string
-    void get(std::string& x) const { value_.get(x); }
+    void get(uint64_t& x) const { scalar_.get(x); }
+    void get(amqp_uuid& x) const { scalar_.get(x); }
+    void get(amqp_binary& x) const { scalar_.get(x); }
+    void get(amqp_string& x) const { scalar_.get(x); }
 
     template<class T> T get() const { T x; get(x); return x; }
 
-    // String representation: decimal representation of uint64_t, standard text
-    // representation of UUID, amqp_string or amqp_binary are returned without
-    // modification.
-    std::string& str() const;
-
-    bool operator==(const message_id& x) const { return value_ == x.value_; }
-    bool operator<(const message_id& x) const { return value_ < x.value_; }
-
-  friend std::ostream& operator<<(std::ostream&, const message_id&);
   friend PN_CPP_EXTERN encoder operator<<(encoder, const message_id&);
   friend PN_CPP_EXTERN decoder operator>>(decoder, message_id&);
-
-  private:
-    //message_id(const data d) : value_(d) {}
-    value value_;
   friend class message;
-  friend class data;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 0745281..6fe29fa 100644
--- a/proton-c/bindings/cpp/include/proton/scalar.hpp
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -21,54 +21,56 @@
 
 #include "proton/types.hpp"
 #include <iosfwd>
+#include <string>
 
 namespace proton {
 
-class scalar;
+class encoder;
+class decoder;
 
-/** scalar holds an instance of an atomic proton type. */
+/** scalar holds an instance of any scalar AMQP type. */
 class scalar : public comparable<scalar> {
   public:
     PN_CPP_EXTERN scalar();
-    // Use default assign and copy.
+    PN_CPP_EXTERN scalar(const scalar&);
+    PN_CPP_EXTERN scalar& operator=(const scalar&);
 
     /// Type for the value in the scalar, NULL_TYPE if empty()
     PN_CPP_EXTERN type_id type() const;
+
     /// True if the scalar is empty.
     PN_CPP_EXTERN bool empty() const;
 
-    ///@name Create an scalar, type() is deduced from the C++ type of the value.
+    ///@name Assign a C++ value, deduce the AMQP type()
     ///@{
-    PN_CPP_EXTERN explicit scalar(bool);
-    PN_CPP_EXTERN explicit scalar(uint8_t);
-    PN_CPP_EXTERN explicit scalar(int8_t);
-    PN_CPP_EXTERN explicit scalar(uint16_t);
-    PN_CPP_EXTERN explicit scalar(int16_t);
-    PN_CPP_EXTERN explicit scalar(uint32_t);
-    PN_CPP_EXTERN explicit scalar(int32_t);
-    PN_CPP_EXTERN explicit scalar(uint64_t);
-    PN_CPP_EXTERN explicit scalar(int64_t);
-    PN_CPP_EXTERN explicit scalar(wchar_t);
-    PN_CPP_EXTERN explicit scalar(float);
-    PN_CPP_EXTERN explicit scalar(double);
-    PN_CPP_EXTERN explicit scalar(amqp_timestamp);
-    PN_CPP_EXTERN explicit scalar(const amqp_decimal32&);
-    PN_CPP_EXTERN explicit scalar(const amqp_decimal64&);
-    PN_CPP_EXTERN explicit scalar(const amqp_decimal128&);
-    PN_CPP_EXTERN explicit scalar(const amqp_uuid&);
-    PN_CPP_EXTERN explicit scalar(const amqp_string&);
-    PN_CPP_EXTERN explicit scalar(const amqp_symbol&);
-    PN_CPP_EXTERN explicit scalar(const amqp_binary&);
-    PN_CPP_EXTERN explicit scalar(const std::string& s); ///< Treated as an AMQP string
-    PN_CPP_EXTERN explicit scalar(const char* s);        ///< Treated as an AMQP string
+    PN_CPP_EXTERN scalar& operator=(bool);
+    PN_CPP_EXTERN scalar& operator=(uint8_t);
+    PN_CPP_EXTERN scalar& operator=(int8_t);
+    PN_CPP_EXTERN scalar& operator=(uint16_t);
+    PN_CPP_EXTERN scalar& operator=(int16_t);
+    PN_CPP_EXTERN scalar& operator=(uint32_t);
+    PN_CPP_EXTERN scalar& operator=(int32_t);
+    PN_CPP_EXTERN scalar& operator=(uint64_t);
+    PN_CPP_EXTERN scalar& operator=(int64_t);
+    PN_CPP_EXTERN scalar& operator=(wchar_t);
+    PN_CPP_EXTERN scalar& operator=(float);
+    PN_CPP_EXTERN scalar& operator=(double);
+    PN_CPP_EXTERN scalar& operator=(amqp_timestamp);
+    PN_CPP_EXTERN scalar& operator=(const amqp_decimal32&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_decimal64&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_decimal128&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_uuid&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_string&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_symbol&);
+    PN_CPP_EXTERN scalar& operator=(const amqp_binary&);
+    PN_CPP_EXTERN scalar& operator=(const std::string& s); ///< Treated as an AMQP string
+    PN_CPP_EXTERN scalar& operator=(const char* s);        ///< Treated as an AMQP string
     ///@}
 
-    /// Assign to an scalar using the same rules as construction.
-    template <class T> scalar& operator=(T x) { return *this = scalar(x); }
+    /// Construct from any type that we can assign from.
+    template <class T> explicit scalar(T x) { *this = x; }
 
-    ///@name get(T&) extracts the value if the types match exactly,
-    ///i.e. if `type() == type_id_of<T>::value`
-    /// throws type_mismatch otherwise.
+    ///@name get(T&) extracts the value if the types match exactly, throws type_error otherwise.
     ///@{
     PN_CPP_EXTERN void get(bool&) const;
     PN_CPP_EXTERN void get(uint8_t&) const;
@@ -97,25 +99,58 @@ class scalar : public comparable<scalar> {
     template<class T> T get() const { T x; get(x); return x; }
 
     ///@name as_ methods do "loose" conversion, they will convert the scalar's
-    ///value to the requested type if possible, else throw type_mismatch
+    ///value to the requested type if possible, else throw type_error
     ///@{
-    PN_CPP_EXTERN int64_t as_int() const;     ///< Allowed if type_id_integral(type())
-    PN_CPP_EXTERN uint64_t as_uint() const;   ///< Allowed if type_id_integral(type())
-    PN_CPP_EXTERN double as_double() const;    ///< Allowed if type_id_floating_point(type())
-    PN_CPP_EXTERN std::string as_string() const; ///< Allowed if type_id_string_like(type())
+    PN_CPP_EXTERN int64_t as_int() const;     ///< Allowed if type_id_is_integral(type())
+    PN_CPP_EXTERN uint64_t as_uint() const;   ///< Allowed if type_id_is_integral(type())
+    PN_CPP_EXTERN double as_double() const;    ///< Allowed if type_id_is_floating_point(type())
+    PN_CPP_EXTERN std::string as_string() const; ///< Allowed if type_id_is_string_like(type())
     ///@}
 
-    PN_CPP_EXTERN bool operator==(const scalar& x) const;
-    /// Note if the values are of different type(), operator< will compare the type()
-    PN_CPP_EXTERN bool operator<(const scalar& x) const;
+  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&);
+
 
-  PN_CPP_EXTERN friend std::ostream& operator<<(std::ostream&, const scalar&);
+    /// Scalars with different type() are considered unequal even if the values
+    /// are equal as numbers or strings.
+  friend PN_CPP_EXTERN bool operator==(const scalar& x, const scalar& y);
+
+    /// For scalars of different type(), operator< sorts by order of type().
+  friend PN_CPP_EXTERN bool operator<(const scalar& x, const scalar& y);
 
   private:
     void ok(pn_type_t) const;
-    void set(const std::string&);
+    void set(const std::string&, pn_type_t);
+    void set(const pn_atom_t&);
     pn_atom_t atom_;
     std::string str_;           // Owner of string-like data.
+
+  friend class message;
+};
+
+///@internal base for restricted scalar types
+class restricted_scalar : public comparable<restricted_scalar> {
+  public:
+    operator scalar() const { return scalar_; }
+    type_id type() const { return scalar_.type(); }
+
+    ///@name as_ methods do "loose" conversion, they will convert the scalar's
+    ///value to the requested type if possible, else throw type_error
+    ///@{
+    int64_t as_int() const { return scalar_.as_int(); }
+    uint64_t as_uint() const { return scalar_.as_uint(); }
+    double as_double() const { return scalar_.as_double();  }
+    std::string as_string() const { return scalar_.as_string(); }
+    ///@}
+
+  friend std::ostream& operator<<(std::ostream& o, const restricted_scalar& x)  { return o << x.scalar_; }
+  friend bool operator<(const restricted_scalar& x, const restricted_scalar& y)  { return x.scalar_ < y.scalar_; }
+  friend bool operator==(const restricted_scalar& x, const restricted_scalar& y)  { return x.scalar_ == y.scalar_; }
+
+  protected:
+    restricted_scalar() {}
+    scalar scalar_;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/include/proton/ssl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/ssl.hpp b/proton-c/bindings/cpp/include/proton/ssl.hpp
index b3757dc..0518dc6 100644
--- a/proton-c/bindings/cpp/include/proton/ssl.hpp
+++ b/proton-c/bindings/cpp/include/proton/ssl.hpp
@@ -79,7 +79,7 @@ class ssl_domain {
   public:
     PN_CPP_EXTERN ssl_domain(const ssl_domain&);
     PN_CPP_EXTERN ssl_domain& operator=(const ssl_domain&);
-    ~ssl_domain();
+    PN_CPP_EXTERN ~ssl_domain();
 
   protected:
     ssl_domain(bool is_server);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 494f7db..8f502a3 100644
--- a/proton-c/bindings/cpp/include/proton/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/type_traits.hpp
@@ -76,7 +76,7 @@ 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 atomic C++ types
+// Metafunction returning AMQP type for scalar C++ types
 template <class T, class Enable=void> struct type_id_of;
 template<> struct type_id_of<amqp_null> { static const type_id value=NULL_TYPE; };
 template<> struct type_id_of<amqp_boolean> { static const type_id value=BOOLEAN; };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 645d9da..db5989b 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -67,12 +67,26 @@ enum type_id {
     MAP=PN_MAP                  ///< A sequence of key:value pairs, may be of mixed types.
 };
 
+/// Name of the AMQP type
+PN_CPP_EXTERN std::string type_name(type_id);
+
+/// Print the type_name
+PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, type_id);
+
 /// Raised when there is a type mismatch, with the expected and actual type ID.
-struct type_mismatch : public error {
-    PN_CPP_EXTERN explicit type_mismatch(type_id want, type_id got, const std::string& =std::string());
+struct type_error : public decode_error {
+    PN_CPP_EXTERN explicit type_error(type_id want, type_id got, const std::string& =std::string());
     type_id want; ///< Expected type_id
     type_id got;  ///< Actual type_id
 };
+ 
+
+///@cond INTERNAL
+/// Provide a full set of comparison operators for proton:: types that have < and ==.
+template <class T> bool operator>(const T &a, const T &b) { return b < a; }
+template <class T> bool operator<=(const T &a, const T &b) { return !(a > b); }
+template <class T> bool operator>=(const T &a, const T &b) { return !(a < b); }
+template <class T> bool operator!=(const T &a, const T &b) { return !(a == b); }
 
 PN_CPP_EXTERN pn_bytes_t pn_bytes(const std::string&);
 PN_CPP_EXTERN std::string str(const pn_bytes_t& b);
@@ -107,26 +121,23 @@ typedef double amqp_double;
 
 /// AMQP UTF-8 encoded string.
 struct amqp_string : public std::string {
-    amqp_string(const std::string& s=std::string()) : std::string(s) {}
-    amqp_string(const char* s) : std::string(s) {}
-    amqp_string(const pn_bytes_t& b) : std::string(b.start, b.size) {}
-    operator pn_bytes_t() const { return pn_bytes(*this); }
+    explicit amqp_string(const std::string& s=std::string()) : std::string(s) {}
+    explicit amqp_string(const char* s) : std::string(s) {}
+    explicit amqp_string(const pn_bytes_t& b) : std::string(b.start, b.size) {}
 };
 
 /// AMQP ASCII encoded symbolic name.
 struct amqp_symbol : public std::string {
-    amqp_symbol(const std::string& s=std::string()) : std::string(s) {}
-    amqp_symbol(const char* s) : std::string(s) {}
-    amqp_symbol(const pn_bytes_t& b) : std::string(b.start, b.size) {}
-    operator pn_bytes_t() const { return pn_bytes(*this); }
+    explicit amqp_symbol(const std::string& s=std::string()) : std::string(s) {}
+    explicit amqp_symbol(const char* s) : std::string(s) {}
+    explicit amqp_symbol(const pn_bytes_t& b) : std::string(b.start, b.size) {}
 };
 
 /// AMQP variable-length binary data.
 struct amqp_binary : public std::string {
-    amqp_binary(const std::string& s=std::string()) : std::string(s) {}
-    amqp_binary(const char* s) : std::string(s) {}
-    amqp_binary(const pn_bytes_t& b) : std::string(b.start, b.size) {}
-    operator pn_bytes_t() const { return pn_bytes(*this); }
+    explicit amqp_binary(const std::string& s=std::string()) : std::string(s) {}
+    explicit amqp_binary(const char* s) : std::string(s) {}
+    explicit amqp_binary(const pn_bytes_t& b) : std::string(b.start, b.size) {}
 };
 
 /// Template for opaque proton proton types that can be treated as byte arrays.
@@ -170,40 +181,28 @@ struct amqp_timestamp : public comparable<amqp_timestamp> {
 };
 PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const amqp_timestamp&);
 
-///@cond INTERNAL
-template<class T, type_id A> struct cref {
-    typedef T cpp_type;
-    static const type_id type;
-
-    cref(const T& v) : value(v) {}
-    const T& value;
-};
-template <class T, type_id A> const type_id cref<T, A>::type = A;
-///@endcond INTERNAL
-
-/**
- * Indicate the desired AMQP type to use when encoding T.
- * For example to encode a vector as a list:
- *
- *     std::vector<amqp_int> v;
- *     encoder << as<LIST>(v);
- */
-template <type_id A, class T> cref<T, A> as(const T& value) { return cref<T, A>(value); }
-
 // TODO aconway 2015-06-16: described types.
 
-/// Name of the AMQP type
-PN_CPP_EXTERN std::string type_name(type_id);
-
 ///@name Attributes of a type_id value, returns same result as the
 /// corresponding std::type_traits tests for the corresponding C++ types.
 ///@{
+/// Any scalar type
 PN_CPP_EXTERN bool type_id_is_scalar(type_id);
+/// One of the signed integer types: BYTE, SHORT, INT or LONG
+PN_CPP_EXTERN bool type_id_is_signed_int(type_id);
+/// One of the unsigned integer types: UBYTE, USHORT, UINT or ULONG
+PN_CPP_EXTERN bool type_id_is_unsigned_int(type_id);
+/// Any of the signed or unsigned integers, BOOL, CHAR or TIMESTAMP.
 PN_CPP_EXTERN bool type_id_is_integral(type_id);
-PN_CPP_EXTERN bool type_id_is_signed(type_id); ///< CHAR and BOOL are not signed.
+/// A floating point type, float or double
 PN_CPP_EXTERN bool type_id_is_floating_point(type_id);
+/// Any signed integer, float or double. BOOL, CHAR and TIMESTAMP are not signed.
+PN_CPP_EXTERN bool type_id_is_signed(type_id);
+/// Any DECIMAL type.
 PN_CPP_EXTERN bool type_id_is_decimal(type_id);
-PN_CPP_EXTERN bool type_id_is_string_like(type_id);   ///< STRING, SYMBOL, BINARY
+/// STRING, SYMBOL or BINARY
+PN_CPP_EXTERN bool type_id_is_string_like(type_id);
+/// Container types: MAP, LIST, ARRAY or DESCRIBED.
 PN_CPP_EXTERN bool type_id_is_container(type_id);
 ///@}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 c33eea1..dedcadd 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -43,9 +43,10 @@ class decoder;
 class value : public comparable<value> {
   public:
     PN_CPP_EXTERN value();
-    PN_CPP_EXTERN value(const value& x);
-    // TODO: Should enumerate specifically all the pointer types that can convert to value
-    // to avoid accidental conversions to bool this will require enable_if<> or the like
+    PN_CPP_EXTERN value(const value&);
+#if PN_HAS_CPP11
+    PN_CPP_EXTERN value(value&&);
+#endif
     template <class T> value(const T& x) : data_(data::create()) { data_.copy(x); }
 
     PN_CPP_EXTERN value& operator=(const value& x);
@@ -65,18 +66,27 @@ class value : public comparable<value> {
 
     /** Get the value. */
     template<class T> void get(T &t) const { decoder() >> t; }
+    template<class T> void get(map_ref<T> t) const { decoder() >> t; }
+    template<class T> void get(pairs_ref<T> t) const { decoder() >> t; }
+    template<class T> void get(sequence_ref<T> t) const { decoder() >> t; }
 
     /** Get the value. */
     template<class T> T get() const { T t; get(t); return t; }
 
+    // FIXME aconway 2015-12-28: friend ops.
     PN_CPP_EXTERN bool operator==(const value& x) const;
     PN_CPP_EXTERN bool operator<(const value& x) const;
 
+    PN_CPP_EXTERN void swap(value& v);
+
   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);
 
   private:
+    value(data d);
+    value& ref(data d);
+
     data data_;
   friend class message;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 20d0461..4639683 100644
--- a/proton-c/bindings/cpp/src/decoder.cpp
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -21,6 +21,7 @@
 #include "proton/decoder.hpp"
 #include "proton/value.hpp"
 #include "proton/message_id.hpp"
+#include "proton/annotation_key.hpp"
 #include "proton_bits.hpp"
 #include "msg.hpp"
 
@@ -34,8 +35,6 @@ namespace proton {
  * to be returned by the decoder.
  *
  */
-decode_error::decode_error(const std::string& msg) : error("decode: "+msg) {}
-
 namespace {
 struct save_state {
     pn_data_t* data;
@@ -87,8 +86,7 @@ data decoder::data() { return proton::data(pn_object()); }
 namespace {
 
 void bad_type(type_id want, type_id got) {
-    if (want != got)
-        throw decode_error("expected "+type_name(want)+" found "+type_name(got));
+    if (want != got) throw type_error(want, got);
 }
 
 type_id pre_get(pn_data_t* data) {
@@ -99,10 +97,10 @@ type_id pre_get(pn_data_t* data) {
 }
 
 // Simple extract with no type conversion.
-template <class T, class U> void extract(pn_data_t* data, T& value, U (*get)(pn_data_t*)) {
+template <class T, class U> void extract(pn_data_t* data, T& x, U (*get)(pn_data_t*)) {
     save_state ss(data);
     bad_type(type_id_of<T>::value, pre_get(data));
-    value = T(get(data));
+    x = T(get(data));
     ss.cancel();                // No error, no rewind
 }
 
@@ -165,191 +163,211 @@ decoder operator>>(decoder d, value& v) {
     return d;
 }
 
-decoder operator>>(decoder d, message_id& id) {
+decoder operator>>(decoder d, message_id& x) {
     switch (d.type()) {
       case ULONG:
       case UUID:
       case BINARY:
       case STRING:
-        return d >> id.value_;
+        return d >> x.scalar_;
       default:
         throw decode_error("expected one of ulong, uuid, binary or string but found " +
                            type_name(d.type()));
     };
 }
 
+decoder operator>>(decoder d, annotation_key& x) {
+    switch (d.type()) {
+      case ULONG:
+      case SYMBOL:
+        return d >> x.scalar_;
+      default:
+        throw decode_error("expected one of ulong or symbol but found " + type_name(d.type()));
+    };
+}
+
 decoder operator>>(decoder d, amqp_null) {
     save_state ss(d.pn_object());
     bad_type(NULL_TYPE, pre_get(d.pn_object()));
     return d;
 }
 
-decoder operator>>(decoder d, amqp_boolean& value) {
-    extract(d.pn_object(), value, pn_data_get_bool);
+decoder operator>>(decoder d, scalar& x) {
+    save_state ss(d.pn_object());
+    type_id got = pre_get(d.pn_object());
+    if (!type_id_is_scalar(got))
+        throw decode_error("expected scalar, found "+type_name(got));
+    x.set(pn_data_get_atom(d.pn_object()));
+    ss.cancel();                // No error, no rewind
+    return d;
+}
+
+decoder operator>>(decoder d, amqp_boolean &x) {
+    extract(d.pn_object(), x, pn_data_get_bool);
     return d;
 }
 
-decoder operator>>(decoder d0, amqp_ubyte& value) {
+decoder operator>>(decoder d0, amqp_ubyte &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
+      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;
 }
 
-decoder operator>>(decoder d0, amqp_byte& value) {
+decoder operator>>(decoder d0, amqp_byte &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
+      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;
 }
 
-decoder operator>>(decoder d0, amqp_ushort& value) {
+decoder operator>>(decoder d0, amqp_ushort &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
-      case USHORT: value = pn_data_get_ushort(d); break;
+      case UBYTE: x = pn_data_get_ubyte(d); break;
+      case USHORT: x = pn_data_get_ushort(d); break;
       default: bad_type(USHORT, type_id(type_id(pn_data_type(d))));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_short& value) {
+decoder operator>>(decoder d0, amqp_short &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
-      case SHORT: value = pn_data_get_short(d); break;
+      case BYTE: x = pn_data_get_byte(d); break;
+      case SHORT: x = pn_data_get_short(d); break;
       default: bad_type(SHORT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_uint& value) {
+decoder operator>>(decoder d0, amqp_uint &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
-      case USHORT: value = pn_data_get_ushort(d); break;
-      case UINT: value = pn_data_get_uint(d); break;
+      case UBYTE: x = pn_data_get_ubyte(d); break;
+      case USHORT: x = pn_data_get_ushort(d); break;
+      case UINT: x = pn_data_get_uint(d); break;
       default: bad_type(UINT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_int& value) {
+decoder operator>>(decoder d0, amqp_int &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
-      case SHORT: value = pn_data_get_short(d); break;
-      case INT: value = pn_data_get_int(d); break;
+      case BYTE: x = pn_data_get_byte(d); break;
+      case SHORT: x = pn_data_get_short(d); break;
+      case INT: x = pn_data_get_int(d); break;
       default: bad_type(INT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_ulong& value) {
+decoder operator>>(decoder d0, amqp_ulong &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case UBYTE: value = pn_data_get_ubyte(d); break;
-      case USHORT: value = pn_data_get_ushort(d); break;
-      case UINT: value = pn_data_get_uint(d); break;
-      case ULONG: value = pn_data_get_ulong(d); break;
+      case UBYTE: x = pn_data_get_ubyte(d); break;
+      case USHORT: x = pn_data_get_ushort(d); break;
+      case UINT: x = pn_data_get_uint(d); break;
+      case ULONG: x = pn_data_get_ulong(d); break;
       default: bad_type(ULONG, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_long& value) {
+decoder operator>>(decoder d0, amqp_long &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case BYTE: value = pn_data_get_byte(d); break;
-      case SHORT: value = pn_data_get_short(d); break;
-      case INT: value = pn_data_get_int(d); break;
-      case LONG: value = pn_data_get_long(d); break;
+      case BYTE: x = pn_data_get_byte(d); break;
+      case SHORT: x = pn_data_get_short(d); break;
+      case INT: x = pn_data_get_int(d); break;
+      case LONG: x = pn_data_get_long(d); break;
       default: bad_type(LONG, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d, amqp_char& value) {
-    extract(d.pn_object(), value, pn_data_get_char);
+decoder operator>>(decoder d, amqp_char &x) {
+    extract(d.pn_object(), x, pn_data_get_char);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_timestamp& value) {
-    extract(d.pn_object(), value, pn_data_get_timestamp);
+decoder operator>>(decoder d, amqp_timestamp &x) {
+    extract(d.pn_object(), x, pn_data_get_timestamp);
     return d;
 }
 
-decoder operator>>(decoder d0, amqp_float& value) {
+decoder operator>>(decoder d0, amqp_float &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case FLOAT: value = pn_data_get_float(d); break;
-      case DOUBLE: value = float(pn_data_get_double(d)); break;
+      case FLOAT: x = pn_data_get_float(d); break;
+      case DOUBLE: x = float(pn_data_get_double(d)); break;
       default: bad_type(FLOAT, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d0, amqp_double& value) {
+decoder operator>>(decoder d0, amqp_double &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case FLOAT: value = pn_data_get_float(d); break;
-      case DOUBLE: value = pn_data_get_double(d); break;
+      case FLOAT: x = pn_data_get_float(d); break;
+      case DOUBLE: x = pn_data_get_double(d); break;
       default: bad_type(DOUBLE, type_id(pn_data_type(d)));
     }
     ss.cancel();
     return d0;
 }
 
-decoder operator>>(decoder d, amqp_decimal32& value) {
-    extract(d.pn_object(), value, pn_data_get_decimal32);
+decoder operator>>(decoder d, amqp_decimal32 &x) {
+    extract(d.pn_object(), x, pn_data_get_decimal32);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_decimal64& value) {
-    extract(d.pn_object(), value, pn_data_get_decimal64);
+decoder operator>>(decoder d, amqp_decimal64 &x) {
+    extract(d.pn_object(), x, pn_data_get_decimal64);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_decimal128& value)  {
-    extract(d.pn_object(), value, pn_data_get_decimal128);
+decoder operator>>(decoder d, amqp_decimal128 &x)  {
+    extract(d.pn_object(), x, pn_data_get_decimal128);
     return d;
 }
 
-decoder operator>>(decoder d, amqp_uuid& value)  {
-    extract(d.pn_object(), value, pn_data_get_uuid);
+decoder operator>>(decoder d, amqp_uuid &x)  {
+    extract(d.pn_object(), x, pn_data_get_uuid);
     return d;
 }
 
-decoder operator>>(decoder d0, std::string& value) {
+decoder operator>>(decoder d0, std::string &x) {
     pn_data_t* d = d0.pn_object();
     save_state ss(d);
     switch (pre_get(d)) {
-      case STRING: value = str(pn_data_get_string(d)); break;
-      case BINARY: value = str(pn_data_get_binary(d)); break;
-      case SYMBOL: value = str(pn_data_get_symbol(d)); break;
+      case STRING: x = str(pn_data_get_string(d)); break;
+      case BINARY: x = str(pn_data_get_binary(d)); break;
+      case SYMBOL: x = str(pn_data_get_symbol(d)); break;
       default: bad_type(STRING, type_id(pn_data_type(d)));
     }
     ss.cancel();

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/encode_decode_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/encode_decode_test.cpp b/proton-c/bindings/cpp/src/encode_decode_test.cpp
index 3e15a58..8c285ac 100644
--- a/proton-c/bindings/cpp/src/encode_decode_test.cpp
+++ b/proton-c/bindings/cpp/src/encode_decode_test.cpp
@@ -48,31 +48,13 @@ template <class T> void value_test(T x, type_id tid, const std::string& s, T y)
     ASSERT(y > x);
 }
 
-void value_tests() {
-    value_test(false, BOOLEAN, "false", true);
-    value_test(amqp_ubyte(42), UBYTE, "42", amqp_ubyte(50));
-    value_test(amqp_byte(-42), BYTE, "-42", amqp_byte(-40));
-    value_test(amqp_ushort(4242), USHORT, "4242", amqp_ushort(5252));
-    value_test(amqp_short(-4242), SHORT, "-4242", amqp_short(3));
-    value_test(amqp_uint(4242), UINT, "4242", amqp_uint(5252));
-    value_test(amqp_int(-4242), INT, "-4242", amqp_int(3));
-    value_test(amqp_ulong(4242), ULONG, "4242", amqp_ulong(5252));
-    value_test(amqp_long(-4242), LONG, "-4242", amqp_long(3));
-    value_test(amqp_float(1.234), FLOAT, "1.234", amqp_float(2.345));
-    value_test(amqp_double(11.2233), DOUBLE, "11.2233", amqp_double(12));
-    value_test(amqp_string("aaa"), STRING, "aaa", amqp_string("aaaa"));
-    value_test(std::string("xxx"), STRING, "xxx", std::string("yyy"));
-    value_test(amqp_symbol("aaa"), SYMBOL, "aaa", amqp_symbol("aaaa"));
-    value_test(amqp_binary("aaa"), BINARY, "b\"aaa\"", amqp_binary("aaaa"));
-}
-
 // Map values
 void map_test() {
     std::map<string, int> m;
     m["a"] = 1;
     m["b"] = 2;
     m["c"] = 3;
-    proton::value v = m;
+    value v = m;
     ASSERT_EQUAL("{\"a\"=1, \"b\"=2, \"c\"=3}",  str(v));
     std::map<value, value> mv;
     v.get(mv);
@@ -81,8 +63,9 @@ void map_test() {
     mv.erase("c");
     v = value(mv);
     ASSERT_EQUAL("{\"a\"=1, \"b\"=b\"xyz\"}",  str(v));
+
     std::vector<std::pair<string, value> > vec;
-    v.decoder() >> to_pairs(vec);       // FIXME aconway 2015-11-17: get doesn't work with pairs.
+    v.get(to_pairs(vec));
     ASSERT_EQUAL(2, vec.size());
     ASSERT_EQUAL(std::make_pair(std::string("a"), value(1)), vec[0]);
     ASSERT_EQUAL(std::make_pair(std::string("b"), value(amqp_binary("xyz"))), vec[1]);
@@ -90,7 +73,21 @@ void map_test() {
 
 int main(int, char**) {
     int failed = 0;
+    RUN_TEST(failed, value_test(false, BOOLEAN, "false", true));
+    RUN_TEST(failed, value_test(amqp_ubyte(42), UBYTE, "42", amqp_ubyte(50)));
+    RUN_TEST(failed, value_test(amqp_byte(-42), BYTE, "-42", amqp_byte(-40)));
+    RUN_TEST(failed, value_test(amqp_ushort(4242), USHORT, "4242", amqp_ushort(5252)));
+    RUN_TEST(failed, value_test(amqp_short(-4242), SHORT, "-4242", amqp_short(3)));
+    RUN_TEST(failed, value_test(amqp_uint(4242), UINT, "4242", amqp_uint(5252)));
+    RUN_TEST(failed, value_test(amqp_int(-4242), INT, "-4242", amqp_int(3)));
+    RUN_TEST(failed, value_test(amqp_ulong(4242), ULONG, "4242", amqp_ulong(5252)));
+    RUN_TEST(failed, value_test(amqp_long(-4242), LONG, "-4242", amqp_long(3)));
+    RUN_TEST(failed, value_test(amqp_float(1.234), FLOAT, "1.234", amqp_float(2.345)));
+    RUN_TEST(failed, value_test(amqp_double(11.2233), DOUBLE, "11.2233", amqp_double(12)));
+    RUN_TEST(failed, value_test(amqp_string("aaa"), STRING, "aaa", amqp_string("aaaa")));
+    RUN_TEST(failed, value_test(std::string("xxx"), STRING, "xxx", std::string("yyy")));
+    RUN_TEST(failed, value_test(amqp_symbol("aaa"), SYMBOL, "aaa", amqp_symbol("aaaa")));
+    RUN_TEST(failed, value_test(amqp_binary("aaa"), BINARY, "b\"aaa\"", amqp_binary("aaaa")));
     RUN_TEST(failed, map_test());
-    RUN_TEST(failed, value_tests());
     return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 327426a..109b290 100644
--- a/proton-c/bindings/cpp/src/encoder.cpp
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -20,6 +20,7 @@
 #include "proton/data.hpp"
 #include "proton/encoder.hpp"
 #include "proton/message_id.hpp"
+#include "proton/annotation_key.hpp"
 #include "proton/value.hpp"
 
 #include "proton_bits.hpp"
@@ -100,35 +101,39 @@ encoder operator<<(encoder e, finish) {
 
 namespace {
 template <class T, class U>
-encoder insert(encoder e, pn_data_t* data, T& value, int (*put)(pn_data_t*, U)) {
+encoder insert(encoder e, pn_data_t* data, T& x, int (*put)(pn_data_t*, U)) {
     save_state ss(data);         // Save state in case of error.
-    check(put(data, value), data);
+    check(put(data, x), data);
     ss.cancel();                // Don't restore state, all is good.
     return e;
 }
+
+int pn_data_put_amqp_string(pn_data_t *d, const amqp_string& x) { return pn_data_put_string(d, pn_bytes(x)); }
+int pn_data_put_amqp_binary(pn_data_t *d, const amqp_binary& x) { return pn_data_put_binary(d, pn_bytes(x)); }
+int pn_data_put_amqp_symbol(pn_data_t *d, const amqp_symbol& x) { return pn_data_put_symbol(d, pn_bytes(x)); }
 }
 
 encoder operator<<(encoder e, amqp_null) { pn_data_put_null(e.pn_object()); return e; }
-encoder operator<<(encoder e, amqp_boolean value) { return insert(e, e.pn_object(), value, pn_data_put_bool); }
-encoder operator<<(encoder e, amqp_ubyte value) { return insert(e, e.pn_object(), value, pn_data_put_ubyte); }
-encoder operator<<(encoder e, amqp_byte value) { return insert(e, e.pn_object(), value, pn_data_put_byte); }
-encoder operator<<(encoder e, amqp_ushort value) { return insert(e, e.pn_object(), value, pn_data_put_ushort); }
-encoder operator<<(encoder e, amqp_short value) { return insert(e, e.pn_object(), value, pn_data_put_short); }
-encoder operator<<(encoder e, amqp_uint value) { return insert(e, e.pn_object(), value, pn_data_put_uint); }
-encoder operator<<(encoder e, amqp_int value) { return insert(e, e.pn_object(), value, pn_data_put_int); }
-encoder operator<<(encoder e, amqp_char value) { return insert(e, e.pn_object(), value, pn_data_put_char); }
-encoder operator<<(encoder e, amqp_ulong value) { return insert(e, e.pn_object(), value, pn_data_put_ulong); }
-encoder operator<<(encoder e, amqp_long value) { return insert(e, e.pn_object(), value, pn_data_put_long); }
-encoder operator<<(encoder e, amqp_timestamp value) { return insert(e, e.pn_object(), value, pn_data_put_timestamp); }
-encoder operator<<(encoder e, amqp_float value) { return insert(e, e.pn_object(), value, pn_data_put_float); }
-encoder operator<<(encoder e, amqp_double value) { return insert(e, e.pn_object(), value, pn_data_put_double); }
-encoder operator<<(encoder e, amqp_decimal32 value) { return insert(e, e.pn_object(), value, pn_data_put_decimal32); }
-encoder operator<<(encoder e, amqp_decimal64 value) { return insert(e, e.pn_object(), value, pn_data_put_decimal64); }
-encoder operator<<(encoder e, amqp_decimal128 value) { return insert(e, e.pn_object(), value, pn_data_put_decimal128); }
-encoder operator<<(encoder e, amqp_uuid value) { return insert(e, e.pn_object(), value, pn_data_put_uuid); }
-encoder operator<<(encoder e, amqp_string value) { return insert(e, e.pn_object(), value, pn_data_put_string); }
-encoder operator<<(encoder e, amqp_symbol value) { return insert(e, e.pn_object(), value, pn_data_put_symbol); }
-encoder operator<<(encoder e, amqp_binary value) { return insert(e, e.pn_object(), value, pn_data_put_binary); }
+encoder operator<<(encoder e, amqp_boolean x) { return insert(e, e.pn_object(), x, pn_data_put_bool); }
+encoder operator<<(encoder e, amqp_ubyte x) { return insert(e, e.pn_object(), x, pn_data_put_ubyte); }
+encoder operator<<(encoder e, amqp_byte x) { return insert(e, e.pn_object(), x, pn_data_put_byte); }
+encoder operator<<(encoder e, amqp_ushort x) { return insert(e, e.pn_object(), x, pn_data_put_ushort); }
+encoder operator<<(encoder e, amqp_short x) { return insert(e, e.pn_object(), x, pn_data_put_short); }
+encoder operator<<(encoder e, amqp_uint x) { return insert(e, e.pn_object(), x, pn_data_put_uint); }
+encoder operator<<(encoder e, amqp_int x) { return insert(e, e.pn_object(), x, pn_data_put_int); }
+encoder operator<<(encoder e, amqp_char x) { return insert(e, e.pn_object(), x, pn_data_put_char); }
+encoder operator<<(encoder e, amqp_ulong x) { return insert(e, e.pn_object(), x, pn_data_put_ulong); }
+encoder operator<<(encoder e, amqp_long x) { return insert(e, e.pn_object(), x, pn_data_put_long); }
+encoder operator<<(encoder e, amqp_timestamp x) { return insert(e, e.pn_object(), x, pn_data_put_timestamp); }
+encoder operator<<(encoder e, amqp_float x) { return insert(e, e.pn_object(), x, pn_data_put_float); }
+encoder operator<<(encoder e, amqp_double x) { return insert(e, e.pn_object(), x, pn_data_put_double); }
+encoder operator<<(encoder e, amqp_decimal32 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal32); }
+encoder operator<<(encoder e, amqp_decimal64 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal64); }
+encoder operator<<(encoder e, amqp_decimal128 x) { return insert(e, e.pn_object(), x, pn_data_put_decimal128); }
+encoder operator<<(encoder e, amqp_uuid x) { return insert(e, e.pn_object(), x, pn_data_put_uuid); }
+encoder operator<<(encoder e, amqp_string x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_string); }
+encoder operator<<(encoder e, amqp_symbol x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_symbol); }
+encoder operator<<(encoder e, amqp_binary x) { return insert(e, e.pn_object(), x, pn_data_put_amqp_binary); }
 
 encoder operator<<(encoder e, const value& v) {
     data edata = e.data();
@@ -138,6 +143,11 @@ encoder operator<<(encoder e, const value& v) {
     return e;
 }
 
-encoder operator<<(encoder e, const message_id& v) { return e << v.value_; }
+encoder operator<<(encoder e, const scalar& x) {
+    return insert(e, e.pn_object(), x.atom_, pn_data_put_atom);
+}
+
+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/1622d0e6/proton-c/bindings/cpp/src/error.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/error.cpp b/proton-c/bindings/cpp/src/error.cpp
index 980d6c0..8382a70 100644
--- a/proton-c/bindings/cpp/src/error.cpp
+++ b/proton-c/bindings/cpp/src/error.cpp
@@ -27,4 +27,6 @@ error::error(const std::string& msg) : std::runtime_error(prefix+msg) {}
 
 timeout_error::timeout_error(const std::string& msg) : error(msg) {}
 
+decode_error::decode_error(const std::string& msg) : error("decode: "+msg) {}
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/event.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/event.cpp b/proton-c/bindings/cpp/src/event.cpp
index 2a35ee8..b3e93d8 100644
--- a/proton-c/bindings/cpp/src/event.cpp
+++ b/proton-c/bindings/cpp/src/event.cpp
@@ -77,5 +77,5 @@ class message &event::message() const {
     throw error(MSG("No message associated with event"));
 }
 
-event_loop::~event_loop() {}    // FIXME aconway 2015-12-28: move
+event_loop::~event_loop() {}
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/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 c2fcd00..c7ee1f6 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "proton/data.hpp"
 #include "proton/message.hpp"
 #include "proton/error.hpp"
 #include "proton/link.hpp"
@@ -31,24 +32,39 @@
 #include "msg.hpp"
 #include "proton_bits.hpp"
 
-#include <cstring>
+#include <string>
 #include <assert.h>
 
 namespace proton {
 
-message::message() : message_(::pn_message()) {}
+// impl exists so body is pre-constructed in reference mode (prevent it creating its own data)
+// for all message ctors.
+message::impl::impl() : msg(0), body(0) {}
 
-message::message(const message &m) : message_(::pn_message()) { *this = m; }
+message::impl::~impl() {
+    if (msg) {
+        body.ref(0);            // Clear the reference.
+        pn_message_free(msg);
+    }
+}
 
-#if defined(PN_HAS_CPP11) && PN_HAS_CPP11
-message::message(message &&m) : message_(::pn_message()) { swap(m); }
-#endif
+// Lazy construct the message.
+pn_message_t* message::pn_msg() const {
+    if (!impl_.msg) impl_.msg = pn_message();
+    return impl_.msg;
+}
+
+message::message() {}
+
+message::message(const message &m) { *this = m; }
 
-message::message(const value& v) : message_(::pn_message()) { body(v); }
+#if PN_HAS_CPP11
+message::message(message &&m) { swap(m); }
+#endif
 
-message::~message() { ::pn_message_free(message_); }
+message::~message() {}
 
-void message::swap(message& m) { std::swap(message_, m.message_); }
+void message::swap(message& m) { std::swap(impl_.msg, m.impl_.msg); }
 
 message& message::operator=(const message& m) {
     // TODO aconway 2015-08-10: more efficient pn_message_copy function
@@ -58,7 +74,7 @@ message& message::operator=(const message& m) {
     return *this;
 }
 
-void message::clear() { pn_message_clear(message_); }
+void message::clear() { if (impl_.msg) pn_message_clear(impl_.msg); }
 
 namespace {
 void check(int err) {
@@ -66,7 +82,7 @@ void check(int err) {
 }
 } // namespace
 
-void message::id(const message_id& id) { data(pn_message_id(message_)).copy(id.value_); }
+void message::id(const message_id& id) { pn_message_set_id(pn_msg(), id.scalar_.atom_); }
 
 namespace {
 inline message_id from_pn_atom(const pn_atom_t& v) {
@@ -86,222 +102,169 @@ inline message_id from_pn_atom(const pn_atom_t& v) {
 }
 
 message_id message::id() const {
-    return from_pn_atom(pn_message_get_id(message_));
+    return from_pn_atom(pn_message_get_id(pn_msg()));
 }
 
 void message::user_id(const std::string &id) {
-    check(pn_message_set_user_id(message_, pn_bytes(id)));
+    check(pn_message_set_user_id(pn_msg(), pn_bytes(id)));
 }
 
 std::string message::user_id() const {
-    return str(pn_message_get_user_id(message_));
+    return str(pn_message_get_user_id(pn_msg()));
 }
 
 void message::address(const std::string &addr) {
-    check(pn_message_set_address(message_, addr.c_str()));
+    check(pn_message_set_address(pn_msg(), addr.c_str()));
 }
 
 std::string message::address() const {
-    const char* addr = pn_message_get_address(message_);
+    const char* addr = pn_message_get_address(pn_msg());
     return addr ? std::string(addr) : std::string();
 }
 
 void message::subject(const std::string &s) {
-    check(pn_message_set_subject(message_, s.c_str()));
+    check(pn_message_set_subject(pn_msg(), s.c_str()));
 }
 
 std::string message::subject() const {
-    const char* s = pn_message_get_subject(message_);
+    const char* s = pn_message_get_subject(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::reply_to(const std::string &s) {
-    check(pn_message_set_reply_to(message_, s.c_str()));
+    check(pn_message_set_reply_to(pn_msg(), s.c_str()));
 }
 
 std::string message::reply_to() const {
-    const char* s = pn_message_get_reply_to(message_);
+    const char* s = pn_message_get_reply_to(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::correlation_id(const message_id& id) {
-    data(pn_message_correlation_id(message_)).copy(id.value_);
+    data(pn_message_correlation_id(pn_msg())).copy(id.scalar_);
 }
 
 message_id message::correlation_id() const {
-    return from_pn_atom(pn_message_get_correlation_id(message_));
+    return from_pn_atom(pn_message_get_correlation_id(pn_msg()));
 }
 
 void message::content_type(const std::string &s) {
-    check(pn_message_set_content_type(message_, s.c_str()));
+    check(pn_message_set_content_type(pn_msg(), s.c_str()));
 }
 
 std::string message::content_type() const {
-    const char* s = pn_message_get_content_type(message_);
+    const char* s = pn_message_get_content_type(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::content_encoding(const std::string &s) {
-    check(pn_message_set_content_encoding(message_, s.c_str()));
+    check(pn_message_set_content_encoding(pn_msg(), s.c_str()));
 }
 
 std::string message::content_encoding() const {
-    const char* s = pn_message_get_content_encoding(message_);
+    const char* s = pn_message_get_content_encoding(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::expiry_time(amqp_timestamp t) {
-    pn_message_set_expiry_time(message_, t.milliseconds);
+    pn_message_set_expiry_time(pn_msg(), t.milliseconds);
 }
 amqp_timestamp message::expiry_time() const {
-    return amqp_timestamp(pn_message_get_expiry_time(message_));
+    return amqp_timestamp(pn_message_get_expiry_time(pn_msg()));
 }
 
 void message::creation_time(amqp_timestamp t) {
-    pn_message_set_creation_time(message_, t);
+    pn_message_set_creation_time(pn_msg(), t);
 }
 amqp_timestamp message::creation_time() const {
-    return pn_message_get_creation_time(message_);
+    return pn_message_get_creation_time(pn_msg());
 }
 
 void message::group_id(const std::string &s) {
-    check(pn_message_set_group_id(message_, s.c_str()));
+    check(pn_message_set_group_id(pn_msg(), s.c_str()));
 }
 
 std::string message::group_id() const {
-    const char* s = pn_message_get_group_id(message_);
+    const char* s = pn_message_get_group_id(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
 void message::reply_to_group_id(const std::string &s) {
-    check(pn_message_set_reply_to_group_id(message_, s.c_str()));
+    check(pn_message_set_reply_to_group_id(pn_msg(), s.c_str()));
 }
 
 std::string message::reply_to_group_id() const {
-    const char* s = pn_message_get_reply_to_group_id(message_);
+    const char* s = pn_message_get_reply_to_group_id(pn_msg());
     return s ? std::string(s) : std::string();
 }
 
-bool message::inferred() const { return pn_message_is_inferred(message_); }
-
-void message::inferred(bool b) { pn_message_set_inferred(message_, b); }
-
-void message::body(const value& v) { body().copy(v); }
+bool message::inferred() const { return pn_message_is_inferred(pn_msg()); }
 
-const data message::body() const {
-    return pn_message_body(message_);
-}
+void message::inferred(bool b) { pn_message_set_inferred(pn_msg(), b); }
 
-data message::body() {
-    return pn_message_body(message_);
-}
+const value& message::body() const { return impl_.body.ref(pn_message_body(pn_msg())); }
+value& message::body() { return impl_.body.ref(pn_message_body(pn_msg())); }
 
-void message::properties(const value& v) {
-    properties().copy(v);
-}
+// MAP CACHING: the properties, annotations and instructions maps can either be
+// encoded in the pn_message pn_data_t structures OR decoded as C++ map members
+// of the message but not both. At least one of the pn_data_t or the map member
+// is always empty, the non-empty one is the authority.
 
-const data message::properties() const {
-    return pn_message_properties(message_);
-}
-
-data message::properties() {
-    return pn_message_properties(message_);
-}
-
-namespace {
-typedef std::map<std::string, value> props_map;
-}
-
-void message::property(const std::string& name, const value &v) {
-    // TODO aconway 2015-11-17: not efficient but avoids cache consistency problems.
-    // Could avoid full encode/decode with linear scan of names. Need
-    // better codec suport for in-place modification of data.
-    props_map m;
-    if (!properties().empty())
-        properties().get(m);
-    m[name] = v;
-    properties(m);
-}
-
-value message::property(const std::string& name) const {
-    // TODO aconway 2015-11-17: not efficient but avoids cache consistency problems.
-    if (!properties().empty()) {
-        props_map m;
-        properties().get(m);
-        props_map::const_iterator i = m.find(name);
-        if (i != m.end())
-            return i->second;
+// 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));
+    if (map.empty() && !d.empty()) {
+        d.decoder() >> rewind() >> map;
+        d.clear();              // The map member is now the authority.
     }
-    return value();
+    return map;
 }
 
-bool message::erase_property(const std::string& name) {
-    // TODO aconway 2015-11-17: not efficient but avoids cache consistency problems.
-    if (!properties().empty()) {
-        props_map m;
-        properties().get(m);
-        if (m.erase(name)) {
-            properties(m);
-            return true;
-        }
+// 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));
+    if (d.empty() && !map.empty()) {
+        d.encoder() << map;
+        map.clear();        // The encoded pn_data_t  is now the authority.
     }
-    return false;
+    return map;
 }
 
-void message::annotations(const value& v) {
-    annotations().copy(v);
+message::property_map& message::properties() {
+    return get_map(pn_msg(), pn_message_properties, properties_);
 }
 
-const data message::annotations() const {
-    return pn_message_annotations(message_);
+const message::property_map& message::properties() const {
+    return get_map(pn_msg(), pn_message_properties, properties_);
 }
 
-data message::annotations() {
-    return pn_message_annotations(message_);
-}
 
-namespace {
-typedef std::map<proton::amqp_symbol, value> annotation_map;
+message::annotation_map& message::annotations() {
+    return get_map(pn_msg(), pn_message_annotations, annotations_);
 }
 
-void message::annotation(const proton::amqp_symbol &k, const value &v) {
-    annotation_map m;
-    if (!annotations().empty())
-        annotations().get(m);
-    m[k] = v;
-    annotations(m);
+const message::annotation_map& message::annotations() const {
+    return get_map(pn_msg(), pn_message_annotations, annotations_);
 }
 
-value message::annotation(const proton::amqp_symbol &k) const {
-    if (!annotations().empty()) {
-        annotation_map m;
-        annotations().get(m);
-        annotation_map::const_iterator i = m.find(k);
-        if (i != m.end())
-            return i->second;
-    }
-    return value();
 
+message::annotation_map& message::instructions() {
+    return get_map(pn_msg(), pn_message_instructions, instructions_);
 }
 
-bool message::erase_annotation(const proton::amqp_symbol &k) {
-    if (!annotations().empty()) {
-        annotation_map m;
-        annotations().get(m);
-        if (m.erase(k)) {
-            annotations(m);
-            return true;
-        }
-    }
-    return false;
+const message::annotation_map& message::instructions() const {
+    return get_map(pn_msg(), pn_message_instructions, instructions_);
 }
 
 void message::encode(std::string &s) const {
+    put_map(pn_msg(), pn_message_properties, properties_);
+    put_map(pn_msg(), pn_message_annotations, annotations_);
+    put_map(pn_msg(), pn_message_instructions, instructions_);
     size_t sz = s.capacity();
     if (sz < 512) sz = 512;
     while (true) {
         s.resize(sz);
-        int err = pn_message_encode(message_, const_cast<char*>(s.data()), &sz);
+        int err = pn_message_encode(pn_msg(), const_cast<char*>(s.data()), &sz);
         if (err) {
             if (err != PN_OVERFLOW)
                 check(err);
@@ -320,7 +283,10 @@ std::string message::encode() const {
 }
 
 void message::decode(const std::string &s) {
-    check(pn_message_decode(message_, s.data(), s.size()));
+    properties_.clear();
+    annotations_.clear();
+    instructions_.clear();
+    check(pn_message_decode(pn_msg(), s.data(), s.size()));
 }
 
 void message::decode(proton::link link, proton::delivery delivery) {
@@ -333,22 +299,22 @@ void message::decode(proton::link link, proton::delivery delivery) {
     link.advance();
 }
 
-bool message::durable() const { return pn_message_is_durable(message_); }
-void message::durable(bool b) { pn_message_set_durable(message_, b); }
+bool message::durable() const { return pn_message_is_durable(pn_msg()); }
+void message::durable(bool b) { pn_message_set_durable(pn_msg(), b); }
 
-duration message::ttl() const { return duration(pn_message_get_ttl(message_)); }
-void message::ttl(duration d) { pn_message_set_ttl(message_, d.milliseconds); }
+duration message::ttl() const { return duration(pn_message_get_ttl(pn_msg())); }
+void message::ttl(duration d) { pn_message_set_ttl(pn_msg(), d.milliseconds); }
 
-uint8_t message::priority() const { return pn_message_get_priority(message_); }
-void message::priority(uint8_t d) { pn_message_set_priority(message_, d); }
+uint8_t message::priority() const { return pn_message_get_priority(pn_msg()); }
+void message::priority(uint8_t d) { pn_message_set_priority(pn_msg(), d); }
 
-bool message::first_acquirer() const { return pn_message_is_first_acquirer(message_); }
-void message::first_acquirer(bool b) { pn_message_set_first_acquirer(message_, b); }
+bool message::first_acquirer() const { return pn_message_is_first_acquirer(pn_msg()); }
+void message::first_acquirer(bool b) { pn_message_set_first_acquirer(pn_msg(), b); }
 
-uint32_t message::delivery_count() const { return pn_message_get_delivery_count(message_); }
-void message::delivery_count(uint32_t d) { pn_message_set_delivery_count(message_, d); }
+uint32_t message::delivery_count() const { return pn_message_get_delivery_count(pn_msg()); }
+void message::delivery_count(uint32_t d) { pn_message_set_delivery_count(pn_msg(), d); }
 
-int32_t message::sequence() const { return pn_message_get_group_sequence(message_); }
-void message::sequence(int32_t d) { pn_message_set_group_sequence(message_, d); }
+int32_t message::sequence() const { return pn_message_get_group_sequence(pn_msg()); }
+void message::sequence(int32_t d) { pn_message_set_group_sequence(pn_msg(), d); }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1622d0e6/proton-c/bindings/cpp/src/message_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message_test.cpp b/proton-c/bindings/cpp/src/message_test.cpp
index 54995c0..9f05d1c 100644
--- a/proton-c/bindings/cpp/src/message_test.cpp
+++ b/proton-c/bindings/cpp/src/message_test.cpp
@@ -18,6 +18,7 @@
  */
 
 #include "proton/message.hpp"
+#include "proton/scalar.hpp"
 #include "test_bits.hpp"
 #include <string>
 #include <fstream>
@@ -32,58 +33,99 @@ using namespace proton;
     m.ATTR(#ATTR); \
     ASSERT_EQUAL(std::string(#ATTR), m.ATTR())
 
-#define CHECK_STR_VALUE(ATTR) \
+#define CHECK_MESSAGE_ID(ATTR) \
     m.ATTR(#ATTR); \
-    ASSERT_EQUAL(std::string(#ATTR), m.ATTR().get<std::string>())
+    ASSERT_EQUAL(scalar(#ATTR), m.ATTR())
 
-void test_message() {
+void test_message_properties() {
     message m("hello");
     std::string s = m.body().get<std::string>();
     ASSERT_EQUAL("hello", s);
 
-    CHECK_STR_VALUE(id);
+    CHECK_MESSAGE_ID(id);
     CHECK_STR(user_id);
     CHECK_STR(address);
     CHECK_STR(subject);
     CHECK_STR(reply_to);
-    CHECK_STR_VALUE(correlation_id);
+    CHECK_MESSAGE_ID(correlation_id);
     CHECK_STR(content_type);
     CHECK_STR(content_encoding);
     CHECK_STR(group_id);
     CHECK_STR(reply_to_group_id);
-
     m.expiry_time(42);
     ASSERT_EQUAL(m.expiry_time().milliseconds, 42);
     m.creation_time(4242);
     ASSERT_EQUAL(m.creation_time().milliseconds, 4242);
 
-    m.property("foo", 12);
-    ASSERT_EQUAL(m.property("foo"), value(12));
-    m.property("xxx", false);
-    ASSERT_EQUAL(m.property("xxx"), value(false));
-    ASSERT(m.erase_property("xxx"));
-    ASSERT(m.property("xxx").empty());
-    ASSERT(!m.erase_property("yyy"));
-
-    std::map<std::string, proton::value> props;
-    m.properties().get(props);
-    ASSERT_EQUAL(props.size(), 1);
-    ASSERT_EQUAL(props["foo"], value(12));
-    props["bar"] = amqp_symbol("xyz");
-    props["foo"] = true;
-    m.properties(props);
-    ASSERT_EQUAL(m.property("foo"), value(true));
-    ASSERT_EQUAL(m.property("bar"), value(amqp_symbol("xyz")));
-    m.property("bar", amqp_binary("bar"));
-    std::map<std::string, proton::value> props2;
-    m.properties().get(props2);
-    ASSERT_EQUAL(2, props2.size());
-    ASSERT_EQUAL(props2["foo"], value(true));
-    ASSERT_EQUAL(props2["bar"], value(amqp_binary("bar")));
+    message m2(m);
+    ASSERT_EQUAL("hello", m2.body().get<std::string>());
+    ASSERT_EQUAL(message_id("id"), m2.id());
+    ASSERT_EQUAL("user_id", m2.user_id());
+    ASSERT_EQUAL("address", m2.address());
+    ASSERT_EQUAL("subject", m2.subject());
+    ASSERT_EQUAL("reply_to", m2.reply_to());
+    ASSERT_EQUAL(message_id("correlation_id"), m2.correlation_id());
+    ASSERT_EQUAL("content_type", m2.content_type());
+    ASSERT_EQUAL("content_encoding", m2.content_encoding());
+    ASSERT_EQUAL("group_id", m2.group_id());
+    ASSERT_EQUAL("reply_to_group_id", m2.reply_to_group_id());
+    ASSERT_EQUAL(42, m2.expiry_time().milliseconds);
+    ASSERT_EQUAL(4242, m.creation_time().milliseconds);
+
+    m2 = m;
+    ASSERT_EQUAL("hello", m2.body().get<std::string>());
+    ASSERT_EQUAL(message_id("id"), m2.id());
+    ASSERT_EQUAL("user_id", m2.user_id());
+    ASSERT_EQUAL("address", m2.address());
+    ASSERT_EQUAL("subject", m2.subject());
+    ASSERT_EQUAL("reply_to", m2.reply_to());
+    ASSERT_EQUAL(message_id("correlation_id"), m2.correlation_id());
+    ASSERT_EQUAL("content_type", m2.content_type());
+    ASSERT_EQUAL("content_encoding", m2.content_encoding());
+    ASSERT_EQUAL("group_id", m2.group_id());
+    ASSERT_EQUAL("reply_to_group_id", m2.reply_to_group_id());
+    ASSERT_EQUAL(42, m2.expiry_time().milliseconds);
+    ASSERT_EQUAL(4242, m.creation_time().milliseconds);
+}
+
+void test_message_maps() {
+    message m;
+
+    ASSERT(m.properties().empty());
+    ASSERT(m.annotations().empty());
+    ASSERT(m.instructions().empty());
+
+    m.properties()["foo"] = 12;
+    m.instructions()["bar"] = "xyz";
+    m.annotations()[23] = "23";
+
+    ASSERT_EQUAL(m.properties()["foo"], scalar(12));
+    ASSERT_EQUAL(m.instructions()["bar"], scalar("xyz"));
+    ASSERT_EQUAL(m.annotations()[23], scalar("23"));
+
+    message m2(m);
+    message::annotation_map& amap = m2.instructions();
+
+    ASSERT_EQUAL(m2.properties()["foo"], scalar(12));
+    ASSERT_EQUAL(m2.instructions()["bar"], scalar("xyz"));
+    ASSERT_EQUAL(m2.annotations()[23], scalar("23"));
+
+    m.properties()["foo"] = "newfoo";
+    m.instructions()[24] = 1000;
+    m.annotations().erase(23);
+
+    m2 = m;
+    ASSERT_EQUAL(1, m2.properties().size());
+    ASSERT_EQUAL(m2.properties()["foo"], scalar("newfoo"));
+    ASSERT_EQUAL(2, m2.instructions().size());
+    ASSERT_EQUAL(m2.instructions()["bar"], scalar("xyz"));
+    ASSERT_EQUAL(m2.instructions()[24], scalar(1000));
+    ASSERT(m2.annotations().empty());
 }
 
 int main(int argc, char** argv) {
     int failed = 0;
-    RUN_TEST(failed, test_message());
+    RUN_TEST(failed, test_message_properties());
+    RUN_TEST(failed, test_message_maps());
     return failed;
 }


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


Mime
View raw message