Revival of GH-7371: Added vector union support for Python#8680
Revival of GH-7371: Added vector union support for Python#8680jtdavis777 wants to merge 6 commits intogoogle:masterfrom
Conversation
|
|
9506d5c to
4168b59
Compare
4168b59 to
c5751ec
Compare
|
@fliiiix would you be up for helping me polish this PR up? I just rebased the original commits onto (a more recent) master, but enough things changed I would appreciate a second set of eyes to point out what still needs work. |
|
What's missing before this can go into master? I'm very interested in this feature. |
|
I am excited to see this PR! We have been using a fork with @surculus12's old diff for a couple years now. It is kind of wild that vector of unions was not supported before. Looking forward to seeing this get merged!! |
eric-quera
left a comment
There was a problem hiding this comment.
Agree. Would be great to get this merged in.
| auto vectortype = field.value.type.VectorType(); | ||
| if (vectortype.base_type == BASE_TYPE_STRUCT) { | ||
| GenUnPackForStructVector(struct_def, field, &code); | ||
| } else { |
There was a problem hiding this comment.
I'd expect GenUnPack here to also check for the BASE_TYPE_UNION here, a la
if base type is struct: GenUnPackForStructVector
elif base type is union: GenUnPackForUnionVector
else: GenUnPackForScalarVector
The java and csharp gen files do this, at least - why not the python?
| case BASE_TYPE_ARRAY: | ||
| case BASE_TYPE_VECTOR: { | ||
| auto vectortype = field.value.type.VectorType(); | ||
| if (vectortype.base_type == BASE_TYPE_STRUCT) { |
There was a problem hiding this comment.
Similarly here, the other language gen files check for BASE_TYPE_UNION within the vector type base, so something like
if BASE_TYPE_STRUCT
GenPackForStructVectorField
else if base_type == BASE_TYPE_UNION
GenPackForUnionVectorField
else
GenPackForScalarVectorField
| field_method + "())"; | ||
| } | ||
|
|
||
| void GenUnPackForStructVector(const StructDef& struct_def, |
There was a problem hiding this comment.
Heavily borrowing from the other two GenUnPacks,
void GenUnPackForUnionVector(const StructDef& struct_def,
const FieldDef& field,
std::string* code_ptr) const {
auto& code = *code_ptr;
const auto field_field = namer_.Field(field);
const auto field_method = namer_.Method(field);
const auto struct_var = namer_.Variable(struct_def);
const EnumDef& enum_def = *field.value.type.VectorType().enum_def;
auto union_type = namer_.Type(enum_def);
if (parser_.opts.include_dependence_headers) {
union_type = namer_.NamespacedType(enum_def) + "." + union_type;
}
code += GenIndents(2) + "if not " + struct_var + "." + field_method +
"IsNone():";
code += GenIndents(3) + "self." + field_field + " = []";
code += GenIndents(3) + "for i in range(" + struct_var + "." +
field_method + "Length()):";
// Call the union creator for each element, using the type vector
// Example Pattern I think? Character.CharacterCreator(movie.CharactersType(i), movie.Characters(i))
code += GenIndents(4) + "self." + field_field + ".append(" +
union_type + "Creator(" +
struct_var + "." + field_method + "Type(i), " +
struct_var + "." + field_method + "(i)))";
}
| code += ")\n"; | ||
| } | ||
|
|
||
| void GenPackForStructVectorField(const StructDef& struct_def, |
There was a problem hiding this comment.
Heavily borrowing from StructVector and Union GenPackFor*Field methods,
void GenPackForUnionVectorField(const StructDef& struct_def,
const FieldDef& field,
std::string* code_prefix_ptr,
std::string* code_ptr) const {
auto& code_prefix = *code_prefix_ptr;
auto& code = *code_ptr;
const auto field_field = namer_.Field(field);
const auto struct_type = namer_.Type(struct_def);
const auto field_method = namer_.Method(field);
// Creates the field - union vectors work like non-fixed struct vectors maybe?
code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
code_prefix += GenIndents(3) + field_field + "list = []";
code_prefix += GenIndents(3) + "for i in range(len(self." + field_field + ")):";
// Note: I have put no thought into how this should work for strings in unions
code_prefix += GenIndents(4) + "if self." + field_field + "[i] is not None:";
code_prefix += GenIndents(5) + field_field + "list.append(self." +
field_field + "[i].Pack(builder))";
code_prefix += GenIndents(4) + "else:";
code_prefix += GenIndents(5) + field_field + "list.append(0)";
code_prefix += GenIndents(3) + struct_type + "Start" + field_method +
"Vector(builder, len(self." + field_field + "))";
code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
field_field + "))):";
code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative(" +
field_field + "list[i])";
code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
code += GenIndents(2) + "if self." + field_field + " is not None:";
code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
field_field + ")";
}
There was a problem hiding this comment.
I have now put thought into how this should work for strings in unions
s/
code_prefix += GenIndents(5) + field_field + "list.append(self." +
field_field + "[i].Pack(builder))";
/
const EnumDef& enum_def = *field.value.type.VectorType().enum_def;
auto union_type = namer_.Type(enum_def);
if (parser_.opts.include_dependence_headers) {
union_type = namer_.NamespacedType(enum_def) + "." + union_type;
}
code_prefix += GenIndents(4) + field_field + "list.append(" +
union_type + "Pack(builder, self." + field_field + "[i], " +
"self." + field_field + "Type[i]))";
/g
to get some nonsense like the following characterslist.append(Character.CharacterPack(builder, self.characters[i], self.charactersType[i]))
| } | ||
| code += GenIndents(1) + "return None"; | ||
| code += "\n"; | ||
| } |
There was a problem hiding this comment.
See idl_gen_csharp.cpp:L1788-L1810 - probably want a GenUnionCreator
| std::string enumcode; | ||
| GenEnum(enum_def, &enumcode); | ||
| if (parser_.opts.generate_object_based_api & enum_def.is_union) { | ||
| GenUnionCreator(enum_def, &enumcode); |
There was a problem hiding this comment.
GetUnionCreator(...)
GetUnionPacker(...)
|
|
||
| // TODO(luwa): TypeT should be moved under the None check as well. | ||
| code_prefix += GenIndents(2) + "if self." + field_field + " is not None:"; | ||
| code_prefix += GenIndents(3) + field_field + " = self." + field_field + |
There was a problem hiding this comment.
Replace with
code_prefix += GenIndents(3) + field_field + " = " + union_type + "Pack(builder, self." + field_field + ", self." + field_field + "Type)";
Not that important but I think that's safer / more defensive for single unions with string members
|
@ZachMarcus thank you for the thorough review! I can probably work on incorporate these changes in the next couple days as I have time, or feel free to PR them into my fork if you feel so inspired. |
|
It would be great to get this merged! Any update? |
|
I am also looking for these changes. Hope to get this merged soon! |
|
Hey all, I see your comments! Give me a week or two and I'll do my best to polish this up and see about getting it merged. |
|
I promise I still hope to get back to this PR to get it merged, thank you to everyone for your patience :) |
I wanted to revisit GH-7371 (fixes #4530) to add Advanced Unions support to python.
All credit for the base work goes to @surculus12 (and I cherry picked their commits over to preserve authorship) - I'm only coming in to get it up to date with the current repo and hopefully get it across the finish line.
I will address the last PR comments left on the original PR as and if they still apply.