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
[swift] distinguish unknown from absent enum value for scheme evolution #8231
Comments
Hej |
Hi @mustiikhalil I believe that ideally would be (1) with some extension (maybe under option) to generate public struct EnumUnknown_A: RawRepresentable, Enum, Verifiable {
public typealias T = Int8
public static var byteSize: Int { return MemoryLayout<Int8>.size }
public var value: Int8 { return self.rawValue }
public var rawValue: Int8
public static var a: EnumUnknown_A = .init(rawValue: 0)
public static var b: EnumUnknown_A = .init(rawValue: 1)
public static var max: EnumUnknown_A { return .b }
public static var min: EnumUnknown_A { return .a }
} That way, any unknown value can be propagated to the client code while structure remain What do you think about that? I like both other options - they can always be a part of generated code. |
@blindspotbounty The whole idea of having it as an enum is that the options are constrained so I don't think making it a struct would be an option here. However, after a bit of thinking maybe we can do something like this: // Flatbuffers
// - Sources/EnumValues.swift
public enum EnumValues<T> where T: Enum {
case found(v: T)
case unknown(v: Any)
} And then we can add an API that does the following: public enum EnumUnknown_A: Int8, Enum, Verifiable {
...
public static func wrapped(_ v: Int8) -> EnumValues<EnumUnknown_A> {
guard let e = EnumUnknown_A(rawValue: v) else { return .unknown(v: v) }
return .found(v: e)
}
}
public struct EnumUnknown_foo: FlatBufferObject, Verifiable {
...
/// New API?
public var value: EnumValues<EnumUnknown_A>? {
let o = _accessor.offset(VTOFFSET.value.v)
if o == 0 { return nil }
return EnumUnknown_A.wrapped(_accessor.readBuffer(of: Int8.self, at: o)
}
// maybe keep the original one
public var value: EnumUnknown_A? { let o = _accessor.offset(VTOFFSET.value.v); return o == 0 ? nil : EnumUnknown_A(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? nil }
...
} Or we can also leverage the What do you think? From my point of view this is safer than allowing the user to get any value from the buffer, instead of just creating a struct that you can pass to it any value kinda |
@mustiikhalil thank you for you input and I apologize for the late answer. That looks good to me. I think I can try propose PR next days if you don't mind, do you think we should do it under option or add some new accessors indefinitely? Btw, have one more use case comes to mind (it is out of scope but nice to have in future) is to allow to propagate such field.
and the corresponding code: extension EnumUnknown_Foo {
...
mutating func update(_ update: EnumUnknown_FooUpdate) {
if let value = update.value {
self.mutate(value: value)
}
}
|
@blindspotbounty No worries
Yeah that would be amazing!
So I don't want to add extra flags to the code generator so i would say just adding it normally would be alright. However we will keep the original one. So what i think would be useful is something like this: // Original
public var value: EnumUnknown_A? { ... }
// + new one
public var unsafeValue: EnumValue<EnumUnknown_A>? { ... } Since in theory we are reading memory that's not planned for with the generated code. and thus making it unsafe although its been verified that its within the buffer. |
We discovered that on enum scheme evolution we cannot distinguish absent value from unknown one.
There is an example of scheme evolution.
First version:
Second version:
Generating code for them:
Code for v1:
Code for v2:
Now, from v2 I can create table with:
or:
If I send and read the same buffer in older version, it won't be possible to distinguish unknown value or its absence:
Could you suggest if it would be possible to implement distinguishing these two variants, please?
The text was updated successfully, but these errors were encountered: