You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kp...@apache.org on 2016/03/17 16:34:25 UTC

[2/4] qpid-proton git commit: PROTON-1138: c++: get<>/coerce<> API and documentation.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 0d3a2f5..dd30867 100644
--- a/proton-c/bindings/cpp/include/proton/error.hpp
+++ b/proton-c/bindings/cpp/include/proton/error.hpp
@@ -36,19 +36,19 @@ namespace proton {
 /// subclasses of proton::error.
 struct
 PN_CPP_CLASS_EXTERN error : public std::runtime_error {
-  PN_CPP_EXTERN explicit error(const std::string&);
+    PN_CPP_EXTERN explicit error(const std::string&); ///< Construct with message
 };
 
 /// Raised if a timeout expires.
 struct
 PN_CPP_CLASS_EXTERN timeout_error : public error {
-  PN_CPP_EXTERN explicit timeout_error(const std::string&);
+    PN_CPP_EXTERN explicit timeout_error(const std::string&);  ///< Construct with message
 };
 
 /// Raised if there is an error converting between AMQP and C++ data.
 struct
 PN_CPP_CLASS_EXTERN conversion_error : public error {
-  PN_CPP_EXTERN explicit conversion_error(const std::string&);
+    PN_CPP_EXTERN explicit conversion_error(const std::string&);  ///< Construct with message
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/forward_list.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/forward_list.hpp b/proton-c/bindings/cpp/include/proton/forward_list.hpp
index 9358da9..00e3b2c 100644
--- a/proton-c/bindings/cpp/include/proton/forward_list.hpp
+++ b/proton-c/bindings/cpp/include/proton/forward_list.hpp
@@ -30,7 +30,7 @@ namespace codec {
 /// std::forward_list<T> for most T is encoded as an AMQP array.
 template <class T, class A>
 encoder& operator<<(encoder& e, const std::forward_list<T, A>& x) {
-    return e << encoder::array(x, type_id_of<T>::value);
+    return e << encoder::array(x, internal::type_id_of<T>::value);
 }
 
 /// Specialize for std::forward_list<value>, encode as AMQP forward_list (variable type)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/io.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io.hpp b/proton-c/bindings/cpp/include/proton/io.hpp
index 35a7223..9c63edb 100644
--- a/proton-c/bindings/cpp/include/proton/io.hpp
+++ b/proton-c/bindings/cpp/include/proton/io.hpp
@@ -25,6 +25,7 @@
 
 namespace proton {
 
+///@details
 /// IO using sockets, file descriptors, or handles, for use with
 /// proton::connection_engine.
 ///
@@ -32,7 +33,6 @@ namespace proton {
 /// over your own IO implementation or to integrate an existing IO framework of
 /// your choice, this implementation is provided as a convenience if sockets is
 /// sufficient for your needs.
-
 namespace io {
 
 /// @name Setup and teardown
@@ -67,6 +67,7 @@ struct guard {
 /// An IO resource.
 typedef int64_t descriptor;
 
+/// An invalid descriptor.
 PN_CPP_EXTERN extern const descriptor INVALID_DESCRIPTOR;
 
 /// Return a string describing the most recent IO error.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/link.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/link.hpp b/proton-c/bindings/cpp/include/proton/link.hpp
index e626398..8de2e7b 100644
--- a/proton-c/bindings/cpp/include/proton/link.hpp
+++ b/proton-c/bindings/cpp/include/proton/link.hpp
@@ -124,12 +124,14 @@ PN_CPP_CLASS_EXTERN link : public internal::object<pn_link_t> , public endpoint
     /// Session that owns this link.
     PN_CPP_EXTERN class session session() const;
 
+    ///@cond INTERNAL
     /// XXX local versus remote, mutability
     /// XXX - local_sender_settle_mode and local_receiver_settle_mode
     PN_CPP_EXTERN link_options::sender_settle_mode sender_settle_mode();
     PN_CPP_EXTERN link_options::receiver_settle_mode receiver_settle_mode();
     PN_CPP_EXTERN link_options::sender_settle_mode remote_sender_settle_mode();
     PN_CPP_EXTERN link_options::receiver_settle_mode remote_receiver_settle_mode();
+    ///@endcond
 
   private:
     // Used by link_options
@@ -154,8 +156,11 @@ PN_CPP_CLASS_EXTERN link : public internal::object<pn_link_t> , public endpoint
 /// An iterator for links.
 class link_iterator : public internal::iter_base<link, link_iterator> {
   public:
+    ///@cond INTERNAL
     explicit link_iterator(link l = 0, pn_session_t* s = 0) :
         internal::iter_base<link, link_iterator>(l), session_(s) {}
+    ///@endcond
+    /// Advance
     PN_CPP_EXTERN link_iterator operator++();
 
   private:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/list.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/list.hpp b/proton-c/bindings/cpp/include/proton/list.hpp
index 0172b24..1a996a0 100644
--- a/proton-c/bindings/cpp/include/proton/list.hpp
+++ b/proton-c/bindings/cpp/include/proton/list.hpp
@@ -30,7 +30,7 @@ namespace codec {
 /// std::list<T> for most T is encoded as an AMQP array.
 template <class T, class A>
 encoder& operator<<(encoder& e, const std::list<T, A>& x) {
-    return e << encoder::array(x, type_id_of<T>::value);
+    return e << encoder::array(x, internal::type_id_of<T>::value);
 }
 
 /// Specialize for std::list<value>, encode as AMQP list (variable type)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 0fc4cc1..2bba148 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -164,7 +164,7 @@ class message {
 
     /// @name Transfer headers
     /// @{
-    
+
     /// Get the durable flag for a message.
     ///
     /// The durable flag indicates that any parties taking
@@ -206,7 +206,7 @@ class message {
     /// does not mean the message has not been delivered to, but not
     /// acquired, by other recipients.
     PN_CPP_EXTERN bool first_acquirer() const;
-    
+
     /// Set the first acquirer flag for a message.
     PN_CPP_EXTERN void first_acquirer(bool);
 
@@ -240,7 +240,7 @@ class message {
     PN_CPP_EXTERN void group_sequence(int32_t);
 
     /// @}
-    
+
     /// @name Extended attributes
     /// @{
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 0def327..2860a2a 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -21,7 +21,7 @@
  */
 
 #include <proton/binary.hpp>
-#include <proton/scalar.hpp>
+#include <proton/scalar_base.hpp>
 #include <proton/uuid.hpp>
 
 #include <string>
@@ -37,53 +37,49 @@ namespace proton {
 ///  - proton::uuid
 ///  - proton::binary
 ///
-class message_id : public restricted_scalar {
+class message_id : public scalar_base {
   public:
     /// An empty message_id has a uint64_t == 0 value.
-    message_id() { scalar_ = uint64_t(0); }
-    message_id(const message_id& x) { scalar_ = x; }
-    message_id& operator=(const message_id& x) { scalar_ = x; return *this; }
+    message_id() { put_(uint64_t(0)); }
 
-    message_id(uint64_t x) { scalar_ = x; }
-    message_id(const uuid& x) { scalar_ = x; }
-    message_id(const binary& x) { scalar_ = x; }
-    message_id(const std::string& x) { scalar_ = x; }
-
-    /// Extra conversion - treat char* as amqp::STRING
-    message_id(const char* x) { scalar_ = x; }
+    /// Construct from any type that can be assigned
+    template <class T> message_id(const T& x) { *this = x; }
 
     /// @name Assignment operators
-    ///
     /// Assign a C++ value, deduce the AMQP type()
     ///
     /// @{
-    message_id& operator=(uint64_t x) { scalar_ = x; return *this; }
-    message_id& operator=(const uuid& x) { scalar_ = x; return *this; }
-    message_id& operator=(const binary& x) { scalar_ = x; return *this; }
-    message_id& operator=(const std::string& x) { scalar_ = x; return *this; }
-    /// @}
-
-    /// @name Get methods
-    ///
-    /// get(T&) extracts the value if the types match exactly and
-    /// throws conversion_error otherwise.
-    ///
-    /// @{
-    void get(uint64_t& x) const { scalar_.get(x); }
-    void get(uuid& x) const { scalar_.get(x); }
-    void get(binary& x) const { scalar_.get(x); }
-    void get(std::string& x) const { scalar_.get(x); }
+    message_id& operator=(uint64_t x) { put_(x); return *this; }
+    message_id& operator=(const uuid& x) { put_(x); return *this; }
+    message_id& operator=(const binary& x) { put_(x); return *this; }
+    message_id& operator=(const std::string& x) { put_(x); return *this; }
+    message_id& operator=(const char* x) { put_(x); return *this; } ///< Treated as amqp::STRING
     /// @}
 
-    /// Return the value as type T.
-    template<class T> T get() const { T x; get(x); return x; }
-
   private:
-    message_id(const pn_atom_t& a): restricted_scalar(a) {}
+    message_id(const pn_atom_t& a): scalar_base(a) {}
 
+    ///@cond INTERNAL
   friend class message;
   friend class codec::decoder;
+    ///@endcond
 };
 
+///@cond internal
+template <class T> T get(const message_id& x);
+///@endcond
+
+/// Get the uint64_t value or throw conversion_error. @related message_id
+template<> inline uint64_t get<uint64_t>(const message_id& x) { return internal::get<uint64_t>(x); }
+/// Get the @ref uuid value or throw conversion_error. @related message_id
+template<> inline uuid get<uuid>(const message_id& x) { return internal::get<uuid>(x); }
+/// Get the @ref binary value or throw conversion_error. @related message_id
+template<> inline binary get<binary>(const message_id& x) { return internal::get<binary>(x); }
+/// Get the std::string value or throw conversion_error. @related message_id
+template<> inline std::string get<std::string>(const message_id& x) { return internal::get<std::string>(x); }
+
+/// @copydoc scalar::coerce
+/// @related message_id
+template<class T> T coerce(const message_id& x) { return internal::coerce<T>(x); }
 }
 #endif // MESSAGE_ID_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 dd55e95..af16a89 100644
--- a/proton-c/bindings/cpp/include/proton/scalar.hpp
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -1,5 +1,5 @@
-#ifndef SCALAR_HPP
-#define SCALAR_HPP
+#ifndef PROTON_SCALAR_HPP
+#define PROTON_SCALAR_HPP
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -20,14 +20,7 @@
  * under the License.
  */
 
-#include <proton/binary.hpp>
-#include <proton/export.hpp>
-#include <proton/comparable.hpp>
-#include <proton/types_fwd.hpp>
-#include <proton/type_id.hpp>
-
-#include <iosfwd>
-#include <string>
+#include <proton/scalar_base.hpp>
 
 namespace proton {
 
@@ -36,190 +29,48 @@ class decoder;
 class encoder;
 }
 
-/// A holder for an instance of any scalar AMQP type.
-/// The conversions for scalar types are documented in proton::amqp.
+/// A holder for an instance of any scalar AMQP type, see \ref types.
 ///
-class scalar : private comparable<scalar> {
+class scalar : public scalar_base {
   public:
     /// Create an empty scalar.
-    PN_CPP_EXTERN scalar();
-
-    /// Copy a scalar.
-    PN_CPP_EXTERN scalar(const scalar&);
-
-    /// Copy a 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 Construct from a C++ value.
-    /// See proton::amqp for the list of type correspondences.
-    ///
-    /// @{
-    PN_CPP_EXTERN scalar(bool x);
-    PN_CPP_EXTERN scalar(uint8_t x);
-    PN_CPP_EXTERN scalar(int8_t x);
-    PN_CPP_EXTERN scalar(uint16_t x);
-    PN_CPP_EXTERN scalar(int16_t x);
-    PN_CPP_EXTERN scalar(uint32_t x);
-    PN_CPP_EXTERN scalar(int32_t x);
-    PN_CPP_EXTERN scalar(uint64_t x);
-    PN_CPP_EXTERN scalar(int64_t x);
-    PN_CPP_EXTERN scalar(wchar_t x);
-    PN_CPP_EXTERN scalar(float x);
-    PN_CPP_EXTERN scalar(double x);
-    PN_CPP_EXTERN scalar(timestamp x);
-    PN_CPP_EXTERN scalar(const decimal32& x);
-    PN_CPP_EXTERN scalar(const decimal64& x);
-    PN_CPP_EXTERN scalar(const decimal128& x);
-    PN_CPP_EXTERN scalar(const uuid& x);
-    PN_CPP_EXTERN scalar(const std::string& x);
-    PN_CPP_EXTERN scalar(const symbol& x);
-    PN_CPP_EXTERN scalar(const binary& x);
-    PN_CPP_EXTERN scalar(const char* s); ///< Treated as an AMQP string
-    /// @}
-
-
-    /// @name Assignment operators
-    ///
-    /// Assign a C++ value as the corresponding AMQP type.
-    /// See proton::amqp for the list of type correspondences.
-    ///
-    /// @{
-    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=(timestamp);
-    PN_CPP_EXTERN scalar& operator=(const decimal32&);
-    PN_CPP_EXTERN scalar& operator=(const decimal64&);
-    PN_CPP_EXTERN scalar& operator=(const decimal128&);
-    PN_CPP_EXTERN scalar& operator=(const uuid&);
-    PN_CPP_EXTERN scalar& operator=(const std::string&);
-    PN_CPP_EXTERN scalar& operator=(const symbol&);
-    PN_CPP_EXTERN scalar& operator=(const binary&);
-    PN_CPP_EXTERN scalar& operator=(const char* s); ///< Treated as an AMQP string
-    /// @}
-
-
-    /// @name Get methods
-    ///
-    /// get(T&) extracts the value if the types match exactly and
-    /// throws conversion_error otherwise.
-    ///
-    /// @{
-    PN_CPP_EXTERN void get(bool&) const;
-    PN_CPP_EXTERN void get(uint8_t&) const;
-    PN_CPP_EXTERN void get(int8_t&) const;
-    PN_CPP_EXTERN void get(uint16_t&) const;
-    PN_CPP_EXTERN void get(int16_t&) const;
-    PN_CPP_EXTERN void get(uint32_t&) const;
-    PN_CPP_EXTERN void get(int32_t&) const;
-    PN_CPP_EXTERN void get(uint64_t&) const;
-    PN_CPP_EXTERN void get(int64_t&) const;
-    PN_CPP_EXTERN void get(wchar_t&) const;
-    PN_CPP_EXTERN void get(float&) const;
-    PN_CPP_EXTERN void get(double&) const;
-    PN_CPP_EXTERN void get(timestamp&) const;
-    PN_CPP_EXTERN void get(decimal32&) const;
-    PN_CPP_EXTERN void get(decimal64&) const;
-    PN_CPP_EXTERN void get(decimal128&) const;
-    PN_CPP_EXTERN void get(uuid&) const;
-    PN_CPP_EXTERN void get(symbol&) const;
-    PN_CPP_EXTERN void get(binary&) const;
-    PN_CPP_EXTERN void get(std::string&) const;
-    /// @}
-
-    /// get<T>() is like get(T&) but returns the value.
-    template<class T> T get() const { T x; get(x); return x; }
-
-    /// @name As methods
-    ///
-    /// As methods do "loose" conversion.  They will convert the
-    /// scalar's value to the requested type if possible, else throw
-    /// conversion_error.
-    ///
-    /// @{
-    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())
-    /// @}
-
-    /// @cond INTERNAL
+    PN_CPP_EXTERN scalar() {}
 
-  friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const scalar&);
+    /// Construct from any scalar type, see \ref types.
+    template <class T> scalar(const T& x) { *this = x; }
 
-    /// 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);
+    /// Assign from any scalar type, see \ref types.
+    template <class T> scalar& operator=(const T& x) { put_(x); return *this; }
 
-    /// For scalars of different type(), operator< sorts by order of type().
-  friend PN_CPP_EXTERN bool operator<(const scalar& x, const scalar& y);
+    /// No contents, type() == NULL_TYPE
+    bool empty() const { return type() == NULL_TYPE; }
 
-    /// @endcond
+    /// Clear the scalar, make it empty()
+    void clear() { *this = null(); }
 
-  private:
-    scalar(const pn_atom_t& a);
-    void ok(pn_type_t) const;
-    void set(const binary&, pn_type_t);
-    void set(const pn_atom_t&);
-    pn_atom_t atom_;
-    binary bytes_;              // Hold binary data.
-
-  friend class message;
-  friend class restricted_scalar;
-  friend class codec::encoder;
-  friend class codec::decoder;
 };
 
-/// @cond INTERNAL
-/// Base class for restricted scalar types.
-class restricted_scalar : private comparable<restricted_scalar> {
-  public:
-    operator const scalar&() const { return scalar_; }
-    type_id type() const { return scalar_.type(); }
-
-    /// @name As methods
-    ///
-    /// As methods do "loose" conversion.  They will convert the
-    /// scalar's value to the requested type if possible, else throw
-    /// conversion_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(); }
-    /// @}
-
-  protected:
-    restricted_scalar() {}
-    restricted_scalar(const pn_atom_t& a) : scalar_(a) {}
-    restricted_scalar(const restricted_scalar& x) : scalar_(x.scalar_) {}
-
-    scalar scalar_;
-
-  friend class message;
+/// Get a contained value of type T. For example:
+///
+///      uint64_t i = get<uint64_t>(x)
+///
+/// Will succeed if and only if x contains a uint64_t value.
+///
+/// @throw conversion_error if contained value is not of type T.
+/// @related scalar
+template<class T> T get(const scalar& s) { return internal::get<T>(s); }
 
-    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_; }
-};
-/// @endcond
+/// Coerce the contained value to type T. For example:
+///
+///      uint64_t i = get<uint64_t>(x)
+///
+/// Will succeed if x contains any numeric value, but may lose precision if it
+/// contains a float or double value.
+///
+/// @throw conversion_error if the value cannot be converted to T according to `std::is_convertible`
+/// @related scalar
+template<class T> T coerce(const scalar& x) { return internal::coerce<T>(x); }
 
 }
 
-#endif // SCALAR_HPP
+#endif  /*!PROTON_SCALAR_HPP*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/scalar_base.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar_base.hpp b/proton-c/bindings/cpp/include/proton/scalar_base.hpp
new file mode 100644
index 0000000..43003c8
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/scalar_base.hpp
@@ -0,0 +1,181 @@
+#ifndef PROTON_SCALAR_BASE_HPP
+#define PROTON_SCALAR_BASE_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/binary.hpp>
+#include <proton/comparable.hpp>
+#include <proton/decimal.hpp>
+#include <proton/error.hpp>
+#include <proton/export.hpp>
+#include <proton/symbol.hpp>
+#include <proton/timestamp.hpp>
+#include <proton/type_id.hpp>
+#include <proton/types_fwd.hpp>
+#include <proton/type_traits.hpp>
+#include <proton/uuid.hpp>
+
+#include <iosfwd>
+#include <string>
+
+namespace proton {
+
+namespace codec {
+class decoder;
+class encoder;
+}
+
+
+/// Base class for scalar types.
+class scalar_base : private comparable<scalar_base> {
+  public:
+    /// AMQP type of data stored in the scalar
+    PN_CPP_EXTERN type_id type() const;
+
+    /// @cond INTERNAL
+    /// deprecated
+    PN_CPP_EXTERN int64_t as_int() const;
+    PN_CPP_EXTERN uint64_t as_uint() const;
+    PN_CPP_EXTERN double as_double() const;
+    PN_CPP_EXTERN std::string as_string() const;
+    template <class T> void get(T& x) const { get_(x); }
+    template <class T> T get() const { T x; get_(x); return x; }
+    /// @endcond
+
+    /// Compare
+  friend PN_CPP_EXTERN bool operator<(const scalar_base& x, const scalar_base& y);
+    /// Compare
+  friend PN_CPP_EXTERN bool operator==(const scalar_base& x, const scalar_base& y);
+    /// Print contained value
+  friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, const scalar_base& x);
+
+  protected:
+    PN_CPP_EXTERN scalar_base(const pn_atom_t& a);
+    PN_CPP_EXTERN scalar_base();
+    PN_CPP_EXTERN scalar_base(const scalar_base&);
+    PN_CPP_EXTERN scalar_base& operator=(const scalar_base&);
+
+    PN_CPP_EXTERN void put_(bool);
+    PN_CPP_EXTERN void put_(uint8_t);
+    PN_CPP_EXTERN void put_(int8_t);
+    PN_CPP_EXTERN void put_(uint16_t);
+    PN_CPP_EXTERN void put_(int16_t);
+    PN_CPP_EXTERN void put_(uint32_t);
+    PN_CPP_EXTERN void put_(int32_t);
+    PN_CPP_EXTERN void put_(uint64_t);
+    PN_CPP_EXTERN void put_(int64_t);
+    PN_CPP_EXTERN void put_(wchar_t);
+    PN_CPP_EXTERN void put_(float);
+    PN_CPP_EXTERN void put_(double);
+    PN_CPP_EXTERN void put_(timestamp);
+    PN_CPP_EXTERN void put_(const decimal32&);
+    PN_CPP_EXTERN void put_(const decimal64&);
+    PN_CPP_EXTERN void put_(const decimal128&);
+    PN_CPP_EXTERN void put_(const uuid&);
+    PN_CPP_EXTERN void put_(const std::string&);
+    PN_CPP_EXTERN void put_(const symbol&);
+    PN_CPP_EXTERN void put_(const binary&);
+    PN_CPP_EXTERN void put_(const char* s); ///< Treated as an AMQP string
+    PN_CPP_EXTERN void put_(const null&);
+
+    PN_CPP_EXTERN void get_(bool&) const;
+    PN_CPP_EXTERN void get_(uint8_t&) const;
+    PN_CPP_EXTERN void get_(int8_t&) const;
+    PN_CPP_EXTERN void get_(uint16_t&) const;
+    PN_CPP_EXTERN void get_(int16_t&) const;
+    PN_CPP_EXTERN void get_(uint32_t&) const;
+    PN_CPP_EXTERN void get_(int32_t&) const;
+    PN_CPP_EXTERN void get_(uint64_t&) const;
+    PN_CPP_EXTERN void get_(int64_t&) const;
+    PN_CPP_EXTERN void get_(wchar_t&) const;
+    PN_CPP_EXTERN void get_(float&) const;
+    PN_CPP_EXTERN void get_(double&) const;
+    PN_CPP_EXTERN void get_(timestamp&) const;
+    PN_CPP_EXTERN void get_(decimal32&) const;
+    PN_CPP_EXTERN void get_(decimal64&) const;
+    PN_CPP_EXTERN void get_(decimal128&) const;
+    PN_CPP_EXTERN void get_(uuid&) const;
+    PN_CPP_EXTERN void get_(std::string&) const;
+    PN_CPP_EXTERN void get_(symbol&) const;
+    PN_CPP_EXTERN void get_(binary&) const;
+    PN_CPP_EXTERN void get_(null&) const;
+
+  private:
+    void ok(pn_type_t) const;
+    void set(const pn_atom_t&);
+    void set(const binary& x, pn_type_t t);
+
+    pn_atom_t atom_;
+    binary bytes_;              // Hold binary data.
+
+  friend class message;
+  friend class codec::encoder;
+  friend class codec::decoder;
+};
+
+namespace internal {
+
+template<class T> T get(const scalar_base& s) { T x; s.get(x); return x; }
+
+template <class R, class F> R visit(const scalar_base& s, F f) {
+    switch(s.type()) {
+      case BOOLEAN: return f(s.get<bool>());
+      case UBYTE: return f(s.get<uint8_t>());
+      case BYTE: return f(s.get<int8_t>());
+      case USHORT: return f(s.get<uint16_t>());
+      case SHORT: return f(s.get<int16_t>());
+      case UINT: return f(s.get<uint32_t>());
+      case INT: return f(s.get<int32_t>());
+      case CHAR: return f(s.get<wchar_t>());
+      case ULONG: return f(s.get<uint64_t>());
+      case LONG: return f(s.get<int64_t>());
+      case TIMESTAMP: return f(s.get<timestamp>());
+      case FLOAT: return f(s.get<float>());
+      case DOUBLE: return f(s.get<double>());
+      case DECIMAL32: return f(s.get<decimal32>());
+      case DECIMAL64: return f(s.get<decimal64>());
+      case DECIMAL128: return f(s.get<decimal128>());
+      case UUID: return f(s.get<uuid>());
+      case BINARY: return f(s.get<binary>());
+      case STRING: return f(s.get<std::string>());
+      case SYMBOL: return f(s.get<symbol>());
+      default: throw conversion_error("invalid scalar type "+type_name(s.type()));
+    }
+}
+
+template<class T> struct coerce_op {
+    template <class U>
+    typename enable_if<is_convertible<U, T>::value, T>::type operator()(const U& x) {
+        return static_cast<T>(x);
+    }
+    template <class U>
+    typename enable_if<!is_convertible<U, T>::value, T>::type operator()(const U&) {
+        throw conversion_error("cannot coerce from " + type_name(type_id_of<U>::value));
+    }
+};
+
+template <class T> T coerce(const scalar_base& s) { return visit<T>(s, coerce_op<T>()); }
+
+} // internal
+
+
+} // proton
+
+#endif  /*!PROTON_SCALAR_BASE_HPP*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/session.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/session.hpp b/proton-c/bindings/cpp/include/proton/session.hpp
index 5b08669..014ab2a 100644
--- a/proton-c/bindings/cpp/include/proton/session.hpp
+++ b/proton-c/bindings/cpp/include/proton/session.hpp
@@ -105,8 +105,10 @@ PN_CPP_CLASS_EXTERN session : public internal::object<pn_session_t>, public endp
 /// An iterator for sessions.
 class session_iterator : public internal::iter_base<session, session_iterator> {
  public:
+    ///@cond INTERNAL
     explicit session_iterator(session s = 0) : internal::iter_base<session, session_iterator>(s) {}
-    PN_CPP_EXTERN session_iterator operator++();
+    ///@endcond
+    PN_CPP_EXTERN session_iterator operator++();     ///< Advance
 };
 
 /// A range of sessions.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/symbol.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/symbol.hpp b/proton-c/bindings/cpp/include/proton/symbol.hpp
index 24a5213..7a5764a 100644
--- a/proton-c/bindings/cpp/include/proton/symbol.hpp
+++ b/proton-c/bindings/cpp/include/proton/symbol.hpp
@@ -26,8 +26,12 @@ namespace proton {
 ///
 class symbol : public std::string {
   public:
+    /// Construct from a std::string
     symbol(const std::string& s=std::string()) : std::string(s) {}
+    /// Construct from a C-string
     symbol(const char* s) : std::string(s) {}
+    /// Construct from any sequence of char
+    template<class Iter> symbol(Iter start, Iter finish) : std::string(start, finish) {}
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/timestamp.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/timestamp.hpp b/proton-c/bindings/cpp/include/proton/timestamp.hpp
index 00282dd..61d8cf3 100644
--- a/proton-c/bindings/cpp/include/proton/timestamp.hpp
+++ b/proton-c/bindings/cpp/include/proton/timestamp.hpp
@@ -22,28 +22,32 @@
 #include "proton/duration.hpp"
 
 namespace proton {
-/// A timestamp in milliseconds since the epoch 00:00:00 (UTC), 1 January 1970.
+/// 64 bit timestamp in milliseconds since the epoch 00:00:00 (UTC), 1 January 1970.
 class timestamp : private comparable<timestamp> {
   public:
-    typedef int64_t numeric_type;
-    PN_CPP_EXTERN static timestamp now();
+    typedef int64_t numeric_type; ///< Numeric type holding milliseconds value
+    PN_CPP_EXTERN static timestamp now(); ///< Current wall-clock time
 
-    explicit timestamp(numeric_type ms = 0) : ms_(ms) {}
-    timestamp& operator=(numeric_type ms) { ms_ = ms; return *this; }
-    numeric_type milliseconds() const { return ms_; }
-    numeric_type ms() const { return ms_; }
+    explicit timestamp(numeric_type ms = 0) : ms_(ms) {} ///< Construct from milliseconds
+    timestamp& operator=(numeric_type ms) { ms_ = ms; return *this; }  ///< Assign from milliseconds
+    numeric_type milliseconds() const { return ms_; } ///< Get milliseconds
+    numeric_type ms() const { return ms_; }           ///< Get milliseconds
 
   private:
     numeric_type ms_;
 };
 
+///@name Comparison and arithmetic operators
+///@{
 inline bool operator==(timestamp x, timestamp y) { return x.ms() == y.ms(); }
 inline bool operator<(timestamp x, timestamp y) { return x.ms() < y.ms(); }
 
 inline timestamp operator+(timestamp ts, duration d) { return timestamp(ts.ms() + d.ms()); }
 inline duration operator-(timestamp t0, timestamp t1) { return duration(t0.ms() - t1.ms()); }
 inline timestamp operator+(duration d, timestamp ts) { return ts + d; }
+///@}
 
+/// Printable format.
 PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, timestamp);
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/type_id.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/type_id.hpp b/proton-c/bindings/cpp/include/proton/type_id.hpp
index 2d399a5..8a6e841 100644
--- a/proton-c/bindings/cpp/include/proton/type_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/type_id.hpp
@@ -1,5 +1,5 @@
-#ifndef TYPES_H
-#define TYPES_H
+#ifndef PROTON_TYPE_ID_HPP
+#define PROTON_TYPE_ID_HPP
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -20,6 +20,10 @@
  * under the License.
  */
 
+///@file
+///
+/// Type-identifiers for AMQP types.
+
 #include <proton/export.hpp>
 #include <proton/codec.h>
 #include <string>
@@ -64,6 +68,19 @@ PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, type_id);
 /// Throw a conversion_error if want != got with a message including the names of the types.
 PN_CPP_EXTERN void assert_type_equal(type_id want, type_id got);
 
+///@name Test propreties of a type_id.
+///@{
+inline bool type_id_is_signed_int(type_id t) { return t == BYTE || t == SHORT || t == INT || t == LONG; }
+inline bool type_id_is_unsigned_int(type_id t) { return t == UBYTE || t == USHORT || t == UINT || t == ULONG; }
+inline bool type_id_is_integral(type_id t) { return t == BOOLEAN || t == CHAR || t == TIMESTAMP || type_id_is_unsigned_int(t) || type_id_is_signed_int(t); }
+inline bool type_id_is_floating_point(type_id t) { return t == FLOAT || t == DOUBLE; }
+inline bool type_id_is_decimal(type_id t) { return t == DECIMAL32 || t == DECIMAL64 || t == DECIMAL128; }
+inline bool type_id_is_signed(type_id t) { return type_id_is_signed_int(t) || type_id_is_floating_point(t) || type_id_is_decimal(t); }
+inline bool type_id_is_string_like(type_id t) { return t == BINARY || t == STRING || t == SYMBOL; }
+inline bool type_id_is_container(type_id t) { return t == LIST || t == MAP || t == ARRAY || t == DESCRIBED; }
+inline bool type_id_is_scalar(type_id t) { return type_id_is_integral(t) || type_id_is_floating_point(t) || type_id_is_decimal(t) || type_id_is_string_like(t) || t == TIMESTAMP || t == UUID; }
+///}
+
 } // proton
 
-#endif // TYPES_H
+#endif  /*!PROTON_TYPE_ID_HPP*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 1000a63..db4d685 100644
--- a/proton-c/bindings/cpp/include/proton/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/type_traits.hpp
@@ -20,8 +20,6 @@
  * under the License.
  */
 
-/// @cond INTERNAL
-
 /// @file
 ///
 /// Internal: Type traits for mapping between AMQP and C++ types.
@@ -33,8 +31,9 @@
 #include <proton/types_fwd.hpp>
 #include <proton/type_id.hpp>
 
+///@cond INTERNAL
 namespace proton {
-namespace codec {
+namespace internal {
 
 class decoder;
 class encoder;
@@ -83,35 +82,39 @@ 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; };
 
-template <type_id ID> struct type_id_constant { static const type_id value = ID; };
-
-// Metafunction returning AMQP type for scalar C++ types.
-template <class T, class Enable=void> struct type_id_of;
-template<> struct type_id_of<bool> : public type_id_constant<BOOLEAN> {};
-template<> struct type_id_of<uint8_t> : public type_id_constant<UBYTE> {};
-template<> struct type_id_of<int8_t> : public type_id_constant<BYTE> {};
-template<> struct type_id_of<uint16_t> : public type_id_constant<USHORT> {};
-template<> struct type_id_of<int16_t> : public type_id_constant<SHORT> {};
-template<> struct type_id_of<uint32_t> : public type_id_constant<UINT> {};
-template<> struct type_id_of<int32_t> : public type_id_constant<INT> {};
-template<> struct type_id_of<uint64_t> : public type_id_constant<ULONG> {};
-template<> struct type_id_of<int64_t> : public type_id_constant<LONG> {};
-template<> struct type_id_of<wchar_t> : public type_id_constant<CHAR> {};
-template<> struct type_id_of<timestamp> : public type_id_constant<TIMESTAMP> {};
-template<> struct type_id_of<float> : public type_id_constant<FLOAT> {};
-template<> struct type_id_of<double> : public type_id_constant<DOUBLE> {};
-template<> struct type_id_of<decimal32> : public type_id_constant<DECIMAL32> {};
-template<> struct type_id_of<decimal64> : public type_id_constant<DECIMAL64> {};
-template<> struct type_id_of<decimal128> : public type_id_constant<DECIMAL128> {};
-template<> struct type_id_of<uuid> : public type_id_constant<UUID> {};
-template<> struct type_id_of<binary> : public type_id_constant<BINARY> {};
-template<> struct type_id_of<std::string> : public type_id_constant<STRING> {};
-template<> struct type_id_of<symbol> : public type_id_constant<SYMBOL> {};
-template<> struct type_id_of<const char*> : public type_id_constant<STRING> {};
-
-// Metafunction to test if a class has a type_id.
+template <type_id ID, class T> struct type_id_constant {
+    typedef T type;
+    static const type_id value = ID;
+};
+
+///@name Metafunction returning AMQP type for scalar C++ types.
+///@{
+template <class T> struct type_id_of;
+template<> struct type_id_of<bool> : public type_id_constant<BOOLEAN, bool> {};
+template<> struct type_id_of<uint8_t> : public type_id_constant<UBYTE, uint8_t> {};
+template<> struct type_id_of<int8_t> : public type_id_constant<BYTE, int8_t> {};
+template<> struct type_id_of<uint16_t> : public type_id_constant<USHORT, uint16_t> {};
+template<> struct type_id_of<int16_t> : public type_id_constant<SHORT, int16_t> {};
+template<> struct type_id_of<uint32_t> : public type_id_constant<UINT, uint32_t> {};
+template<> struct type_id_of<int32_t> : public type_id_constant<INT, int32_t> {};
+template<> struct type_id_of<uint64_t> : public type_id_constant<ULONG, uint64_t> {};
+template<> struct type_id_of<int64_t> : public type_id_constant<LONG, int64_t> {};
+template<> struct type_id_of<wchar_t> : public type_id_constant<CHAR, wchar_t> {};
+template<> struct type_id_of<float> : public type_id_constant<FLOAT, float> {};
+template<> struct type_id_of<double> : public type_id_constant<DOUBLE, double> {};
+template<> struct type_id_of<timestamp> : public type_id_constant<TIMESTAMP, timestamp> {};
+template<> struct type_id_of<decimal32> : public type_id_constant<DECIMAL32, decimal32> {};
+template<> struct type_id_of<decimal64> : public type_id_constant<DECIMAL64, decimal64> {};
+template<> struct type_id_of<decimal128> : public type_id_constant<DECIMAL128, decimal128> {};
+template<> struct type_id_of<uuid> : public type_id_constant<UUID, uuid> {};
+template<> struct type_id_of<std::string> : public type_id_constant<STRING, std::string> {};
+template<> struct type_id_of<symbol> : public type_id_constant<SYMBOL, symbol> {};
+template<> struct type_id_of<binary> : public type_id_constant<BINARY, binary> {};
+///@}
+
+/// Metafunction to test if a class has a type_id.
 template <class T, class Enable=void> struct has_type_id : public false_type {};
-template <class T> struct has_type_id<T, typename enable_if<!!type_id_of<T>::value>::type>  : public true_type {};
+template <class T> struct has_type_id<T, typename type_id_of<T>::type>  : public true_type {};
 
 // Map arbitrary integral types to known AMQP integral types.
 template<size_t SIZE, bool IS_SIGNED> struct integer_type;
@@ -129,41 +132,22 @@ template <class T> struct is_unknown_integer {
     static const bool value = !has_type_id<T>::value && is_integral<T>::value;
 };
 
-namespace is_encodable_impl {   // Protected the world from wildcard operator<<
-
-typedef char yes;
-typedef double no;
-struct wildcard { wildcard(...); };
-
-no operator<<(wildcard, wildcard); // Fallback
-
-template<typename T> struct is_encodable {
-    static yes test(encoder);
-    static no test(...);         // Failed test, no match.
-    static encoder &e;
-    static const T& t;
-    static bool const value = sizeof(test(e << t)) == sizeof(yes);
+// Helper base for SFINAE test templates.
+struct sfinae {
+    typedef char yes;
+    typedef double no;
+    struct wildcard { wildcard(...); };
 };
-// Avoid recursion
-template <> struct is_encodable<value> : public true_type {};
-
-} // namespace is_encodable_impl
-
-/// is_encodable<T>::value is true if there is an operator<< for encoder and T.
-using is_encodable_impl::is_encodable;
 
-/// An enabler template for C++ values that can be converted to AMQP values.
-template<class T, class U=void> struct enable_amqp_type :
-        public enable_if<is_encodable<T>::value, U> {};
-
-/// Enabler for encodable types excluding proton::value.
-template<class T, class U=void> struct assignable : enable_amqp_type<T, U> {};
-template<class U> struct assignable<value, U> : public false_type {};
-/// An enabler for integer types that are not directly AMQP types.
-template <class T, class U=void> struct enable_unknown_integer :
-        public enable_if<is_unknown_integer<T>::value, U> {};
+template <class From, class To> struct is_convertible : public sfinae {
+    static yes test(const To&);
+    static no test(...);
+    static const From& from;
+    static bool const value = sizeof(test(from)) == sizeof(yes);
+};
 
 } // internal
 } // proton
+//@endcond
 
 #endif // PROTON_TYPE_TRAITS_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 bb2017b..66f0f93 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -22,8 +22,90 @@
 ///@file
 ///
 /// Include the definitions of all proton types used to represent AMQP types.
-/// Provided for convenience, you can include types individually instead.
 
+/**@page types AMQP and C++ types
+
+@details
+
+An AMQP message body can hold binary data using any encoding you like. AMQP also
+defines its own encoding and types. The AMQP encoding is often used in message
+bodies because it is supported by AMQP libraries on many languages and
+platforms. You also need to use the AMQP types to set and examine message
+properties.
+
+## Scalar types
+
+Each type is identified by a proton::type_id.
+
+C++ type            | AMQP type_id         | Description
+--------------------|----------------------|-----------------------
+bool                | proton::BOOLEAN      | Boolean true/false
+uint8_t             | proton::UBYTE        | 8 bit unsigned byte
+int8_t              | proton::BYTE         | 8 bit signed byte
+uint16_t            | proton::USHORT       | 16 bit unsigned integer
+int16_t             | proton::SHORT        | 16 bit signed integer
+uint32_t            | proton::UINT         | 32 bit unsigned integer
+int32_t             | proton::INT          | 32 bit signed integer
+uint64_t            | proton::ULONG        | 64 bit unsigned integer
+int64_t             | proton::LONG         | 64 bit signed integer
+wchar_t             | proton::CHAR         | 32 bit unicode code point
+float               | proton::FLOAT        | 32 bit binary floating point
+double              | proton::DOUBLE       | 64 bit binary floating point
+proton::timestamp   | proton::TIMESTAMP    | 64 bit signed milliseconds since 00:00:00 (UTC), 1 January 1970.
+proton::decimal32   | proton::DECIMAL32    | 32 bit decimal floating point
+proton::decimal64   | proton::DECIMAL64    | 64 bit decimal floating point
+proton::decimal128  | proton::DECIMAL128   | 128 bit decimal floating point
+proton::uuid        | proton::UUID         | 128 bit universally-unique identifier
+std::string         | proton::STRING       | UTF-8 encoded unicode string
+proton::symbol      | proton::SYMBOL       | 7-bit ASCII encoded string
+proton::binary      | proton::BINARY       | Variable-length binary data
+
+proton::scalar is a holder that can hold a scalar value of any type.
+
+## Compound types
+
+C++ type            | AMQP type_id         | Description
+--------------------|----------------------|-----------------------
+see below           | proton::ARRAY        | Sequence of values of the same type
+see below           | proton::LIST         | Sequence of values of mixed types
+see below           | proton::MAP          | Map of key/value pairs
+
+proton::value is a holder that can hold any AMQP value, scalar or compound
+
+proton::ARRAY converts to/from C++ sequences: std::vector, std::deque, std::list and
+std::forward_list.
+
+proton::LIST converts to/from sequences of proton::value or proton::scalar,
+which can hold mixed types of data.
+
+proton::MAP converts to/from std::map, std::unordered_map and sequences of
+std::pair. 
+
+When decoding the encoded map types must be convertible to element type of the
+C++ sequence or the key/value types of the C++ map. Use proton::value as the
+element or key/value type to decode any ARRAY/LIST/MAP.
+
+For example you can decode any AMQP MAP into:
+
+    std::map<proton::value, proton::value>
+
+You can decode any AMQP LIST or ARRAY into
+
+    std::vector<proton::value>
+
+## Include files
+
+You can simply include proton/types.hpp to include all the type definitions and
+conversions. Alternatively, you can selectively include only what you need:
+
+ - proton/types_fwd.hpp: forward declarations for all types.
+ - proton/list.hpp, proton/vector.hpp etc.: conversions for std::list, std::vector etc.
+ - include individual .hpp files as per the table above.
+*/
+
+// TODO aconway 2016-03-15: described types, described arrays.
+
+#include <proton/annotation_key.hpp>
 #include <proton/binary.hpp>
 #include <proton/config.hpp>
 #include <proton/decimal.hpp>
@@ -31,6 +113,7 @@
 #include <proton/duration.hpp>
 #include <proton/list.hpp>
 #include <proton/map.hpp>
+#include <proton/message_id.hpp>
 #include <proton/scalar.hpp>
 #include <proton/symbol.hpp>
 #include <proton/timestamp.hpp>
@@ -39,9 +122,6 @@
 #include <proton/value.hpp>
 #include <proton/vector.hpp>
 
-#include <proton/annotation_key.hpp>
-#include <proton/message_id.hpp>
-
 #include <proton/config.hpp>
 #if PN_CPP_HAS_CPP11
 #include <proton/forward_list.hpp>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/types_fwd.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/types_fwd.hpp b/proton-c/bindings/cpp/include/proton/types_fwd.hpp
index 0eca2ed..77e2bf3 100644
--- a/proton-c/bindings/cpp/include/proton/types_fwd.hpp
+++ b/proton-c/bindings/cpp/include/proton/types_fwd.hpp
@@ -24,9 +24,13 @@
 ///
 /// Forward declarations for all the C++ types used by proton to represent AMQP types.
 
+#include <proton/config.hpp>
+
 #include <proton/type_compat.h>
+
 #include <string>
 
+/// The proton namespace
 namespace proton {
 
 class binary;
@@ -40,8 +44,13 @@ class duration;
 class uuid;
 class uuid;
 class value;
-struct null {};
 
+struct null {
+    null() {}
+#if PN_CPP_HAS_CPP11
+    null(std::nullptr_t) {}
+#endif
+};
 }
 
 #endif // PROTON_TYPES_FWD_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/url.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/url.hpp b/proton-c/bindings/cpp/include/proton/url.hpp
index c863971..869692c 100644
--- a/proton-c/bindings/cpp/include/proton/url.hpp
+++ b/proton-c/bindings/cpp/include/proton/url.hpp
@@ -33,7 +33,7 @@ namespace proton {
 struct
 PN_CPP_CLASS_EXTERN url_error : public error {
     /// @cond INTERNAL
-    PN_CPP_EXTERN explicit url_error(const std::string&);
+    PN_CPP_EXTERN explicit url_error(const std::string&); ///< Construct with message
     /// @endcond
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 e0b7317..fb3c5a3 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -49,38 +49,33 @@ class value_base {
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const value_base&);
 };
 
-/// A holder for any single AMQP value, simple or complex (can be list, array, map etc.)
-///
-/// @see proton::amqp for conversions rules between C++ and AMQP types.
-///
+/// A holder for any AMQP value, simple or complex, see @ref types.
 class value : public value_base, private comparable<value> {
+  private:
+    // Enabler for encodable types excluding proton::value.
+    template<class T, class U=void> struct assignable :
+        public internal::enable_if<codec::is_encodable<T>::value, U> {};
+    template<class U> struct assignable<value, U> {};
+
   public:
-    /// Create a null value.
+    /// Create a null value
     PN_CPP_EXTERN value();
-    /// Create a null value.
-    PN_CPP_EXTERN value(const null&);
 
-    /// Copy a value.
+    ///@name Copy a value
+    ///@{
     PN_CPP_EXTERN value(const value&);
     PN_CPP_EXTERN value& operator=(const value&);
 #if PN_CPP_HAS_CPP11
     PN_CPP_EXTERN value(value&&);
     PN_CPP_EXTERN value& operator=(value&&);
 #endif
+    ///@}
 
-    ///@internal
-    PN_CPP_EXTERN explicit value(const codec::data&);
+    /// Construct from any allowed type T, see @ref types.
+    template <class T> value(const T& x, typename assignable<T>::type* = 0) { *this = x; }
 
-    /// Construct from any allowed type T. @see proton::amqp for allowed types.
-    template <class T> value(const T& x, typename codec::assignable<T>::type* = 0) {
-        codec::encoder e(*this);
-        e << x;
-    }
-    PN_CPP_EXTERN value& operator=(const null&);
-
-    /// Assign from any encodable type T. @see proton::amqp for encodable types.
-    template <class T>
-    typename codec::assignable<T, value&>::type operator=(const T& x) {
+    /// Assign from any allowed type T, see @ref types.
+    template <class T> typename assignable<T, value&>::type operator=(const T& x) {
         codec::encoder e(*this);
         e << x;
         return *this;
@@ -89,40 +84,55 @@ class value : public value_base, private comparable<value> {
     /// Reset the value to null
     PN_CPP_EXTERN void clear();
 
-    /// @name Get methods
-    ///
-    /// Extract the value to type T.
-    ///
-    /// @{
-
-    /// Get the value.
-    template<class T> void get(T &t) const { codec::decoder d(*this); d >> t; }
-
-    PN_CPP_EXTERN void get(null&) const;
-    /// @}
-
-    /// Get the value as C++ type T.
-    template<class T> T get() const { T t; get(t); return t; }
-
-    /// @name As methods
-    ///
-    /// As methods do "loose" conversion, they will convert the scalar
-    /// value to the requested type if possible, else throw conversion_error.
-    ///
-    /// @{
-    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())`
-    /// @}
+    ///@cond INTERNAL (deprecated)
+    template<class T> void get(T &t) const;
+    template<class T> T get() const;
+    PN_CPP_EXTERN int64_t as_int() const;
+    PN_CPP_EXTERN uint64_t as_uint() const;
+    PN_CPP_EXTERN double as_double() const;
+    PN_CPP_EXTERN std::string as_string() const;
+    ///@endcond
 
+    /// swap values
   friend PN_CPP_EXTERN void swap(value&, value&);
+    ///@name Comparison operators
+    ///@{
   friend PN_CPP_EXTERN bool operator==(const value& x, const value& y);
   friend PN_CPP_EXTERN bool operator<(const value& x, const value& y);
-};
+    ///@}
 
-template<class T> T get(const value_base& v) { return codec::decoder(v).extract<T>(); }
+    ///@cond INTERNAL
+    PN_CPP_EXTERN explicit value(const codec::data&);
+    ///@endcond
+};
 
+///@copydoc scalar::get
+///@related proton::value
+template<class T> T get(const value& v) { T x; get(v, x); return x; }
+
+/// Like get(const value&) but assigns the value to a reference instead of returning it.
+/// May be more efficient for complex values (arrays, maps etc.)
+///@related proton::value
+template<class T> void get(const value& v, T& x) { codec::decoder d(v, true); d >> x; }
+
+///@copydoc scalar::coerce
+///@related proton::value
+template<class T> T coerce(const value& v) { T x; coerce(v, x); return x; }
+
+/// Like coerce(const value&) but assigns the value to a reference instead of returning it.
+/// May be more efficient for complex values (arrays, maps etc.)
+///@related proton::value
+template<class T> void coerce(const value& v, T& x) { codec::decoder d(v, false); d >> x; }
+
+///@cond INTERNAL
+template<> inline void get<null>(const value& v, null&) { assert_type_equal(NULL_TYPE, v.type()); }
+template<class T> void value::get(T &x) const { x = proton::get<T>(*this); }
+template<class T> T value::get() const { return proton::get<T>(*this); }
+inline int64_t value::as_int() const { return proton::coerce<int64_t>(*this); }
+inline uint64_t value::as_uint() const { return proton::coerce<uint64_t>(*this); }
+inline double value::as_double() const { return proton::coerce<double>(*this); }
+inline std::string value::as_string() const { return proton::coerce<std::string>(*this); }
+///@endcond
 
 } // proton
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/vector.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/vector.hpp b/proton-c/bindings/cpp/include/proton/vector.hpp
index 350960d..1e04b0d 100644
--- a/proton-c/bindings/cpp/include/proton/vector.hpp
+++ b/proton-c/bindings/cpp/include/proton/vector.hpp
@@ -30,7 +30,7 @@ namespace codec {
 
 /// Encode std::vector<T> as amqp::ARRAY (same type elements)
 template <class T, class A> encoder& operator<<(encoder& e, const std::vector<T, A>& x) {
-    return e << encoder::array(x, type_id_of<T>::value);
+    return e << encoder::array(x, internal::type_id_of<T>::value);
 }
 
 /// Encode std::vector<value> encode as amqp::LIST (mixed type elements)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 890fac5..ba94c00 100644
--- a/proton-c/bindings/cpp/src/decoder.cpp
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -23,6 +23,7 @@
 #include <proton/decimal.hpp>
 #include <proton/encoder.hpp>
 #include <proton/message_id.hpp>
+#include <proton/scalar.hpp>
 #include <proton/symbol.hpp>
 #include <proton/timestamp.hpp>
 #include <proton/value.hpp>
@@ -42,7 +43,7 @@ namespace codec {
  * to be returned by the decoder.
  */
 
-decoder::decoder(const value_base& v) : data(v.data()) { rewind(); }
+decoder::decoder(const value_base& v, bool exact) : data(v.data()), exact_(exact) { rewind(); }
 
 namespace {
 template <class T> T check(T result) {
@@ -80,8 +81,6 @@ void assign(uuid& x, const pn_uuid_t y) { byte_copy(x, y); }
 void assign(decimal32& x, const pn_decimal32_t y) { byte_copy(x, y); }
 void assign(decimal64& x, const pn_decimal64_t y)  { byte_copy(x, y); }
 void assign(decimal128& x, const pn_decimal128_t y) { byte_copy(x, y); }
-void
-assign(std::string& x, const pn_bytes_t y) { x = str(y); }
 void assign(symbol& x, const pn_bytes_t y) { x = str(y); }
 void assign(binary& x, const pn_bytes_t y) { x = bin(y); }
 
@@ -91,7 +90,7 @@ void assign(binary& x, const pn_bytes_t y) { x = bin(y); }
 // Simple extract with no type conversion.
 template <class T, class U> decoder& decoder::extract(T& x, U (*get)(pn_data_t*)) {
     state_guard sg(*this);
-    assert_type_equal(type_id_of<T>::value, pre_get());
+    assert_type_equal(internal::type_id_of<T>::value, pre_get());
     assign(x, get(pn_object()));
     sg.cancel();                // No error, cancel the reset.
     return *this;
@@ -144,35 +143,37 @@ decoder& decoder::operator>>(value_base& x) {
         throw conversion_error("extract into self");
     data d = x.data();
     d.clear();
-    {
-        narrow_guard n(*this);
+    narrow();
+    try {
         check(d.appendn(*this, 1));
+        widen();
+    } catch(...) {
+        widen();
+        throw;
     }
     next();
     return *this;
 }
 
 decoder& decoder::operator>>(message_id& x) {
-    switch (next_type()) {
-      case ULONG:
-      case UUID:
-      case BINARY:
-      case STRING:
-        return *this >> x.scalar_;
-      default:
+    state_guard sg(*this);
+    type_id got = pre_get();
+    if (got != ULONG && got != UUID && got != BINARY && got != STRING)
         throw conversion_error(
-            msg() << "expected one of ulong, uuid, binary or string but found " << next_type());
-    };
+            msg() << "expected one of ulong, uuid, binary or string but found " << got);
+    x.set(pn_data_get_atom(pn_object()));
+    sg.cancel();
+    return *this;
 }
 
 decoder& decoder::operator>>(annotation_key& x) {
-    switch (next_type()) {
-      case ULONG:
-      case SYMBOL:
-        return *this >> x.scalar_;
-      default:
-        throw conversion_error("expected one of ulong or symbol but found " + type_name(next_type()));
-    };
+    state_guard sg(*this);
+    type_id got = pre_get();
+    if (got != ULONG && got != SYMBOL)
+        throw conversion_error(msg() << "expected one of ulong or symbol but found " << got);
+    x.set(pn_data_get_atom(pn_object()));
+    sg.cancel();
+    return *this;
 }
 
 decoder& decoder::operator>>(scalar& x) {
@@ -187,32 +188,18 @@ decoder& decoder::operator>>(scalar& x) {
 
 decoder& decoder::operator>>(bool &x) { return extract(x, pn_data_get_bool); }
 
-decoder& decoder::operator>>(uint8_t &x) {
-    state_guard sg(*this);
-    switch (pre_get()) {
-      case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
-      default: assert_type_equal(UBYTE, type_id(type_id(pn_data_type(pn_object()))));
-    }
-    sg.cancel();
-    return *this;
-}
+decoder& decoder::operator>>(uint8_t &x)  { return extract(x, pn_data_get_ubyte); }
 
-decoder& decoder::operator>>(int8_t &x) {
-    state_guard sg(*this);
-    switch (pre_get()) {
-      case BYTE: x = pn_data_get_byte(pn_object()); break;
-      default: assert_type_equal(BYTE, type_id(type_id(pn_data_type(pn_object()))));
-    }
-    sg.cancel();
-    return *this;
-}
+decoder& decoder::operator>>(int8_t &x) { return extract(x, pn_data_get_byte); }
 
 decoder& decoder::operator>>(uint16_t &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(USHORT, tid);
+    switch (tid) {
       case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
       case USHORT: x = pn_data_get_ushort(pn_object()); break;
-      default: assert_type_equal(USHORT, type_id(type_id(pn_data_type(pn_object()))));
+      default: assert_type_equal(USHORT, tid);
     }
     sg.cancel();
     return *this;
@@ -220,10 +207,12 @@ decoder& decoder::operator>>(uint16_t &x) {
 
 decoder& decoder::operator>>(int16_t &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(SHORT, tid);
+    switch (tid) {
       case BYTE: x = pn_data_get_byte(pn_object()); break;
       case SHORT: x = pn_data_get_short(pn_object()); break;
-      default: assert_type_equal(SHORT, type_id(pn_data_type(pn_object())));
+      default: assert_type_equal(SHORT, tid);
     }
     sg.cancel();
     return *this;
@@ -231,11 +220,13 @@ decoder& decoder::operator>>(int16_t &x) {
 
 decoder& decoder::operator>>(uint32_t &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(UINT, tid);
+    switch (tid) {
       case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
       case USHORT: x = pn_data_get_ushort(pn_object()); break;
       case UINT: x = pn_data_get_uint(pn_object()); break;
-      default: assert_type_equal(UINT, type_id(pn_data_type(pn_object())));
+      default: assert_type_equal(UINT, tid);
     }
     sg.cancel();
     return *this;
@@ -243,11 +234,13 @@ decoder& decoder::operator>>(uint32_t &x) {
 
 decoder& decoder::operator>>(int32_t &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(INT, tid);
+    switch (tid) {
       case BYTE: x = pn_data_get_byte(pn_object()); break;
       case SHORT: x = pn_data_get_short(pn_object()); break;
       case INT: x = pn_data_get_int(pn_object()); break;
-      default: assert_type_equal(INT, type_id(pn_data_type(pn_object())));
+      default: assert_type_equal(INT, tid);
     }
     sg.cancel();
     return *this;
@@ -255,12 +248,14 @@ decoder& decoder::operator>>(int32_t &x) {
 
 decoder& decoder::operator>>(uint64_t &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(ULONG, tid);
+    switch (tid) {
       case UBYTE: x = pn_data_get_ubyte(pn_object()); break;
       case USHORT: x = pn_data_get_ushort(pn_object()); break;
       case UINT: x = pn_data_get_uint(pn_object()); break;
       case ULONG: x = pn_data_get_ulong(pn_object()); break;
-      default: assert_type_equal(ULONG, type_id(pn_data_type(pn_object())));
+      default: assert_type_equal(ULONG, tid);
     }
     sg.cancel();
     return *this;
@@ -268,12 +263,14 @@ decoder& decoder::operator>>(uint64_t &x) {
 
 decoder& decoder::operator>>(int64_t &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(LONG, tid);
+    switch (tid) {
       case BYTE: x = pn_data_get_byte(pn_object()); break;
       case SHORT: x = pn_data_get_short(pn_object()); break;
       case INT: x = pn_data_get_int(pn_object()); break;
       case LONG: x = pn_data_get_long(pn_object()); break;
-      default: assert_type_equal(LONG, type_id(pn_data_type(pn_object())));
+      default: assert_type_equal(LONG, tid);
     }
     sg.cancel();
     return *this;
@@ -285,10 +282,12 @@ decoder& decoder::operator>>(timestamp &x) { return extract(x, pn_data_get_times
 
 decoder& decoder::operator>>(float &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(FLOAT, tid);
+    switch (tid) {
       case FLOAT: x = pn_data_get_float(pn_object()); break;
       case DOUBLE: x = float(pn_data_get_double(pn_object())); break;
-      default: assert_type_equal(FLOAT, type_id(pn_data_type(pn_object())));
+      default: assert_type_equal(FLOAT, tid);
     }
     sg.cancel();
     return *this;
@@ -296,10 +295,12 @@ decoder& decoder::operator>>(float &x) {
 
 decoder& decoder::operator>>(double &x) {
     state_guard sg(*this);
-    switch (pre_get()) {
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(DOUBLE, tid);
+    switch (tid) {
       case FLOAT: x = pn_data_get_float(pn_object()); break;
       case DOUBLE: x = pn_data_get_double(pn_object()); break;
-      default: assert_type_equal(DOUBLE, type_id(pn_data_type(pn_object())));
+      default: assert_type_equal(DOUBLE, tid);
     }
     sg.cancel();
     return *this;
@@ -312,7 +313,19 @@ decoder& decoder::operator>>(decimal128 &x)  { return extract(x, pn_data_get_dec
 decoder& decoder::operator>>(uuid &x)  { return extract(x, pn_data_get_uuid); }
 decoder& decoder::operator>>(binary &x)  { return extract(x, pn_data_get_binary); }
 decoder& decoder::operator>>(symbol &x)  { return extract(x, pn_data_get_symbol); }
-decoder& decoder::operator>>(std::string &x)  { return extract(x, pn_data_get_string); }
+
+decoder& decoder::operator>>(std::string &x)  {
+    state_guard sg(*this);
+    type_id tid = pre_get();
+    if (exact_) assert_type_equal(STRING, tid);
+    switch (tid) {
+      case STRING: x = str(pn_data_get_string(pn_object())); break;
+      case SYMBOL: x = str(pn_data_get_symbol(pn_object())); break;
+      default: assert_type_equal(STRING, tid);
+    }
+    sg.cancel();
+    return *this;
+}
 
 } // codec
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 538decc..2952d0e 100644
--- a/proton-c/bindings/cpp/src/encoder.cpp
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -27,6 +27,7 @@
 #include <proton/decimal.hpp>
 #include <proton/encoder.hpp>
 #include <proton/message_id.hpp>
+#include <proton/scalar_base.hpp>
 #include <proton/symbol.hpp>
 #include <proton/timestamp.hpp>
 #include <proton/value.hpp>
@@ -100,11 +101,11 @@ encoder& encoder::operator<<(const finish&) {
 
 namespace {
 
-template <class T, class U> T convert(const U &x) { return x; }
-template <> pn_uuid_t convert(const uuid& x) { pn_uuid_t y; byte_copy(y, x); return  y; }
-template <> pn_decimal32_t convert(const decimal32 &x) { pn_decimal32_t y; byte_copy(y, x); return  y; }
-template <> pn_decimal64_t convert(const decimal64 &x) { pn_decimal64_t y; byte_copy(y, x); return  y; }
-template <> pn_decimal128_t convert(const decimal128 &x) { pn_decimal128_t y; byte_copy(y, x); return  y; }
+template <class T, class U> T coerce(const U &x) { return x; }
+template <> pn_uuid_t coerce(const uuid& x) { pn_uuid_t y; byte_copy(y, x); return  y; }
+template <> pn_decimal32_t coerce(const decimal32 &x) { pn_decimal32_t y; byte_copy(y, x); return  y; }
+template <> pn_decimal64_t coerce(const decimal64 &x) { pn_decimal64_t y; byte_copy(y, x); return  y; }
+template <> pn_decimal128_t coerce(const decimal128 &x) { pn_decimal128_t y; byte_copy(y, x); return  y; }
 
 int pn_data_put_amqp_string(pn_data_t *d, const std::string& x) { return pn_data_put_string(d, pn_bytes(x)); }
 int pn_data_put_amqp_binary(pn_data_t *d, const binary& x) { return pn_data_put_binary(d, pn_bytes(x)); }
@@ -114,7 +115,7 @@ int pn_data_put_amqp_symbol(pn_data_t *d, const symbol& x) { return pn_data_put_
 template <class T, class U>
 encoder& encoder::insert(const T& x, int (*put)(pn_data_t*, U)) {
     state_guard sg(*this);         // Save state in case of error.
-    check(put(pn_object(), convert<U>(x)));
+    check(put(pn_object(), coerce<U>(x)));
     sg.cancel();                // Don't restore state, all is good.
     return *this;
 }
@@ -139,14 +140,16 @@ encoder& encoder::operator<<(const uuid& x) { return insert(x, pn_data_put_uuid)
 encoder& encoder::operator<<(const std::string& x) { return insert(x, pn_data_put_amqp_string); }
 encoder& encoder::operator<<(const symbol& x) { return insert(x, pn_data_put_amqp_symbol); }
 encoder& encoder::operator<<(const binary& x) { return insert(x, pn_data_put_amqp_binary); }
+encoder& encoder::operator<<(const null&) { pn_data_put_null(pn_object()); return *this; }
 
-encoder& encoder::operator<<(const scalar& x) { return insert(x.atom_, pn_data_put_atom); }
+encoder& encoder::operator<<(const scalar_base& x) { return insert(x.atom_, pn_data_put_atom); }
 
 encoder& encoder::operator<<(const value_base& x) {
     if (*this == x.data_)
         throw conversion_error("cannot insert into self");
-    if (x.empty())
-        pn_data_put_null(pn_object());
+    if (x.empty()) {
+        return *this << null();
+    }
     data d = x.data();
     d.rewind();
     check(append(d));

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 b05c098..abe7cb8 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -42,13 +42,6 @@ string read(string filename) {
     return string(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
 }
 
-template <class T> T get(decoder& d) {
-    assert_type_equal(type_id_of<T>::value, d.next_type());
-    T v;
-    d >> v;
-    return v;
-}
-
 // Test data ostream operator
 void test_data_ostream() {
     value dv;
@@ -98,19 +91,6 @@ void test_encoder_primitives() {
     ASSERT_EQUAL(read("primitives"), data);
 }
 
-// Test type conversions.
-void test_value_conversions() {
-    value v;
-    ASSERT_EQUAL(true, (v=true).get<bool>());
-    ASSERT_EQUAL(2, (v=int8_t(2)).get<int>());
-    ASSERT_EQUAL(3, (v=int8_t(3)).get<long>());
-    ASSERT_EQUAL(3, (v=int8_t(3)).get<long>());
-    ASSERT_EQUAL(1.0, (v=float(1.0)).get<double>());
-    ASSERT_EQUAL(1.0, (v=double(1.0)).get<float>());
-    try { (void)(v = int8_t(1)).get<bool>(); FAIL("got byte as bool"); } catch (conversion_error) {}
-    try { (void)(v = true).get<float>(); FAIL("got bool as float"); } catch (conversion_error) {}
-}
-
 // TODO aconway 2015-06-11: interop test is not complete.
 
 int main(int argc, char** argv) {
@@ -124,6 +104,5 @@ int main(int argc, char** argv) {
     RUN_TEST(failed, test_data_ostream());
     RUN_TEST(failed, test_decoder_primitves_exact());
     RUN_TEST(failed, test_encoder_primitives());
-    RUN_TEST(failed, test_value_conversions());
     return failed;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 6d95256..e00218a 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -87,7 +87,7 @@ void check(int err) {
 }
 } // namespace
 
-void message::id(const message_id& id) { pn_message_set_id(pn_msg(), id.scalar_.atom_); }
+void message::id(const message_id& id) { pn_message_set_id(pn_msg(), id.atom_); }
 
 message_id message::id() const {
     return pn_message_get_id(pn_msg());
@@ -130,7 +130,7 @@ std::string message::reply_to() const {
 
 void message::correlation_id(const message_id& id) {
     codec::encoder e(pn_message_correlation_id(pn_msg()));
-    e << id.scalar_;
+    e << id;
 }
 
 message_id message::correlation_id() const {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/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 8c1e585..bfdbb06 100644
--- a/proton-c/bindings/cpp/src/message_test.cpp
+++ b/proton-c/bindings/cpp/src/message_test.cpp
@@ -40,7 +40,7 @@ using namespace test;
 
 void test_message_properties() {
     message m("hello");
-    std::string s = m.body().get<std::string>();
+    std::string s = get<std::string>(m.body());
     ASSERT_EQUAL("hello", s);
 
     CHECK_MESSAGE_ID(id);
@@ -59,7 +59,7 @@ void test_message_properties() {
     ASSERT_EQUAL(m.creation_time().ms(), 4242);
 
     message m2(m);
-    ASSERT_EQUAL("hello", m2.body().get<std::string>());
+    ASSERT_EQUAL("hello", get<std::string>(m2.body()));
     ASSERT_EQUAL(message_id("id"), m2.id());
     ASSERT_EQUAL("user_id", m2.user_id());
     ASSERT_EQUAL("address", m2.address());
@@ -74,7 +74,7 @@ void test_message_properties() {
     ASSERT_EQUAL(4242, m.creation_time().ms());
 
     m2 = m;
-    ASSERT_EQUAL("hello", m2.body().get<std::string>());
+    ASSERT_EQUAL("hello", get<std::string>(m2.body()));
     ASSERT_EQUAL(message_id("id"), m2.id());
     ASSERT_EQUAL("user_id", m2.user_id());
     ASSERT_EQUAL("address", m2.address());
@@ -92,14 +92,14 @@ void test_message_properties() {
 void test_message_body() {
     std::string s("hello");
     message m1(s.c_str());
-    ASSERT_EQUAL(s, m1.body().get<std::string>());
+    ASSERT_EQUAL(s, get<std::string>(m1.body()));
     message m2(s);
-    ASSERT_EQUAL(s, m2.body().as_string());
+    ASSERT_EQUAL(s, coerce<std::string>(m2.body()));
     message m3;
     m3.body(s);
-    ASSERT_EQUAL(s, m3.body().as_string());
-    ASSERT_EQUAL(5, message(5).body().as_int());
-    ASSERT_EQUAL(3.1, message(3.1).body().as_double());
+    ASSERT_EQUAL(s, coerce<std::string>(m3.body()));
+    ASSERT_EQUAL(5, coerce<int64_t>(message(5).body()));
+    ASSERT_EQUAL(3.1, coerce<double>(message(3.1).body()));
 }
 
 void test_message_maps() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/src/scalar.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar.cpp b/proton-c/bindings/cpp/src/scalar.cpp
deleted file mode 100644
index b862af0..0000000
--- a/proton-c/bindings/cpp/src/scalar.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "msg.hpp"
-#include "types_internal.hpp"
-
-#include "proton/binary.hpp"
-#include "proton/decimal.hpp"
-#include "proton/scalar.hpp"
-#include "proton/symbol.hpp"
-#include "proton/timestamp.hpp"
-#include "proton/type_traits.hpp"
-#include "proton/uuid.hpp"
-
-#include <ostream>
-
-namespace proton {
-
-scalar::scalar() { atom_.type = PN_NULL; }
-scalar::scalar(const pn_atom_t& a) { set(a); }
-scalar::scalar(const scalar& x) { set(x.atom_); }
-
-scalar& scalar::operator=(const scalar& x) {
-    if (this != &x)
-        set(x.atom_);
-    return *this;
-}
-
-type_id scalar::type() const { return type_id(atom_.type); }
-
-bool scalar::empty() const { return type() == NULL_TYPE; }
-
-void scalar::set(const binary& x, pn_type_t t) {
-    atom_.type = t;
-    bytes_ = x;
-    atom_.u.as_bytes = pn_bytes(bytes_);
-}
-
-void scalar::set(const pn_atom_t& atom) {
-    if (type_id_is_string_like(type_id(atom.type)))
-        set(bin(atom.u.as_bytes), atom.type);
-    else
-        atom_ = atom;
-}
-
-scalar::scalar(bool x) { *this = x; }
-scalar::scalar(uint8_t x) { *this = x; }
-scalar::scalar(int8_t x) { *this = x; }
-scalar::scalar(uint16_t x) { *this = x; }
-scalar::scalar(int16_t x) { *this = x; }
-scalar::scalar(uint32_t x) { *this = x; }
-scalar::scalar(int32_t x) { *this = x; }
-scalar::scalar(uint64_t x) { *this = x; }
-scalar::scalar(int64_t x) { *this = x; }
-scalar::scalar(wchar_t x) { *this = x; }
-scalar::scalar(float x) { *this = x; }
-scalar::scalar(double x) { *this = x; }
-scalar::scalar(timestamp x) { *this = x; }
-scalar::scalar(const decimal32& x) { *this = x; }
-scalar::scalar(const decimal64& x) { *this = x; }
-scalar::scalar(const decimal128& x) { *this = x; }
-scalar::scalar(const uuid& x) { *this = x; }
-scalar::scalar(const std::string& x) { *this = x; }
-scalar::scalar(const symbol& x) { *this = x; }
-scalar::scalar(const binary& x) { *this = x; }
-scalar::scalar(const char* x) { *this = x; }
-
-scalar& scalar::operator=(bool x) { atom_.u.as_bool = x; atom_.type = PN_BOOL; return *this; }
-scalar& scalar::operator=(uint8_t x) { atom_.u.as_ubyte = x; atom_.type = PN_UBYTE; return *this; }
-scalar& scalar::operator=(int8_t x) { atom_.u.as_byte = x; atom_.type = PN_BYTE; return *this; }
-scalar& scalar::operator=(uint16_t x) { atom_.u.as_ushort = x; atom_.type = PN_USHORT; return *this; }
-scalar& scalar::operator=(int16_t x) { atom_.u.as_short = x; atom_.type = PN_SHORT; return *this; }
-scalar& scalar::operator=(uint32_t x) { atom_.u.as_uint = x; atom_.type = PN_UINT; return *this; }
-scalar& scalar::operator=(int32_t x) { atom_.u.as_int = x; atom_.type = PN_INT; return *this; }
-scalar& scalar::operator=(uint64_t x) { atom_.u.as_ulong = x; atom_.type = PN_ULONG; return *this; }
-scalar& scalar::operator=(int64_t x) { atom_.u.as_long = x; atom_.type = PN_LONG; return *this; }
-scalar& scalar::operator=(wchar_t x) { atom_.u.as_char = x; atom_.type = PN_CHAR; return *this; }
-scalar& scalar::operator=(float x) { atom_.u.as_float = x; atom_.type = PN_FLOAT; return *this; }
-scalar& scalar::operator=(double x) { atom_.u.as_double = x; atom_.type = PN_DOUBLE; return *this; }
-scalar& scalar::operator=(timestamp x) { atom_.u.as_timestamp = x.ms(); atom_.type = PN_TIMESTAMP; return *this; }
-
-scalar& scalar::operator=(const decimal32& x) {
-    byte_copy(atom_.u.as_decimal32, x);
-    atom_.type = PN_DECIMAL32;
-    return *this;
-}
-
-scalar& scalar::operator=(const decimal64& x) {
-    byte_copy(atom_.u.as_decimal64, x);
-    atom_.type = PN_DECIMAL64;
-    return *this;
-}
-
-scalar& scalar::operator=(const decimal128& x) {
-    byte_copy(atom_.u.as_decimal128, x);
-    atom_.type = PN_DECIMAL128;
-    return *this;
-}
-
-scalar& scalar::operator=(const uuid& x) {
-    byte_copy(atom_.u.as_uuid, x);
-    atom_.type = PN_UUID;
-    return *this;
-}
-
-scalar& scalar::operator=(const std::string& x) { set(binary(x), PN_STRING); return *this; }
-scalar& scalar::operator=(const symbol& x) { set(binary(x), PN_SYMBOL); return *this; }
-scalar& scalar::operator=(const binary& x) { set(x, PN_BINARY); return *this; }
-scalar& scalar::operator=(const char* x) { set(binary(std::string(x)), PN_STRING); return *this; }
-
-void scalar::ok(pn_type_t t) const {
-    if (atom_.type != t) throw make_conversion_error(type_id(t), type());
-}
-
-void scalar::get(bool& x) const { ok(PN_BOOL); x = atom_.u.as_bool; }
-void scalar::get(uint8_t& x) const { ok(PN_UBYTE); x = atom_.u.as_ubyte; }
-void scalar::get(int8_t& x) const { ok(PN_BYTE); x = atom_.u.as_byte; }
-void scalar::get(uint16_t& x) const { ok(PN_USHORT); x = atom_.u.as_ushort; }
-void scalar::get(int16_t& x) const { ok(PN_SHORT); x = atom_.u.as_short; }
-void scalar::get(uint32_t& x) const { ok(PN_UINT); x = atom_.u.as_uint; }
-void scalar::get(int32_t& x) const { ok(PN_INT); x = atom_.u.as_int; }
-void scalar::get(wchar_t& x) const { ok(PN_CHAR); x = wchar_t(atom_.u.as_char); }
-void scalar::get(uint64_t& x) const { ok(PN_ULONG); x = atom_.u.as_ulong; }
-void scalar::get(int64_t& x) const { ok(PN_LONG); x = atom_.u.as_long; }
-void scalar::get(timestamp& x) const { ok(PN_TIMESTAMP); x = atom_.u.as_timestamp; }
-void scalar::get(float& x) const { ok(PN_FLOAT); x = atom_.u.as_float; }
-void scalar::get(double& x) const { ok(PN_DOUBLE); x = atom_.u.as_double; }
-void scalar::get(decimal32& x) const { ok(PN_DECIMAL32); byte_copy(x, atom_.u.as_decimal32); }
-void scalar::get(decimal64& x) const { ok(PN_DECIMAL64); byte_copy(x, atom_.u.as_decimal64); }
-void scalar::get(decimal128& x) const { ok(PN_DECIMAL128); byte_copy(x, atom_.u.as_decimal128); }
-void scalar::get(uuid& x) const { ok(PN_UUID); byte_copy(x, atom_.u.as_uuid); }
-void scalar::get(std::string& x) const {
-    ok(PN_STRING);
-    x = bytes_.str();
-}
-void scalar::get(symbol& x) const { ok(PN_SYMBOL); x = symbol(bytes_.str()); }
-void scalar::get(binary& x) const { ok(PN_BINARY); x = bytes_; }
-
-int64_t scalar::as_int() const {
-    if (type_id_is_floating_point(type()))
-        return int64_t(as_double());
-    switch (atom_.type) {
-      case PN_BOOL: return atom_.u.as_bool;
-      case PN_UBYTE: return atom_.u.as_ubyte;
-      case PN_BYTE: return atom_.u.as_byte;
-      case PN_USHORT: return atom_.u.as_ushort;
-      case PN_SHORT: return atom_.u.as_short;
-      case PN_UINT: return atom_.u.as_uint;
-      case PN_INT: return atom_.u.as_int;
-      case PN_CHAR: return atom_.u.as_char;
-      case PN_ULONG: return int64_t(atom_.u.as_ulong);
-      case PN_LONG: return atom_.u.as_long;
-      case PN_TIMESTAMP: return atom_.u.as_timestamp;
-      default: throw make_conversion_error(LONG, type());
-    }
-}
-
-uint64_t scalar::as_uint() const {
-    if  (!type_id_is_integral(type()))
-        throw make_conversion_error(ULONG, type());
-    return uint64_t(as_int());
-}
-
-double scalar::as_double() const {
-    if (type_id_is_integral(type())) {
-        return type_id_is_signed(type()) ? double(as_int()) : double(as_uint());
-    }
-    switch (atom_.type) {
-      case PN_DOUBLE: return atom_.u.as_double;
-      case PN_FLOAT: return atom_.u.as_float;
-      default: throw make_conversion_error(DOUBLE, type());
-    }
-}
-
-std::string scalar::as_string() const {
-    if (type_id_is_string_like(type()))
-        return bytes_.str();
-    throw make_conversion_error(STRING, type());
-}
-
-namespace {
-
-template <class T, class F> T type_switch(const scalar& a, F f) {
-    switch(a.type()) {
-      case BOOLEAN: return f(a.get<bool>());
-      case UBYTE: return f(a.get<uint8_t>());
-      case BYTE: return f(a.get<int8_t>());
-      case USHORT: return f(a.get<uint16_t>());
-      case SHORT: return f(a.get<int16_t>());
-      case UINT: return f(a.get<uint32_t>());
-      case INT: return f(a.get<int32_t>());
-      case CHAR: return f(a.get<wchar_t>());
-      case ULONG: return f(a.get<uint64_t>());
-      case LONG: return f(a.get<int64_t>());
-      case TIMESTAMP: return f(a.get<timestamp>());
-      case FLOAT: return f(a.get<float>());
-      case DOUBLE: return f(a.get<double>());
-      case DECIMAL32: return f(a.get<decimal32>());
-      case DECIMAL64: return f(a.get<decimal64>());
-      case DECIMAL128: return f(a.get<decimal128>());
-      case UUID: return f(a.get<uuid>());
-      case BINARY: return f(a.get<binary>());
-      case STRING: return f(a.get<std::string>());
-      case SYMBOL: return f(a.get<symbol>());
-      default:
-        throw std::logic_error("bad proton::scalar type");
-    }
-}
-
-struct equal_op {
-    const scalar& a;
-    equal_op(const scalar& a_) : a(a_) {}
-    template<class T> bool operator()(T x) { return x == a.get<T>(); }
-};
-
-struct less_op {
-    const scalar& a;
-    less_op(const scalar& a_) : a(a_) {}
-    template<class T> bool operator()(T x) { return x < a.get<T>(); }
-};
-
-struct ostream_op {
-    std::ostream& o;
-    ostream_op(std::ostream& o_) : o(o_) {}
-    template<class T> std::ostream& operator()(T x) { return o << x; }
-};
-
-} // namespace
-
-bool operator==(const scalar& x, const scalar& y) {
-    if (x.type() != y.type()) return false;
-    if (x.empty()) return true;
-    return type_switch<bool>(x, equal_op(y));
-}
-
-bool operator<(const scalar& x, const scalar& y) {
-    if (x.type() != y.type()) return x.type() < y.type();
-    if (x.empty()) return false;
-    return type_switch<bool>(x, less_op(y));
-}
-
-std::ostream& operator<<(std::ostream& o, const scalar& a) {
-    if (a.empty()) return o << "<null>";
-    return type_switch<std::ostream&>(a, ostream_op(o));
-}
-
-} // namespace proton


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