Support structs in json_to_flatbuffer

Our JSON flatbuffer parsing code did not support structs properly.

Doing this enables easily defining lots of different layouts of
flatbuffers for more thoroughly testing flatbuffer-related changes (as
well as just making the JSON parsing more complete).

Change-Id: Ibfc7a149f9c8b314f6bbba70b4ca6b5857a8728b
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/flatbuffer_utils.cc b/aos/flatbuffer_utils.cc
index 3429fe4..5abe676 100644
--- a/aos/flatbuffer_utils.cc
+++ b/aos/flatbuffer_utils.cc
@@ -19,6 +19,26 @@
   LOG(FATAL) << "Unimplemented";
 }
 
+bool FlatbufferType::IsTable() const {
+  if (type_table_) {
+    return type_table_->st == flatbuffers::ST_TABLE;
+  }
+  if (object_) {
+    return !object_->is_struct();
+  }
+  LOG(FATAL) << "Unimplemented";
+}
+
+bool FlatbufferType::IsStruct() const {
+  if (type_table_) {
+    return type_table_->st == flatbuffers::ST_STRUCT;
+  }
+  if (object_) {
+    return object_->is_struct();
+  }
+  LOG(FATAL) << "Unimplemented";
+}
+
 bool FlatbufferType::IsEnum() const {
   if (type_table_) {
     return type_table_->st == flatbuffers::ST_ENUM;
@@ -256,10 +276,64 @@
 
 }  // namespace
 
+size_t FlatbufferType::InlineSize() const {
+  DCHECK(IsSequence());
+  if (type_table_) {
+    return flatbuffers::InlineSize(flatbuffers::ElementaryType::ET_SEQUENCE,
+                                   type_table_);
+  }
+  if (object_) {
+    return object_->is_struct() ? object_->bytesize() : /*offset size*/ 4u;
+  }
+  if (enum_) {
+    return BaseTypeInlineSize(enum_->underlying_type()->base_type());
+  }
+  LOG(FATAL) << "Unimplemented";
+}
+
+// Returns the required alignment for this type.
+size_t FlatbufferType::Alignment() const {
+  if (type_table_) {
+    // Attempt to derive alignment as max alignment of the members.
+    size_t alignment = 1u;
+    for (size_t field_index = 0;
+         field_index < static_cast<size_t>(NumberFields()); ++field_index) {
+      alignment = std::max(alignment, FieldInlineAlignment(field_index));
+    }
+    return alignment;
+  }
+  if (object_) {
+    return object_->minalign();
+  }
+  // We don't do a great job of supporting unions in general, and as of this
+  // writing did not try to look up what the alignment rules for unions were.
+  LOG(FATAL) << "Unimplemented";
+}
+
+size_t FlatbufferType::FieldInlineAlignment(size_t field_index) const {
+  if (FieldIsSequence(field_index) && FieldType(field_index).IsStruct()) {
+    return FieldType(field_index).Alignment();
+  }
+  return FieldInlineSize(field_index);
+}
+
+size_t FlatbufferType::StructFieldOffset(int index) const {
+  DCHECK(IsStruct());
+  if (type_table_) {
+    return type_table_->values[index];
+  }
+  if (object_) {
+    return ReflectionObjectField(index)->offset();
+  }
+  LOG(FATAL) << "Unimplemented";
+}
+
 size_t FlatbufferType::FieldInlineSize(int index) const {
   DCHECK(IsSequence());
   if (type_table_) {
-    return flatbuffers::InlineSize(FieldElementaryType(index), type_table_);
+    return flatbuffers::InlineSize(
+        FieldElementaryType(index),
+        FieldIsSequence(index) ? FieldType(index).type_table_ : nullptr);
   }
   if (object_ || enum_) {
     const reflection::Type *const type = ReflectionType(index);