Skip to content

Conversation

@CasperN
Copy link
Collaborator

@CasperN CasperN commented Mar 7, 2021

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 :)

@github-actions github-actions bot added c++ codegen Involving generating code from schema rust swift labels Mar 7, 2021
@CasperN CasperN requested review from mustiikhalil and vglavnyy March 7, 2021 00:53
return Error("default value of " + field->value.constant +
" for field " + name + " is not part of enum " +
type.enum_def->name);

Copy link
Contributor

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");
}

Copy link
Collaborator Author

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

Copy link
Contributor

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.

@CasperN
Copy link
Collaborator Author

CasperN commented Mar 8, 2021

@mustiikhalil, I might need some guidance on how to fix swift.

Why were enums excluded in this line?

if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&

@mustiikhalil
Copy link
Collaborator

mustiikhalil commented Mar 9, 2021

So there are two issues there;
1- the use of Void void is a reserved word in swift, and it's not being checked for that (#6507 already fixing that here).
2- warning: the Swift runtime was unable to demangle the type of field ''. the mangled type name is ''. this field will show up as an empty tuple in Mirrors swift doesn't like it when we cast values into enums since enums in swift work in a weird way. So my suggestion would be that we disable this, until a proper solution is found

/// [...., 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 fatalError

@mustiikhalil
Copy link
Collaborator

@CasperN what is the status on this? i am not sure if you saw the comment i made

@CasperN
Copy link
Collaborator Author

CasperN commented Mar 15, 2021

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)) }
Copy link
Collaborator

@mustiikhalil mustiikhalil Mar 16, 2021

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

Copy link
Collaborator Author

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good

Comment on lines 769 to 771

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_ +=
Copy link
Collaborator

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

@CasperN
Copy link
Collaborator Author

CasperN commented Apr 2, 2021

hi all, sorry this one is taking so long, I've been busy recently

@CasperN
Copy link
Collaborator Author

CasperN commented Apr 2, 2021

I don't know what the buildkite failure is, seems transient

@mustiikhalil
Copy link
Collaborator

@CasperN fixed it

@CasperN
Copy link
Collaborator Author

CasperN commented Apr 5, 2021

Can I get LGTMs before I merge, @mustiikhalil @vglavnyy?

Copy link
Collaborator

@mustiikhalil mustiikhalil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vglavnyy
Copy link
Contributor

vglavnyy commented Apr 6, 2021

LGTM

@CasperN CasperN merged commit 261cf3b into google:master Apr 6, 2021
@CasperN CasperN deleted the tst branch August 24, 2021 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ codegen Involving generating code from schema rust swift

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants