From eaa2b414b28bee02bee140658c238da648790a48 Mon Sep 17 00:00:00 2001 From: Oli Wilkinson Date: Mon, 18 Jan 2016 15:23:14 +0000 Subject: [PATCH] Added generation of typed helpers when using nested_flatbuffers in Java/C#. Fixes #3500 --- src/idl_gen_general.cpp | 22 ++++++++++- .../FlatBuffersExampleTests.cs | 39 +++++++++++++++++++ tests/JavaTest.java | 38 ++++++++++++++++++ tests/MyGame/Example/Monster.cs | 2 + tests/MyGame/Example/Monster.java | 2 + 5 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 70c5badfd..c8dbd1d95 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -876,7 +876,27 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, break; } } - + // generate object accessors if is nested_flatbuffer + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (nested) { + auto nested_qualified_name = + parser.namespaces_.back()->GetFullyQualifiedName(nested->constant); + auto nested_type = parser.structs_.Lookup(nested_qualified_name); + auto nested_type_name = WrapInNameSpace(parser, *nested_type); + auto nestedMethodName = MakeCamel(field.name, lang.first_camel_upper) + + "As" + nested_type_name; + auto getNestedMethodName = nestedMethodName; + if (lang.language == IDLOptions::kCSharp) { + getNestedMethodName = "Get" + nestedMethodName; + } + code += " public " + nested_type_name + " "; + code += nestedMethodName + "() { return "; + code += getNestedMethodName + "(new " + nested_type_name + "()); }\n"; + code += " public " + nested_type_name + " " + getNestedMethodName; + code += "(" + nested_type_name + " obj) { "; + code += "int o = __offset(" + NumToString(field.value.offset) +"); "; + code += "return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }\n"; + } // generate mutators for scalar fields or vectors of scalars if (parser.opts.mutable_buffer) { auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs index 43754c77f..80791dd19 100644 --- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs @@ -215,5 +215,44 @@ namespace FlatBuffers.Test Assert.AreEqual("NONE", Any.NONE.ToString()); Assert.AreEqual("Monster", Any.Monster.ToString()); } + + [FlatBuffersTestMethod] + public void TestNestedFlatBuffer() + { + const string nestedMonsterName = "NestedMonsterName"; + const short nestedMonsterHp = 600; + const short nestedMonsterMana = 1024; + // Create nested buffer as a Monster type + var fbb1 = new FlatBufferBuilder(16); + var str1 = fbb1.CreateString(nestedMonsterName); + Monster.StartMonster(fbb1); + Monster.AddName(fbb1, str1); + Monster.AddHp(fbb1, nestedMonsterHp); + Monster.AddMana(fbb1, nestedMonsterMana); + var monster1 = Monster.EndMonster(fbb1); + Monster.FinishMonsterBuffer(fbb1, monster1); + var fbb1Bytes = fbb1.SizedByteArray(); + fbb1 = null; + + // Create a Monster which has the first buffer as a nested buffer + var fbb2 = new FlatBufferBuilder(16); + var str2 = fbb2.CreateString("My Monster"); + var nestedBuffer = Monster.CreateTestnestedflatbufferVector(fbb2, fbb1Bytes); + Monster.StartMonster(fbb2); + Monster.AddName(fbb2, str2); + Monster.AddHp(fbb2, 50); + Monster.AddMana(fbb2, 32); + Monster.AddTestnestedflatbuffer(fbb2, nestedBuffer); + var monster = Monster.EndMonster(fbb2); + Monster.FinishMonsterBuffer(fbb2, monster); + + // Now test the data extracted from the nested buffer + var mons = Monster.GetRootAsMonster(fbb2.DataBuffer); + var nestedMonster = mons.TestnestedflatbufferAsMonster(); + + Assert.AreEqual(nestedMonsterMana, nestedMonster.Mana); + Assert.AreEqual(nestedMonsterHp, nestedMonster.Hp); + Assert.AreEqual(nestedMonsterName, nestedMonster.Name); + } } } diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 0bc0dbadb..154fdec67 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -159,6 +159,8 @@ class JavaTest { TestNamespaceNesting(); + TestNestedFlatBuffer(); + System.out.println("FlatBuffers test: completed successfully"); } @@ -242,6 +244,42 @@ class JavaTest { TableInFirstNS.addFooTable(fbb, nestedTableOff); int off = TableInFirstNS.endTableInFirstNS(fbb); } + + static void TestNestedFlatBuffer() { + final String nestedMonsterName = "NestedMonsterName"; + final short nestedMonsterHp = 600; + final short nestedMonsterMana = 1024; + + FlatBufferBuilder fbb1 = new FlatBufferBuilder(16); + int str1 = fbb1.createString(nestedMonsterName); + Monster.startMonster(fbb1); + Monster.addName(fbb1, str1); + Monster.addHp(fbb1, nestedMonsterHp); + Monster.addMana(fbb1, nestedMonsterMana); + int monster1 = Monster.endMonster(fbb1); + Monster.finishMonsterBuffer(fbb1, monster1); + byte[] fbb1Bytes = fbb1.sizedByteArray(); + fbb1 = null; + + FlatBufferBuilder fbb2 = new FlatBufferBuilder(16); + int str2 = fbb2.createString("My Monster"); + int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes); + Monster.startMonster(fbb2); + Monster.addName(fbb2, str2); + Monster.addHp(fbb2, (short)50); + Monster.addMana(fbb2, (short)32); + Monster.addTestnestedflatbuffer(fbb2, nestedBuffer); + int monster = Monster.endMonster(fbb2); + Monster.finishMonsterBuffer(fbb2, monster); + + // Now test the data extracted from the nested buffer + Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer()); + Monster nestedMonster = mons.testnestedflatbufferAsMonster(); + + TestEq(nestedMonsterMana, nestedMonster.mana()); + TestEq(nestedMonsterHp, nestedMonster.hp()); + TestEq(nestedMonsterName, nestedMonster.name()); + } static void TestEq(T a, T b) { if (!a.equals(b)) { diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index b324a8d5c..e456db8ca 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -45,6 +45,8 @@ public sealed class Monster : Table { public byte GetTestnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; } public int TestnestedflatbufferLength { get { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } } public ArraySegment? GetTestnestedflatbufferBytes() { return __vector_as_arraysegment(30); } + public Monster TestnestedflatbufferAsMonster() { return GetTestnestedflatbufferAsMonster(new Monster()); } + public Monster GetTestnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; } public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.Put(__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } } public Stat Testempty { get { return GetTestempty(new Stat()); } } public Stat GetTestempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 669bed922..16c7386e6 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -51,6 +51,8 @@ public final class Monster extends Table { public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } public int testnestedflatbufferLength() { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } public ByteBuffer testnestedflatbufferAsByteBuffer() { return __vector_as_bytebuffer(30, 1); } + public Monster testnestedflatbufferAsMonster() { return testnestedflatbufferAsMonster(new Monster()); } + public Monster testnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; } public boolean mutateTestnestedflatbuffer(int j, int testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)testnestedflatbuffer); return true; } else { return false; } } public Stat testempty() { return testempty(new Stat()); } public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }