Skip to content

Commit 4168b59

Browse files
surculus12Justin Davis
authored andcommitted
Resolve #4530: Added string and struct union support
1 parent f5ed336 commit 4168b59

File tree

5 files changed

+74
-35
lines changed

5 files changed

+74
-35
lines changed

python/flatbuffers/table.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ def String(self, off):
5353
length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
5454
return bytes(self.Bytes[start:start+length])
5555

56+
def UnionString(self, off):
57+
"""String gets a string from data stored inside the flatbuffer."""
58+
N.enforce_number(off, N.UOffsetTFlags)
59+
start = off + N.UOffsetTFlags.bytewidth
60+
length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
61+
return bytes(self.Bytes[start:start+length])
62+
5663
def VectorLen(self, off):
5764
"""VectorLen retrieves the length of the vector whose offset is stored
5865
at "off" in this object."""

src/idl_gen_python.cpp

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,8 +1078,8 @@ class PythonGenerator : public BaseGenerator {
10781078

10791079
// Get the value of a vector's union member.
10801080
void GetMemberOfVectorOfUnion(const StructDef &struct_def,
1081-
const FieldDef &field,
1082-
std::string *code_ptr) const {
1081+
const FieldDef &field,
1082+
std::string *code_ptr) const {
10831083
auto &code = *code_ptr;
10841084
auto vectortype = field.value.type.VectorType();
10851085

@@ -1092,17 +1092,8 @@ class PythonGenerator : public BaseGenerator {
10921092
code += NumToString(InlineSize(vectortype)) + "\n";
10931093
code += Indent + Indent + Indent;
10941094
code += "x -= self._tab.Pos\n";
1095-
1096-
// TODO(rw): this works and is not the good way to it:
1097-
bool is_native_table = TypeName(field) == "*flatbuffers.Table";
1098-
if (is_native_table) {
10991095
code +=
1100-
Indent + Indent + Indent + "from flatbuffers.table import Table\n";
1101-
} else if (parser_.opts.include_dependence_headers) {
1102-
code += Indent + Indent + Indent;
1103-
code += "from " + GenPackageReference(field.value.type) + " import " +
1104-
TypeName(field) + "\n";
1105-
}
1096+
Indent + Indent + Indent + "from flatbuffers.table import Table\n";
11061097
code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
11071098
code += Indent + Indent + Indent + GenGetter(field.value.type);
11081099
code += "obj, x)\n" + Indent + Indent + Indent + "return obj\n";
@@ -2543,7 +2534,7 @@ class PythonGenerator : public BaseGenerator {
25432534
code +=
25442535
GenIndents(1) + "if unionType == " + union_type + "()." + variant + ":";
25452536
code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
2546-
code += GenIndents(2) + "union = tab.String(table.Pos)";
2537+
code += GenIndents(2) + "union = tab.UnionString(table.Pos)";
25472538
code += GenIndents(2) + "return union";
25482539
}
25492540

src/idl_parser.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,10 @@ bool Parser::SupportsDefaultVectorsAndStrings() const {
26992699
}
27002700

27012701
bool Parser::SupportsAdvancedUnionFeatures() const {
2702+
// Advanced Union Features refers to the following features:
2703+
// - Vectors of unions
2704+
// - Strings in unions
2705+
// - structs in unions
27022706
return (opts.lang_to_generate &
27032707
~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp |
27042708
IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin |

tests/py_test.py

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
import union_vector.Attacker
5959
import union_vector.Character
6060
import union_vector.Movie
61+
import union_vector.Rapunzel
62+
import union_vector.BookReader
6163

6264

6365
def create_namespace_shortcut(is_onefile):
@@ -308,27 +310,41 @@ def test_default_values_with_pack_and_unpack(self):
308310
def test_union_vectors_with_pack_and_unpack(self):
309311
b = flatbuffers.Builder(0)
310312

313+
# Types of the characters
314+
types = [
315+
union_vector.Character.Character.MuLan,
316+
union_vector.Character.Character.Rapunzel,
317+
union_vector.Character.Character.Belle,
318+
union_vector.Character.Character.BookFan,
319+
union_vector.Character.Character.Other,
320+
union_vector.Character.Character.Unused,
321+
]
322+
# Pack the attacker manually
311323
union_vector.Attacker.Start(b)
312324
union_vector.Attacker.AddSwordAttackDamage(b, 1)
313325
attacker_offset = union_vector.Attacker.End(b)
314-
315-
union_vector.Attacker.Start(b)
316-
union_vector.Attacker.AddSwordAttackDamage(b, 2)
317-
attacker_offset2 = union_vector.Attacker.End(b)
318-
319-
characters = [attacker_offset, attacker_offset2]
320-
character_types = [union_vector.Character.Character.MuLan, union_vector.Character.Character.MuLan]
321-
322-
union_vector.Movie.StartCharactersTypeVector(b, len(character_types))
323-
for character_type in reversed(character_types):
326+
# Prepare the rest of the characters
327+
characters = [
328+
attacker_offset,
329+
union_vector.Rapunzel.CreateRapunzel(b, 2),
330+
union_vector.BookReader.CreateBookReader(b, 3),
331+
union_vector.BookReader.CreateBookReader(b, 4),
332+
b.CreateString("Other", "utf-8"),
333+
b.CreateString("Unused", "utf-8")
334+
]
335+
336+
# Pack the types
337+
union_vector.Movie.StartCharactersTypeVector(b, len(types))
338+
for character_type in reversed(types):
324339
b.PrependByte(character_type)
325340
character_types_offset = b.EndVector()
326-
341+
# Pack the characters
327342
union_vector.Movie.StartCharactersVector(b, len(characters))
328343
for character in reversed(characters):
329344
b.PrependUOffsetTRelative(character)
330345
characters_offset = b.EndVector()
331346

347+
# Pack the movie object
332348
union_vector.Movie.Start(b)
333349
union_vector.Movie.AddMainCharacterType(b, 0)
334350
union_vector.Movie.AddMainCharacter(b, 0)
@@ -337,18 +353,39 @@ def test_union_vectors_with_pack_and_unpack(self):
337353
movie_offset = union_vector.Movie.End(b)
338354
b.Finish(movie_offset)
339355

356+
# Unpack the movie object
340357
buf = b.Output()
341358
movie = union_vector.Movie.Movie.GetRootAsMovie(buf, 0)
342359

343-
self.assertEqual(movie.CharactersTypeLength(), len(character_types))
344-
self.assertEqual(movie.CharactersLength(), len(characters))
345-
self.assertEqual(movie.CharactersType(0), character_types[0])
346-
347-
character = union_vector.Attacker.Attacker()
348-
character.Init(movie.Characters(0).Bytes, movie.Characters(0).Pos)
349-
self.assertEqual(character.SwordAttackDamage(), 1)
350-
character.Init(movie.Characters(1).Bytes, movie.Characters(1).Pos)
351-
self.assertEqual(character.SwordAttackDamage(), 2)
360+
self.assertEqual(movie.CharactersType(0), union_vector.Character.Character.MuLan)
361+
self.assertEqual(movie.CharactersType(1), union_vector.Character.Character.Rapunzel)
362+
self.assertEqual(movie.CharactersType(2), union_vector.Character.Character.Belle)
363+
self.assertEqual(movie.CharactersType(3), union_vector.Character.Character.BookFan)
364+
self.assertEqual(movie.CharactersType(4), union_vector.Character.Character.Other)
365+
self.assertEqual(movie.CharactersType(5), union_vector.Character.Character.Unused)
366+
367+
attacker = union_vector.Attacker.Attacker()
368+
attacker.Init(movie.Characters(0).Bytes, movie.Characters(0).Pos)
369+
self.assertEqual(attacker.SwordAttackDamage(), 1)
370+
rapunzel = union_vector.Rapunzel.Rapunzel()
371+
rapunzel.Init(movie.Characters(1).Bytes, movie.Characters(1).Pos)
372+
self.assertEqual(rapunzel.HairLength(), 2)
373+
book_reader = union_vector.BookReader.BookReader()
374+
book_reader.Init(movie.Characters(2).Bytes, movie.Characters(2).Pos)
375+
self.assertEqual(book_reader.BooksRead(), 3)
376+
book_reader.Init(movie.Characters(3).Bytes, movie.Characters(3).Pos)
377+
self.assertEqual(book_reader.BooksRead(), 4)
378+
379+
other = union_vector.Character.CharacterCreator(
380+
union_vector.Character.Character.Other,
381+
movie.Characters(4)
382+
)
383+
self.assertEqual(other.decode("utf-8"), "Other")
384+
unused = union_vector.Character.CharacterCreator(
385+
union_vector.Character.Character.Unused,
386+
movie.Characters(5)
387+
)
388+
self.assertEqual(unused.decode("utf-8"), "Unused")
352389

353390
def test_optional_scalars_with_pack_and_unpack(self):
354391
""" Serializes and deserializes between a buffer with optional values (no

tests/union_vector/Character.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ def CharacterCreator(unionType, table):
2929
return BookReader.BookReaderT.InitFromBuf(table.Bytes, table.Pos)
3030
if unionType == Character().Other:
3131
tab = Table(table.Bytes, table.Pos)
32-
union = tab.String(table.Pos)
32+
union = tab.UnionString(table.Pos)
3333
return union
3434
if unionType == Character().Unused:
3535
tab = Table(table.Bytes, table.Pos)
36-
union = tab.String(table.Pos)
36+
union = tab.UnionString(table.Pos)
3737
return union
3838
return None

0 commit comments

Comments
 (0)