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