-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Default-empty vectors of enums #6505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/idl_parser.cpp
Outdated
| return Error("default value of " + field->value.constant + | ||
| " for field " + name + " is not part of enum " + | ||
| type.enum_def->name); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current if(IsVector(type))-else is more readable than proposed solution. The else branch covers only scalars or enums.
With the new solution, any high-level error (like = [1,2,3]) will be ignored.
Instead of FLATBUFFERS_ASSERT just before if(IsVector(type)) it might be better to write full decision tree including IsArray, for example:
if (type.base_type == BASE_TYPE_UNION) {
if(field->value.constant != "0") return Error("");
} else if (IsInteger(type.base_type)) {
...
} else if (IsVector(type)) {
FLATBUFFERS_ASSERT(field->value.constant == "0" || field->value.constant == "[]");
} else if (IsArray(type)) {
FLATBUFFERS_ASSERT(field->value.constant == "0");
} else {
FLATBUFFERS_ASSERT(false && "unexpected type");
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I refactored away the asserts and used a chain of if/else. PTAL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, looks good.
// Optional and bitflags enums may have default constants that are not
// their specified variants.
Optional fields might have only null initializer to indicate optionality, so it never can be an enum's variant.
|
@mustiikhalil, I might need some guidance on how to fix swift. Why were enums excluded in this line? flatbuffers/src/idl_gen_swift.cpp Line 769 in b240ab7
|
|
So there are two issues there; /// [...., 1, 2, 8, 0] output byte buffer of an encoded array of enums
/// when we try to read it with the enum below swift will return the error mentioned above,
/// and will give us the following array [FlatBuffers_Test_SwiftTests.ABC.b, FlatBuffers_Test_SwiftTests.ABC.c,
/// FlatBuffers_Test_SwiftTests.ABC.()]
/// Composite components of Monster color.
public enum abc: UInt8, Enum {
case a = 1
case b = 2
case c = 8
}3- Sometimes casting enums would actually cause a |
|
@CasperN what is the status on this? i am not sure if you saw the comment i made |
|
Yea I saw your comment. I just didn't find time to work on this briefly. It sounds like this problem with enums is much bigger than default-empty-vector-of-enums. Perhaps Swift should model enums C style? I made a change like that for Rust #6098 since the old way caused UB. |
| public var anyAmbiguousType: MyGame_Example_AnyAmbiguousAliases { let o = _accessor.offset(VTOFFSET.anyAmbiguousType.v); return o == 0 ? .none_ : MyGame_Example_AnyAmbiguousAliases(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ } | ||
| public func anyAmbiguous<T: FlatBufferObject>(type: T.Type) -> T? { let o = _accessor.offset(VTOFFSET.anyAmbiguous.v); return o == 0 ? nil : _accessor.union(o) } | ||
| public var vectorOfEnumsCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfEnums.v); return o == 0 ? 0 : _accessor.vector(count: o) } | ||
| public func vectorOfEnums(at index: Int32) -> MyGame_Example_Color? { let o = _accessor.offset(VTOFFSET.vectorOfEnums.v); return o == 0 ? MyGame_Example_Color.red : MyGame_Example_Color(rawValue: _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1)) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enums in swift isn't completely a problem, since when we actually fetch the values we fetch them as Integers and then use the rawValue initializer to map the integers to actual swift enums. That's why we disabled the return of entire vectors, but if we really want it as a part of the API, then they start becoming an issue.
I see two ways of moving forward here,
1- Implementing it C style. By using a swift struct, that should definitely be possible.
struct Color: Enum {
public static var red = Color(0)
...
var value: Uint8
var named: String {
switch { ... }
}
}2- We create return _accessor.getVectorOfEnums(at: VTOFFSET.vectorOfEnums.v) which returns the numeric values of enums and then we can use map to convert the values to enums. This would affect the performance for sure.
Depending on what we want moving forward, the swift implementation would change to adapt to it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so for the purposes of this PR, I'll just remove "returning the entire vector" from the API. Its up to you if you want to add that in the future or change how enums are modelled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
|
|
||
| if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) && | ||
| !IsBool(field.value.type.base_type)) { | ||
| if (IsScalar(vectortype.base_type) && !IsBool(field.value.type.base_type)) { | ||
| code_ += |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should still not allow enums since enums have their own way of returning their object:
if (IsEnum(vectortype)) {
code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
" : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
"{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
"index * {{SIZE}})) }";
return;
}This will eventually depend on what we go with in my comment ofc
|
hi all, sorry this one is taking so long, I've been busy recently |
|
I don't know what the buildkite failure is, seems transient |
|
@CasperN fixed it |
|
Can I get LGTMs before I merge, @mustiikhalil @vglavnyy? |
mustiikhalil
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
LGTM |
This PR implements default-empty vectors of enums for #6053, which was omitted in #6421 and #6461.
Unlike the last time I did this, I didn't make
more_defaults2.fbs, I just patched Swift and Rust together :)