got MessageType finished (not tests though)
diff --git a/aos/build/aos.gyp b/aos/build/aos.gyp
index b7775a1..a6e4f33 100644
--- a/aos/build/aos.gyp
+++ b/aos/build/aos.gyp
@@ -25,6 +25,7 @@
       ],
       'dependencies': [
         '<(AOS)/common/common.gyp:die',
+        '<(AOS)/common/common.gyp:queue_types',
       ],
     },
     {
diff --git a/aos/build/aos_all.gyp b/aos/build/aos_all.gyp
index 3006820..2584ee2 100644
--- a/aos/build/aos_all.gyp
+++ b/aos/build/aos_all.gyp
@@ -22,6 +22,7 @@
         '../linux_code/starter/starter.gyp:netconsole',
         '../common/common.gyp:queue_test',
         '../common/common.gyp:die_test',
+        '../common/common.gyp:queue_types_test',
         '../common/util/util.gyp:trapezoid_profile_test',
         '../common/util/util.gyp:wrapping_counter_test',
         '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:cows_test',
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 508f94f..4a99198 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -42,6 +42,24 @@
       ],
     },
     {
+      'target_name': 'queue_types',
+      'type': 'static_library',
+      'sources': [
+        'queue_types.cc',
+      ],
+    },
+    {
+      'target_name': 'queue_types_test',
+      'type': 'executable',
+      'sources': [
+        'queue_types_test.cc',
+      ],
+      'dependencies': [
+        'queue_types',
+        '<(EXTERNALS):gtest',
+      ],
+    },
+    {
       'target_name': 'queues',
       'type': 'static_library',
       'sources': [
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/logging_impl.cc
index fa76c86..de1c64a 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/logging_impl.cc
@@ -14,7 +14,6 @@
 using internal::Context;
 using internal::global_top_implementation;
 
-
 // The root LogImplementation. It only logs to stderr/stdout.
 // Some of the things specified in the LogImplementation documentation doesn't
 // apply here (mostly the parts about being able to use LOG) because this is the
diff --git a/aos/common/queue.h b/aos/common/queue.h
index f1d9f82..9f6bc9d 100644
--- a/aos/common/queue.h
+++ b/aos/common/queue.h
@@ -11,9 +11,6 @@
 
 #include "aos/common/time.h"
 #include "aos/common/macros.h"
-#ifndef SWIG
-#include "aos/common/queue_types.h"
-#endif  // SWIG
 #ifndef USE_UNSAFE
 #include "aos/linux_code/ipc_lib/queue.h"
 #endif  // USE_UNSAFE
@@ -21,6 +18,8 @@
 
 namespace aos {
 
+class MessageType;
+
 // This class is a base class for all messages sent over queues.
 class Message {
  public:
@@ -50,9 +49,7 @@
   // Writes the contents of the message to the provided buffer.
   size_t Print(char *buffer, int length) const;
 
-#ifndef SWIG
-  const MessageType &GetType() const;
-#endif  // SWIG
+  const MessageType *GetType() const;
 };
 
 template <class T> class Queue;
diff --git a/aos/common/queue_types.cc b/aos/common/queue_types.cc
index 9ffef25..03d048a 100644
--- a/aos/common/queue_types.cc
+++ b/aos/common/queue_types.cc
@@ -1,6 +1,107 @@
 #include "aos/common/queue_types.h"
 
+#include <errno.h>
+
+#include <memory>
+
+#include "aos/common/byteorder.h"
+
 namespace aos {
 
+ssize_t MessageType::Serialize(char *buffer, size_t max_bytes) const {
+  char *const buffer_start = buffer;
+  size_t name_length = strlen(name);
+  ::std::unique_ptr<size_t> field_name_lengths(new size_t[number_fields]);
+  size_t fields_size = 0;
+  for (int i = 0; i < number_fields; ++i) {
+    fields_size += sizeof(fields[i]->type);
+    field_name_lengths.get()[i] = strlen(fields[i]->name);
+    fields_size += field_name_lengths.get()[i];
+  }
+  if (max_bytes < sizeof(id) + sizeof(name_length) + sizeof(number_fields) +
+                      name_length + fields_size) {
+    errno = EOVERFLOW;
+    return -1;
+  }
+  to_network(&id, buffer);
+  buffer += sizeof(id);
+  to_network(&name_length, buffer);
+  buffer += sizeof(name_length);
+  to_network(&number_fields, buffer);
+  buffer += sizeof(number_fields);
+  memcpy(buffer, name, name_length);
+  buffer += name_length;
+
+  for (int i = 0; i < number_fields; ++i) {
+    to_network(&fields[i]->type, buffer);
+    buffer += sizeof(fields[i]->type);
+    to_network(&field_name_lengths.get()[i], buffer);
+    buffer += sizeof(field_name_lengths.get()[i]);
+    memcpy(buffer, fields[i]->name, field_name_lengths.get()[i]);
+    buffer += field_name_lengths.get()[i];
+  }
+
+  return buffer - buffer_start;
+}
+
+MessageType *MessageType::Deserialize(const char *buffer, size_t *bytes) {
+  size_t name_length;
+  decltype(MessageType::id) id;
+  decltype(MessageType::number_fields) number_fields;
+  if (*bytes < sizeof(id) + sizeof(name_length) + sizeof(number_fields)) {
+    errno = EOVERFLOW;
+    return nullptr;
+  }
+  *bytes -= sizeof(id) + sizeof(name_length) + sizeof(number_fields);
+
+  to_host(buffer, &id);
+  buffer += sizeof(id);
+  to_host(buffer, &name_length);
+  buffer += sizeof(name_length);
+  to_host(buffer, &number_fields);
+  buffer += sizeof(number_fields);
+
+  if (*bytes < name_length) {
+    errno = EOVERFLOW;
+    return nullptr;
+  }
+  *bytes -= name_length;
+
+  Field **fields = new Field *[number_fields];
+  ::std::unique_ptr<MessageType> r(new MessageType(number_fields, fields));
+  r->id = id;
+  ::std::unique_ptr<char> name(new char[name_length + 1]);
+  memcpy(name.get(), buffer, name_length);
+  buffer += name_length;
+  name.get()[name_length] = '\0';
+  r->name = name.release();
+
+  for (int i = 0; i < number_fields; ++i) {
+    size_t field_name_length;
+    if (*bytes < sizeof(fields[i]->type) + sizeof(field_name_length)) {
+      errno = EOVERFLOW;
+      return nullptr;
+    }
+    *bytes -= sizeof(fields[i]->type) + sizeof(field_name_length);
+
+    to_host(buffer, &fields[i]->type);
+    buffer += sizeof(fields[i]->type);
+    to_host(buffer, &field_name_length);
+    buffer += sizeof(field_name_length);
+
+    if (*bytes < field_name_length) {
+      errno = EOVERFLOW;
+      return nullptr;
+    }
+    *bytes -= field_name_length;
+    ::std::unique_ptr<char> field_name(new char[field_name_length + 1]);
+    memcpy(field_name.get(), buffer, field_name_length);
+    buffer += field_name_length;
+    field_name.get()[field_name_length] = '\0';
+    fields[i]->name = field_name.release();
+  }
+
+  return r.release();
+}
 
 }  // namespace aos
diff --git a/aos/common/queue_types.h b/aos/common/queue_types.h
index 51455cd..ddc6aea 100644
--- a/aos/common/queue_types.h
+++ b/aos/common/queue_types.h
@@ -3,16 +3,21 @@
 
 #include <sys/types.h>
 #include <stdint.h>
+#include <string.h>
+
+#include <initializer_list>
+
+#include "aos/common/macros.h"
 
 namespace aos {
 
 // Prints the value from 1 message field into output.
 // output is where to write the text representation.
 // output_bytes should point to the number of bytes available to write in
-// output. It will be changed to the number of bytes that were actually written.
+// output. It will be reduced by the number of bytes that were actually written.
 // input is where to read the data in from.
 // input_bytes should point to the number of bytes available to read from input.
-// It will be changed to the number of bytes that were actually read.
+// It will be reduced by the number of bytes that were actually read.
 // type is the ID of a type to print. It must be a primitive type.
 //
 // The implementation of this is generated by the ruby code.
@@ -31,17 +36,36 @@
     const char *name;
   };
 
-  ~MessageType() {
-    for (int i = 0; i < number_fields; ++i) {
-      delete fields[i];
+  // Constructs a MessageType that doesn't own the storage for any of its
+  // names.
+  MessageType(uint32_t id, const char *name,
+              ::std::initializer_list<Field *> fields_initializer)
+      : id(id), name(name), owns_names(false) {
+    number_fields = fields_initializer.size();
+    fields = new const Field *[number_fields];
+    int i = 0;
+    for (const Field *c : fields_initializer) {
+      fields[i++] = c;
     }
   }
 
-  // Returns -1 for error.
+  ~MessageType() {
+    for (int i = 0; i < number_fields; ++i) {
+      if (owns_names) {
+        delete fields[i]->name;
+      }
+      delete fields[i];
+    }
+    if (owns_names) {
+      delete name;
+    }
+  }
+
+  // Returns -1 for error (in errno).
   ssize_t Serialize(char *buffer, size_t max_bytes) const;
   // bytes should start out as the number of bytes available in buffer and gets
-  // set to the number actually read before returning.
-  // Returns a new instance allocated with new or NULL for error.
+  // reduced by the number actually read before returning.
+  // Returns a new instance allocated with new or NULL for error (in errno).
   static MessageType *Deserialize(const char *buffer, size_t *bytes);
 
   static bool IsPrimitive(uint32_t type_id) {
@@ -52,8 +76,23 @@
   uint32_t id;
   const char *name;
 
-  int number_fields;
+  int32_t number_fields;
   const Field **fields;
+
+ private:
+  MessageType(int32_t number_fields, Field **fields)
+      : name(nullptr),
+        number_fields(number_fields),
+        fields(const_cast<const Field **>(fields)),
+        owns_names(true) {
+    for (int i = 0; i < number_fields; ++i) {
+      fields[i] = new Field();
+    }
+  }
+
+  const bool owns_names;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageType);
 };
 
 namespace type_cache {
diff --git a/aos/common/queue_types_test.cc b/aos/common/queue_types_test.cc
new file mode 100644
index 0000000..38334df
--- /dev/null
+++ b/aos/common/queue_types_test.cc
@@ -0,0 +1,27 @@
+#include "aos/common/queue_types.h"
+
+#include <memory>
+
+#include "gtest/gtest.h"
+
+namespace aos {
+
+typedef MessageType::Field Field;
+
+static const MessageType kTestType1(0x1234, "TestType1",
+                                    {new Field{0, "field1"},
+                                     new Field{0, "field2"},
+                                     new Field{0, "field3"}});
+
+TEST(QueueTypesTest, Serialization) {
+  char buffer[512];
+  ssize_t size;
+
+  size = kTestType1.Serialize(buffer, sizeof(buffer));
+  EXPECT_GT(size, 1);
+  size_t out_size = size;
+  ::std::unique_ptr<MessageType> deserialized(MessageType::Deserialize(buffer, &out_size));
+  EXPECT_EQ(0u, out_size);
+}
+
+}  // namespace aos