Add the ability to derive message types from one another.

`DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT` and `DAP_STRUCT_TYPEINFO_EXT` are two new flavors of `DAP_IMPLEMENT_STRUCT_TYPEINFO` and `DAP_STRUCT_TYPEINFO` that allow you to derive message types.

This involved a bit of reworking on the serializer interfaces.

Added test.

Issue: #32
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2bc668c..3231185 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -194,6 +194,7 @@
         ${CPPDAP_SRC_DIR}/network_test.cpp
         ${CPPDAP_SRC_DIR}/optional_test.cpp
         ${CPPDAP_SRC_DIR}/session_test.cpp
+        ${CPPDAP_SRC_DIR}/typeinfo_test.cpp
         ${CPPDAP_SRC_DIR}/variant_test.cpp
         ${CPPDAP_GOOGLETEST_DIR}/googletest/src/gtest-all.cc
     )
diff --git a/include/dap/serialization.h b/include/dap/serialization.h
index 25f774e..998cb37 100644
--- a/include/dap/serialization.h
+++ b/include/dap/serialization.h
@@ -78,10 +78,6 @@
   template <typename T0, typename... Types>
   inline bool deserialize(dap::variant<T0, Types...>*) const;
 
-  // deserialize() decodes a list of fields and stores them into the object.
-  inline bool deserialize(void* object,
-                          const std::initializer_list<Field>&) const;
-
   // deserialize() decodes the struct field f with the given name.
   template <typename T>
   inline bool field(const std::string& name, T* f) const;
@@ -117,20 +113,6 @@
   return deserialize(&var->value);
 }
 
-bool Deserializer::deserialize(
-    void* object,
-    const std::initializer_list<Field>& fields) const {
-  for (auto const& f : fields) {
-    if (!field(f.name, [&](Deserializer* d) {
-          auto ptr = reinterpret_cast<uint8_t*>(object) + f.offset;
-          return f.type->deserialize(d, ptr);
-        })) {
-      return false;
-    }
-  }
-  return true;
-}
-
 template <typename T>
 bool Deserializer::field(const std::string& name, T* v) const {
   return this->field(name,
@@ -140,6 +122,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Serializer
 ////////////////////////////////////////////////////////////////////////////////
+class FieldSerializer;
 
 // Serializer is the interface used to encode data to structured storage.
 // A Serializer is associated with a single storage object, whos type and value
@@ -149,16 +132,12 @@
 // Methods that return a bool use this to indicate success.
 class Serializer {
  public:
-  using FieldSerializer = std::function<bool(Serializer*)>;
-  template <typename T>
-  using IsFieldSerializer = std::is_convertible<T, FieldSerializer>;
-
   // serialization methods for simple data types.
   virtual bool serialize(boolean) = 0;
   virtual bool serialize(integer) = 0;
   virtual bool serialize(number) = 0;
   virtual bool serialize(const string&) = 0;
-  virtual bool serialize(const object&) = 0;
+  virtual bool serialize(const dap::object&) = 0;
   virtual bool serialize(const any&) = 0;
 
   // array() encodes count array elements to the array object referenced by this
@@ -166,14 +145,10 @@
   // Serializer that should be used to encode the n'th array element's data.
   virtual bool array(size_t count, const std::function<bool(Serializer*)>&) = 0;
 
-  // fields() encodes all the provided fields of the given object.
-  virtual bool fields(const void* object,
-                      const std::initializer_list<Field>&) = 0;
-
-  // field() encodes a field to the struct object referenced by this Serializer.
-  // The FieldSerializer will be called with a Serializer used to encode the
-  // field's data.
-  virtual bool field(const std::string& name, const FieldSerializer&) = 0;
+  // object() begins encoding the object referenced by this Serializer.
+  // The std::function will be called with a FieldSerializer to serialize the
+  // object's fields.
+  virtual bool object(const std::function<bool(dap::FieldSerializer*)>&) = 0;
 
   // remove() deletes the object referenced by this Serializer.
   // remove() can be used to serialize optionals with no value assigned.
@@ -198,12 +173,6 @@
 
   // deserialize() encodes the given string.
   inline bool serialize(const char* v);
-
-  // field() encodes the field with the given name and value.
-  template <
-      typename T,
-      typename = typename std::enable_if<!IsFieldSerializer<T>::value>::type>
-  inline bool field(const std::string& name, const T& v);
 };
 
 template <typename T, typename>
@@ -235,8 +204,31 @@
   return serialize(std::string(v));
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// FieldSerializer
+////////////////////////////////////////////////////////////////////////////////
+
+// FieldSerializer is the interface used to serialize fields of an object.
+class FieldSerializer {
+ public:
+  using SerializeFunc = std::function<bool(Serializer*)>;
+  template <typename T>
+  using IsSerializeFunc = std::is_convertible<T, SerializeFunc>;
+
+  // field() encodes a field to the struct object referenced by this Serializer.
+  // The SerializeFunc will be called with a Serializer used to encode the
+  // field's data.
+  virtual bool field(const std::string& name, const SerializeFunc&) = 0;
+
+  // field() encodes the field with the given name and value.
+  template <
+      typename T,
+      typename = typename std::enable_if<!IsSerializeFunc<T>::value>::type>
+  inline bool field(const std::string& name, const T& v);
+};
+
 template <typename T, typename>
-bool Serializer::field(const std::string& name, const T& v) {
+bool FieldSerializer::field(const std::string& name, const T& v) {
   return this->field(name, [&](Serializer* s) { return s->serialize(v); });
 }
 
diff --git a/include/dap/typeof.h b/include/dap/typeof.h
index e2d3cc8..e682ab5 100644
--- a/include/dap/typeof.h
+++ b/include/dap/typeof.h
@@ -136,46 +136,127 @@
 // NAME is the serialized name of the field, as described by the DAP
 // specification.
 #define DAP_FIELD(FIELD, NAME)                       \
-  dap::Field {                                       \
+  ::dap::Field {                                     \
     NAME, DAP_OFFSETOF(StructTy, FIELD),             \
         TypeOf<DAP_TYPEOF(StructTy, FIELD)>::type(), \
   }
 
 // DAP_DECLARE_STRUCT_TYPEINFO() declares a TypeOf<> specialization for STRUCT.
-#define DAP_DECLARE_STRUCT_TYPEINFO(STRUCT)                \
-  template <>                                              \
-  struct TypeOf<STRUCT> {                                  \
-    static constexpr bool has_custom_serialization = true; \
-    static const TypeInfo* type();                         \
+// Must be used within the 'dap' namespace.
+#define DAP_DECLARE_STRUCT_TYPEINFO(STRUCT)                         \
+  template <>                                                       \
+  struct TypeOf<STRUCT> {                                           \
+    static constexpr bool has_custom_serialization = true;          \
+    static const TypeInfo* type();                                  \
+    static bool deserializeFields(const Deserializer*, void* obj);  \
+    static bool serializeFields(FieldSerializer*, const void* obj); \
   }
 
-// DAP_DECLARE_STRUCT_TYPEINFO() implements the type() member function for the
+// DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION() implements the deserializeFields()
+// and serializeFields() static methods of a TypeOf<> specialization. Used
+// internally by DAP_IMPLEMENT_STRUCT_TYPEINFO() and
+// DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT().
+// You probably do not want to use this directly.
+#define DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, ...)           \
+  bool TypeOf<STRUCT>::deserializeFields(const Deserializer* d, void* obj) {  \
+    using StructTy = STRUCT;                                                  \
+    (void)sizeof(StructTy); /* avoid unused 'using' warning */                \
+    for (auto field : std::initializer_list<Field>{__VA_ARGS__}) {            \
+      if (!d->field(field.name, [&](Deserializer* d) {                        \
+            auto ptr = reinterpret_cast<uint8_t*>(obj) + field.offset;        \
+            return field.type->deserialize(d, ptr);                           \
+          })) {                                                               \
+        return false;                                                         \
+      }                                                                       \
+    }                                                                         \
+    return true;                                                              \
+  }                                                                           \
+  bool TypeOf<STRUCT>::serializeFields(FieldSerializer* s, const void* obj) { \
+    using StructTy = STRUCT;                                                  \
+    (void)sizeof(StructTy); /* avoid unused 'using' warning */                \
+    for (auto field : std::initializer_list<Field>{__VA_ARGS__}) {            \
+      if (!s->field(field.name, [&](Serializer* s) {                          \
+            auto ptr = reinterpret_cast<const uint8_t*>(obj) + field.offset;  \
+            return field.type->serialize(s, ptr);                             \
+          })) {                                                               \
+        return false;                                                         \
+      }                                                                       \
+    }                                                                         \
+    return true;                                                              \
+  }
+
+// DAP_IMPLEMENT_STRUCT_TYPEINFO() implements the type() member function for the
 // TypeOf<> specialization for STRUCT.
 // STRUCT is the structure typename.
 // NAME is the serialized name of the structure, as described by the DAP
 // specification. The variadic (...) parameters should be a repeated list of
 // DAP_FIELD()s, one for each field of the struct.
-#define DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, ...)                  \
-  const TypeInfo* TypeOf<STRUCT>::type() {                                \
-    using StructTy = STRUCT;                                              \
-    struct TI : BasicTypeInfo<StructTy> {                                 \
-      TI() : BasicTypeInfo<StructTy>(NAME) {}                             \
-      bool deserialize(const Deserializer* d, void* ptr) const override { \
-        return d->deserialize(ptr, {__VA_ARGS__});                        \
+// Must be used within the 'dap' namespace.
+#define DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, ...)                    \
+  DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__)       \
+  const ::dap::TypeInfo* TypeOf<STRUCT>::type() {                           \
+    struct TI : BasicTypeInfo<STRUCT> {                                     \
+      TI() : BasicTypeInfo<STRUCT>(NAME) {}                                 \
+      bool deserialize(const Deserializer* d, void* obj) const override {   \
+        return deserializeFields(d, obj);                                   \
+      }                                                                     \
+      bool serialize(Serializer* s, const void* obj) const override {       \
+        return s->object(                                                   \
+            [&](FieldSerializer* fs) { return serializeFields(fs, obj); }); \
+      }                                                                     \
+    };                                                                      \
+    static TI typeinfo;                                                     \
+    return &typeinfo;                                                       \
+  }
+
+// DAP_STRUCT_TYPEINFO() is a helper for declaring and implementing a TypeOf<>
+// specialization for STRUCT in a single statement.
+// Must be used within the 'dap' namespace.
+#define DAP_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
+  DAP_DECLARE_STRUCT_TYPEINFO(STRUCT);         \
+  DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, __VA_ARGS__)
+
+// DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT() implements the type() member function for
+// the TypeOf<> specialization for STRUCT that derives from BASE.
+// STRUCT is the structure typename.
+// BASE is the base structure typename.
+// NAME is the serialized name of the structure, as described by the DAP
+// specification. The variadic (...) parameters should be a repeated list of
+// DAP_FIELD()s, one for each field of the struct.
+// Must be used within the 'dap' namespace.
+#define DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...)        \
+  static_assert(std::is_base_of<BASE, STRUCT>::value,                     \
+                #STRUCT " does not derive from " #BASE);                  \
+  DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__)     \
+  const ::dap::TypeInfo* TypeOf<STRUCT>::type() {                         \
+    struct TI : BasicTypeInfo<STRUCT> {                                   \
+      TI() : BasicTypeInfo<STRUCT>(NAME) {}                               \
+      bool deserialize(const Deserializer* d, void* obj) const override { \
+        auto derived = static_cast<STRUCT*>(obj);                         \
+        auto base = static_cast<BASE*>(obj);                              \
+        return TypeOf<BASE>::deserializeFields(d, base) &&                \
+               deserializeFields(d, derived);                             \
       }                                                                   \
-      bool serialize(Serializer* s, const void* ptr) const override {     \
-        return s->fields(ptr, {__VA_ARGS__});                             \
+      bool serialize(Serializer* s, const void* obj) const override {     \
+        return s->object([&](FieldSerializer* fs) {                       \
+          auto derived = static_cast<const STRUCT*>(obj);                 \
+          auto base = static_cast<const BASE*>(obj);                      \
+          return TypeOf<BASE>::serializeFields(fs, base) &&               \
+                 serializeFields(fs, derived);                            \
+        });                                                               \
       }                                                                   \
     };                                                                    \
     static TI typeinfo;                                                   \
     return &typeinfo;                                                     \
   }
 
-// DAP_STRUCT_TYPEINFO() is a helper for declaring and implementing a TypeOf<>
-// specialization for STRUCT in a single statement.
-#define DAP_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
-  DAP_DECLARE_STRUCT_TYPEINFO(STRUCT);         \
-  DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, __VA_ARGS__)
+// DAP_STRUCT_TYPEINFO_EXT() is a helper for declaring and implementing a
+// TypeOf<> specialization for STRUCT that derives from BASE in a single
+// statement.
+// Must be used within the 'dap' namespace.
+#define DAP_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...) \
+  DAP_DECLARE_STRUCT_TYPEINFO(STRUCT);                   \
+  DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, __VA_ARGS__)
 
 }  // namespace dap
 
diff --git a/src/json_serializer.cpp b/src/json_serializer.cpp
index 12fdf9f..16ada79 100644
--- a/src/json_serializer.cpp
+++ b/src/json_serializer.cpp
@@ -224,27 +224,24 @@
   return true;
 }
 
-bool Serializer::fields(const void* object,
-                        const std::initializer_list<Field>& fields) {
-  *json = nlohmann::json({}, false, nlohmann::json::value_t::object);
-  for (auto const& f : fields) {
-    if (!field(f.name, [&](dap::Serializer* d) {
-          auto ptr = reinterpret_cast<const uint8_t*>(object) + f.offset;
-          return f.type->serialize(d, ptr);
-        }))
-      return false;
-  }
-  return true;
-}
+bool Serializer::object(const std::function<bool(dap::FieldSerializer*)>& cb) {
+  struct FS : public FieldSerializer {
+    nlohmann::json* const json;
 
-bool Serializer::field(const std::string& name,
-                       const std::function<bool(dap::Serializer*)>& cb) {
-  Serializer s(&(*json)[name]);
-  auto res = cb(&s);
-  if (s.removed) {
-    json->erase(name);
-  }
-  return res;
+    FS(nlohmann::json* json) : json(json) {}
+    bool field(const std::string& name, const SerializeFunc& cb) override {
+      Serializer s(&(*json)[name]);
+      auto res = cb(&s);
+      if (s.removed) {
+        json->erase(name);
+      }
+      return res;
+    }
+  };
+
+  *json = nlohmann::json({}, false, nlohmann::json::value_t::object);
+  FS fs{json};
+  return cb(&fs);
 }
 
 void Serializer::remove() {
diff --git a/src/json_serializer.h b/src/json_serializer.h
index 41afe1e..4ae4e11 100644
--- a/src/json_serializer.h
+++ b/src/json_serializer.h
@@ -67,11 +67,6 @@
     return dap::Deserializer::deserialize(v);
   }
 
-  inline bool deserialize(void* o,
-                          const std::initializer_list<Field>& f) const {
-    return dap::Deserializer::deserialize(o, f);
-  }
-
   template <typename T>
   inline bool field(const std::string& name, T* v) const {
     return dap::Deserializer::deserialize(name, v);
@@ -94,23 +89,14 @@
   bool serialize(integer v) override;
   bool serialize(number v) override;
   bool serialize(const string& v) override;
-  bool serialize(const object& v) override;
+  bool serialize(const dap::object& v) override;
   bool serialize(const any& v) override;
   bool array(size_t count,
              const std::function<bool(dap::Serializer*)>&) override;
-  bool fields(const void* object,
-              const std::initializer_list<Field>& fields) override;
-  bool field(const std::string& name, const FieldSerializer&) override;
+  bool object(const std::function<bool(dap::FieldSerializer*)>&) override;
   void remove() override;
 
   // Unhide base overloads
-  template <
-      typename T,
-      typename = typename std::enable_if<!IsFieldSerializer<T>::value>::type>
-  inline bool field(const std::string& name, const T& v) {
-    return dap::Serializer::field(name, v);
-  }
-
   template <typename T,
             typename = std::enable_if<TypeOf<T>::has_custom_serialization>>
   inline bool serialize(const T& v) {
diff --git a/src/json_serializer_test.cpp b/src/json_serializer_test.cpp
index 53cc9a2..d26c63e 100644
--- a/src/json_serializer_test.cpp
+++ b/src/json_serializer_test.cpp
@@ -20,8 +20,6 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-#include <nlohmann/json.hpp>
-
 namespace dap {
 
 struct JSONInnerTestObject {
diff --git a/src/session.cpp b/src/session.cpp
index ce8f63f..6344e5a 100644
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -89,22 +89,31 @@
     handlers.put(seq, responseTypeInfo, responseHandler);
 
     dap::json::Serializer s;
-    s.field("seq", dap::integer(seq));
-    s.field("type", "request");
-    s.field("command", requestTypeInfo->name());
-    s.field("arguments", [&](dap::Serializer* s) {
-      return requestTypeInfo->serialize(s, request);
-    });
+    if (!s.object([&](dap::FieldSerializer* fs) {
+          return fs->field("seq", dap::integer(seq)) &&
+                 fs->field("type", "request") &&
+                 fs->field("command", requestTypeInfo->name()) &&
+                 fs->field("arguments", [&](dap::Serializer* s) {
+                   return requestTypeInfo->serialize(s, request);
+                 });
+        })) {
+      return false;
+    }
     return send(s.dump());
   }
 
   bool send(const dap::TypeInfo* typeinfo, const void* event) override {
     dap::json::Serializer s;
-    s.field("seq", dap::integer(nextSeq++));
-    s.field("type", "event");
-    s.field("event", typeinfo->name());
-    s.field("body",
-            [&](dap::Serializer* s) { return typeinfo->serialize(s, event); });
+    if (!s.object([&](dap::FieldSerializer* fs) {
+          return fs->field("seq", dap::integer(nextSeq++)) &&
+                 fs->field("type", "event") &&
+                 fs->field("event", typeinfo->name()) &&
+                 fs->field("body", [&](dap::Serializer* s) {
+                   return typeinfo->serialize(s, event);
+                 });
+        })) {
+      return false;
+    }
     return send(s.dump());
   }
 
@@ -319,13 +328,15 @@
           [&](const dap::TypeInfo* typeinfo, const void* data) {
             // onSuccess
             dap::json::Serializer s;
-            s.field("seq", dap::integer(nextSeq++));
-            s.field("type", "response");
-            s.field("request_seq", sequence);
-            s.field("success", dap::boolean(true));
-            s.field("command", command);
-            s.field("body", [&](dap::Serializer* s) {
-              return typeinfo->serialize(s, data);
+            s.object([&](dap::FieldSerializer* fs) {
+              return fs->field("seq", dap::integer(nextSeq++)) &&
+                     fs->field("type", "response") &&
+                     fs->field("request_seq", sequence) &&
+                     fs->field("success", dap::boolean(true)) &&
+                     fs->field("command", command) &&
+                     fs->field("body", [&](dap::Serializer* s) {
+                       return typeinfo->serialize(s, data);
+                     });
             });
             send(s.dump());
 
@@ -336,12 +347,14 @@
           [&](const dap::TypeInfo* typeinfo, const dap::Error& error) {
             // onError
             dap::json::Serializer s;
-            s.field("seq", dap::integer(nextSeq++));
-            s.field("type", "response");
-            s.field("request_seq", sequence);
-            s.field("success", dap::boolean(false));
-            s.field("command", command);
-            s.field("message", error.message);
+            s.object([&](dap::FieldSerializer* fs) {
+              return fs->field("seq", dap::integer(nextSeq++)) &&
+                     fs->field("type", "response") &&
+                     fs->field("request_seq", sequence) &&
+                     fs->field("success", dap::boolean(false)) &&
+                     fs->field("command", command) &&
+                     fs->field("message", error.message);
+            });
             send(s.dump());
 
             if (auto handler = handlers.responseSent(typeinfo)) {
diff --git a/src/typeinfo_test.cpp b/src/typeinfo_test.cpp
new file mode 100644
index 0000000..23d5793
--- /dev/null
+++ b/src/typeinfo_test.cpp
@@ -0,0 +1,65 @@
+// Copyright 2020 Google LLC
+//
+// Licensed 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
+//
+//     https://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 "dap/typeof.h"
+#include "dap/types.h"
+#include "json_serializer.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace dap {
+
+struct BaseStruct {
+  dap::integer i;
+  dap::number n;
+};
+
+DAP_STRUCT_TYPEINFO(BaseStruct,
+                    "BaseStruct",
+                    DAP_FIELD(i, "i"),
+                    DAP_FIELD(n, "n"));
+
+struct DerivedStruct : public BaseStruct {
+  dap::string s;
+  dap::boolean b;
+};
+
+DAP_STRUCT_TYPEINFO_EXT(DerivedStruct,
+                        BaseStruct,
+                        "DerivedStruct",
+                        DAP_FIELD(s, "s"),
+                        DAP_FIELD(b, "b"));
+
+}  // namespace dap
+
+TEST(TypeInfo, Derived) {
+  dap::DerivedStruct in;
+  in.s = "hello world";
+  in.b = true;
+  in.i = 42;
+  in.n = 3.14;
+
+  dap::json::Serializer s;
+  ASSERT_TRUE(s.serialize(in));
+
+  dap::DerivedStruct out;
+  dap::json::Deserializer d(s.dump());
+  ASSERT_TRUE(d.deserialize(&out)) << "Failed to deserialize\n" << s.dump();
+
+  ASSERT_EQ(out.s, "hello world");
+  ASSERT_EQ(out.b, true);
+  ASSERT_EQ(out.i, 42);
+  ASSERT_EQ(out.n, 3.14);
+}