Array and map members for unions.

BUG=
R=yzshen@chromium.org

Review URL: https://codereview.chromium.org/1065653006
diff --git a/mojo/public/cpp/bindings/tests/union_unittest.cc b/mojo/public/cpp/bindings/tests/union_unittest.cc
index 6124d27..5017d97 100644
--- a/mojo/public/cpp/bindings/tests/union_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/union_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <vector>
 #include "mojo/public/cpp/bindings/array.h"
 #include "mojo/public/cpp/bindings/lib/array_internal.h"
 #include "mojo/public/cpp/bindings/lib/array_serialization.h"
@@ -637,6 +638,7 @@
                                                static_cast<uint32_t>(size), 0);
   EXPECT_TRUE(
       internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false));
+  free(raw_buf);
 }
 
 TEST(UnionTest, StructInUnionValidationNonNullable) {
@@ -657,6 +659,7 @@
                                                static_cast<uint32_t>(size), 0);
   EXPECT_FALSE(
       internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false));
+  free(raw_buf);
 }
 
 TEST(UnionTest, StructInUnionValidationNullable) {
@@ -677,6 +680,144 @@
                                                static_cast<uint32_t>(size), 0);
   EXPECT_TRUE(
       internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false));
+  free(raw_buf);
+}
+
+TEST(UnionTest, ArrayInUnionGetterSetter) {
+  Environment environment;
+
+  Array<int8_t> array(2);
+  array[0] = 8;
+  array[1] = 9;
+
+  ObjectUnionPtr obj(ObjectUnion::New());
+  obj->set_f_array_int8(array.Pass());
+
+  EXPECT_EQ(8, obj->get_f_array_int8()[0]);
+  EXPECT_EQ(9, obj->get_f_array_int8()[1]);
+}
+
+TEST(UnionTest, ArrayInUnionSerialization) {
+  Environment environment;
+
+  Array<int8_t> array(2);
+  array[0] = 8;
+  array[1] = 9;
+
+  ObjectUnionPtr obj(ObjectUnion::New());
+  obj->set_f_array_int8(array.Pass());
+
+  size_t size = GetSerializedSize_(obj, false);
+  EXPECT_EQ(32U, size);
+
+  mojo::internal::FixedBuffer buf(size);
+  internal::ObjectUnion_Data* data = nullptr;
+  SerializeUnion_(obj.Pass(), &buf, &data, false);
+
+  std::vector<Handle> handles;
+  data->EncodePointersAndHandles(&handles);
+  data->DecodePointersAndHandles(&handles);
+
+  ObjectUnionPtr obj2;
+  Deserialize_(data, &obj2);
+
+  EXPECT_EQ(8, obj2->get_f_array_int8()[0]);
+  EXPECT_EQ(9, obj2->get_f_array_int8()[1]);
+}
+
+TEST(UnionTest, ArrayInUnionValidation) {
+  Environment environment;
+
+  Array<int8_t> array(2);
+  array[0] = 8;
+  array[1] = 9;
+
+  ObjectUnionPtr obj(ObjectUnion::New());
+  obj->set_f_array_int8(array.Pass());
+
+  size_t size = GetSerializedSize_(obj, false);
+  mojo::internal::FixedBuffer buf(size);
+  internal::ObjectUnion_Data* data = nullptr;
+  SerializeUnion_(obj.Pass(), &buf, &data, false);
+
+  std::vector<Handle> handles;
+  data->EncodePointersAndHandles(&handles);
+
+  void* raw_buf = buf.Leak();
+  mojo::internal::BoundsChecker bounds_checker(data,
+                                               static_cast<uint32_t>(size), 0);
+
+  EXPECT_TRUE(
+      internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false));
+  free(raw_buf);
+}
+
+TEST(UnionTest, MapInUnionGetterSetter) {
+  Environment environment;
+  Map<String, int8_t> map;
+  map.insert("one", 1);
+  map.insert("two", 2);
+
+  ObjectUnionPtr obj(ObjectUnion::New());
+  obj->set_f_map_int8(map.Pass());
+
+  EXPECT_EQ(1, obj->get_f_map_int8()["one"]);
+  EXPECT_EQ(2, obj->get_f_map_int8()["two"]);
+}
+
+TEST(UnionTest, MapInUnionSerialization) {
+  Environment environment;
+  Map<String, int8_t> map;
+  map.insert("one", 1);
+  map.insert("two", 2);
+
+  ObjectUnionPtr obj(ObjectUnion::New());
+  obj->set_f_map_int8(map.Pass());
+
+  size_t size = GetSerializedSize_(obj, false);
+  EXPECT_EQ(112U, size);
+
+  mojo::internal::FixedBuffer buf(size);
+  internal::ObjectUnion_Data* data = nullptr;
+  SerializeUnion_(obj.Pass(), &buf, &data, false);
+
+  std::vector<Handle> handles;
+  data->EncodePointersAndHandles(&handles);
+  data->DecodePointersAndHandles(&handles);
+
+  ObjectUnionPtr obj2;
+  Deserialize_(data, &obj2);
+
+  EXPECT_EQ(1, obj2->get_f_map_int8()["one"]);
+  EXPECT_EQ(2, obj2->get_f_map_int8()["two"]);
+}
+
+TEST(UnionTest, MapInUnionValidation) {
+  Environment environment;
+  Map<String, int8_t> map;
+  map.insert("one", 1);
+  map.insert("two", 2);
+
+  ObjectUnionPtr obj(ObjectUnion::New());
+  obj->set_f_map_int8(map.Pass());
+
+  size_t size = GetSerializedSize_(obj, false);
+  EXPECT_EQ(112U, size);
+
+  mojo::internal::FixedBuffer buf(size);
+  internal::ObjectUnion_Data* data = nullptr;
+  SerializeUnion_(obj.Pass(), &buf, &data, false);
+
+  std::vector<Handle> handles;
+  data->EncodePointersAndHandles(&handles);
+
+  void* raw_buf = buf.Leak();
+  mojo::internal::BoundsChecker bounds_checker(data,
+                                               static_cast<uint32_t>(size), 0);
+
+  EXPECT_TRUE(
+      internal::ObjectUnion_Data::Validate(raw_buf, &bounds_checker, false));
+  free(raw_buf);
 }
 
 }  // namespace test
diff --git a/mojo/public/interfaces/bindings/tests/test_unions.mojom b/mojo/public/interfaces/bindings/tests/test_unions.mojom
index ffc8922..cda5be4 100644
--- a/mojo/public/interfaces/bindings/tests/test_unions.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_unions.mojom
@@ -24,6 +24,8 @@
   string f_string;
   DummyStruct f_dummy;
   DummyStruct? f_nullable;
+  array<int8> f_array_int8;
+  map<string, int8> f_map_int8;
 };
 
 struct DummyStruct {
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
index f29ea2d..f84f60a 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_declaration.tmpl
@@ -32,7 +32,7 @@
   // a struct." - Section 9.5.2 ISO/IEC 14882:2011 (The C++ Spec)
   union MOJO_ALIGNAS(8) Union_ {
 {%- for field in union.fields %}
-{%-   if field.kind|is_string_kind or field.kind|is_struct_kind %}
+{%-   if field.kind|is_object_kind %}
     uint64_t f_{{field.name}};
 {%-   elif field.kind.spec == 'b' %}
     uint8_t f_{{field.name}} : 1;
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
index 3e6b0ad..9ddcc51 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_definition.tmpl
@@ -57,10 +57,36 @@
 
 void {{class_name}}::EncodePointersAndHandles(
     std::vector<mojo::Handle>* handles) {
-  // TODO(azani): Implement pointers and handles.
+  switch (tag) {
+{%- for field in union.fields %}
+    case {{enum_name}}::{{field.name|upper}}: {
+{%-   if field.kind|is_object_kind and not field.kind|is_union_kind %}
+      mojo::internal::Encode(
+          reinterpret_cast<{{field.kind|cpp_field_type}}*>(&data.f_{{field.name}}),
+          handles);
+{%-   elif field.kind|is_any_handle_kind %}
+      mojo::internal::EncodeHandle(&data.f_{{field.name}}, handles);
+{%-   endif %}
+      return;
+    }
+{%- endfor %}
+  }
 }
 
 void {{class_name}}::DecodePointersAndHandles(
     std::vector<mojo::Handle>* handles) {
-  // TODO(azani): Implement pointers and handles.
+  switch (tag) {
+{%- for field in union.fields %}
+    case {{enum_name}}::{{field.name|upper}}: {
+{%-   if field.kind|is_object_kind and not field.kind|is_union_kind %}
+      mojo::internal::Decode(
+          reinterpret_cast<{{field.kind|cpp_field_type}}*>(&data.f_{{field.name}}),
+          handles);
+{%-   elif field.kind|is_any_handle_kind %}
+      mojo::internal::DecodeHandle(&data.f_{{field.name}}, handles);
+{%-   endif %}
+      return;
+    }
+{%- endfor %}
+  }
 }
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
index f1dd0aa..7df17c1 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
@@ -43,6 +43,18 @@
         Serialize_(*(input_acc.data()->{{field.name}}), buf, &{{field.name}}_ptr->ptr);
 {%      elif field.kind|is_struct_kind %}
         Serialize_(mojo::internal::Forward(*(input_acc.data()->{{field.name}})), buf, &{{field.name}}_ptr->ptr);
+{%      elif field.kind|is_array_kind %}
+        const mojo::internal::ArrayValidateParams {{field.name}}_validate_params =
+            {{field.kind|get_array_validate_params|indent(16)}};
+        SerializeArray_(
+            mojo::internal::Forward(*(input_acc.data()->{{field.name}})),
+            buf, &{{field.name}}_ptr->ptr, &{{field.name}}_validate_params);
+{%      elif field.kind|is_map_kind %}
+        const mojo::internal::ArrayValidateParams {{field.name}}_validate_params =
+            {{field.kind.value_kind|get_map_validate_params|indent(16)}};
+        SerializeMap_(
+            mojo::internal::Forward(*(input_acc.data()->{{field.name}})),
+            buf, &{{field.name}}_ptr->ptr, &{{field.name}}_validate_params);
 {%-     endif %}
 {%    else %}
         result->data.f_{{field.name}} = input_acc.data()->{{field.name}};
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
index 46931bc..4355f41 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_union_class_definition.tmpl
@@ -23,7 +23,7 @@
     case Tag::{{field.name|upper}}:
 {%    if field.kind|is_string_kind %}
       rv->set_{{field.name}}(*(data_.{{field.name}}));
-{%    elif field.kind|is_struct_kind %}
+{%    elif field.kind|is_object_kind %}
       rv->set_{{field.name}}(data_.{{field.name}}->Clone());
 {%-   else %}
       rv->set_{{field.name}}(data_.{{field.name}});
@@ -72,7 +72,7 @@
   SwitchActive(Tag::{{field.name|upper}});
 {%    if field.kind|is_string_kind %}
   *(data_.{{field.name}}) = {{field.name}};
-{%    elif field.kind|is_struct_kind %}
+{%    elif field.kind|is_object_kind %}
   *(data_.{{field.name}}) = {{field.name}}.Pass();
 {%-   else %}
   data_.{{field.name}} = {{field.name}};
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index 35dec21..dbe977d 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -228,7 +228,8 @@
   return _kind_to_cpp_type[kind]
 
 def GetUnionGetterReturnType(kind):
-  if mojom.IsStructKind(kind):
+  if (mojom.IsStructKind(kind) or mojom.IsArrayKind(kind) or
+      mojom.IsMapKind(kind)):
     return "%s&" % GetCppWrapperType(kind)
   return GetCppResultWrapperType(kind)