From 4c7a9c10d31ecea7b72fed50d735cecea248b6ea Mon Sep 17 00:00:00 2001 From: mustiikhalil Date: Thu, 7 Oct 2021 23:22:22 +0200 Subject: [PATCH] Adds JSON encoding to swift (#6874) Updates generated code & removes unneeded protocol Updates cpp to only generate code when flag is passed Updates code gen script --- grpc/examples/generate.sh | 2 +- .../Sources/Model/greeter_generated.swift | 22 + grpc/examples/ts/greeter/src/greeter.ts | 2 + include/flatbuffers/idl.h | 2 + scripts/generate_code.py | 2 +- src/flatc.cpp | 3 + src/idl_gen_swift.cpp | 222 ++++++- .../SwiftFlatBuffers/fuzzer_generated.swift | 116 +++- tests/FlatBuffers.Test.Swift/SwiftTest.sh | 8 +- .../FlatBuffersMonsterWriterTests.swift | 20 + .../FlatBuffersUnionTests.swift | 43 ++ .../FlatbuffersMoreDefaults.swift | 20 + .../monster_test_generated.swift | 556 +++++++++++++++++- .../more_defaults_generated.swift | 44 ++ .../optional_scalars_generated.swift | 140 +++++ .../union_vector_generated.swift | 134 ++++- tests/generate_code.sh | 8 +- 17 files changed, 1324 insertions(+), 20 deletions(-) create mode 100644 grpc/examples/ts/greeter/src/greeter.ts diff --git a/grpc/examples/generate.sh b/grpc/examples/generate.sh index 39ca6620c..0f051da8e 100755 --- a/grpc/examples/generate.sh +++ b/grpc/examples/generate.sh @@ -58,7 +58,7 @@ cd ${current_dir} cd swift cd Greeter/Sources/Model -fbc --bfbs-filenames ../../../.. --swift ${generator} +fbc --bfbs-filenames ../../../.. --swift --gen-json-emit ${generator} cd ${current_dir} diff --git a/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift b/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift index bc1eca3cb..a7c420bc1 100644 --- a/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift +++ b/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift @@ -42,6 +42,17 @@ public struct models_HelloReply: FlatBufferObject, Verifiable { } } +extension models_HelloReply: Encodable { + + enum CodingKeys: String, CodingKey { + case message = "message" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(message, forKey: .message) + } +} + public struct models_HelloRequest: FlatBufferObject, Verifiable { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -80,3 +91,14 @@ public struct models_HelloRequest: FlatBufferObject, Verifiable { } } +extension models_HelloRequest: Encodable { + + enum CodingKeys: String, CodingKey { + case name = "name" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(name, forKey: .name) + } +} + diff --git a/grpc/examples/ts/greeter/src/greeter.ts b/grpc/examples/ts/greeter/src/greeter.ts new file mode 100644 index 000000000..5e62d9994 --- /dev/null +++ b/grpc/examples/ts/greeter/src/greeter.ts @@ -0,0 +1,2 @@ +export { HelloReply } from './models/hello-reply'; +export { HelloRequest } from './models/hello-request'; diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 482804939..3ee02a95f 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -568,6 +568,7 @@ struct IDLOptions { bool gen_nullable; bool java_checkerframework; bool gen_generated; + bool gen_json_coders; std::string object_prefix; std::string object_suffix; bool union_value_namespacing; @@ -662,6 +663,7 @@ struct IDLOptions { gen_nullable(false), java_checkerframework(false), gen_generated(false), + gen_json_coders(false), object_suffix("T"), union_value_namespacing(true), allow_non_utf8(false), diff --git a/scripts/generate_code.py b/scripts/generate_code.py index c2287e1f1..13968c5ec 100755 --- a/scripts/generate_code.py +++ b/scripts/generate_code.py @@ -90,7 +90,7 @@ CPP_17_OPTS = NO_INCL_OPTS + [ RUST_OPTS = BASE_OPTS + ["--rust", "--gen-all", "--gen-name-strings"] TS_OPTS = ["--ts", "--gen-name-strings"] LOBSTER_OPTS = ["--lobster"] -SWIFT_OPTS = ["--swift", "--bfbs-filenames", str(tests_path)] +SWIFT_OPTS = ["--swift", "--gen-json-emit", "--bfbs-filenames", str(tests_path)] JAVA_OPTS = ["--java"] KOTLIN_OPTS = ["--kotlin"] PHP_OPTS = ["--php"] diff --git a/src/flatc.cpp b/src/flatc.cpp index 1505783c3..fc3cc9221 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -113,6 +113,7 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { " If the language uses a single file for output (by default\n" " the case for C++ and JS), all code will end up in this one\n" " file.\n" + " --gen-json-emit Generates encoding code which emits Flatbuffers into JSON\n" " --cpp-include Adds an #include in generated file.\n" " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n" " --cpp-str-type T Set object API string type (default std::string).\n" @@ -308,6 +309,8 @@ int FlatCompiler::Compile(int argc, const char **argv) { opts.java_checkerframework = true; } else if (arg == "--gen-generated") { opts.gen_generated = true; + } else if (arg == "--gen-json-emit") { + opts.gen_json_coders = true; } else if (arg == "--object-prefix") { if (++argi >= argc) Error("missing prefix following: " + arg, true); opts.object_prefix = argv[argi]; diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp index 762cd291f..bb54b6828 100644 --- a/src/idl_gen_swift.cpp +++ b/src/idl_gen_swift.cpp @@ -188,7 +188,8 @@ class SwiftGenerator : public BaseGenerator { GenComment(struct_def.doc_comment); code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def)); code_ += - "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct, Verifiable\\"; + "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct, Verifiable, " + "FlatbuffersInitializable\\"; if (parser_.opts.generate_object_based_api) code_ += ", NativeObject\\"; code_ += " {"; code_ += ""; @@ -229,6 +230,7 @@ class SwiftGenerator : public BaseGenerator { constructor += name + ": " + type; } code_ += ""; + BuildStructConstructor(struct_def); BuildObjectConstructor(main_constructor, constructor); BuildObjectConstructor(base_constructor, ""); @@ -262,6 +264,37 @@ class SwiftGenerator : public BaseGenerator { code_ += "}"; Outdent(); code_ += "}\n"; + if (parser_.opts.gen_json_coders) + GenerateJSONEncodingAPIs(struct_def); + } + + void BuildStructConstructor(const StructDef &struct_def) { + code_ += "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) {"; + Indent(); + code_ += "let {{ACCESS}} = Struct(bb: bb, position: o)"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto name = Name(field); + auto type = field.value.type; + code_.SetValue("VALUENAME", name); + code_.SetValue("VALUETYPE", GenType(type)); + code_.SetValue("OFFSET", NumToString(field.value.offset)); + if (IsScalar(type.base_type)) { + if (IsEnum(type)) + code_.SetValue("VALUETYPE", GenTypeBasic(field.value.type, false)); + code_ += + "_{{VALUENAME}} = {{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, " + "at: {{OFFSET}})"; + } else { + code_ += + "_{{VALUENAME}} = {{VALUETYPE}}({{ACCESS}}.bb, o: " + "{{ACCESS}}.postion + {{OFFSET}})"; + } + } + Outdent(); + code_ += "}\n"; } void GenMutableStructReader(const StructDef &struct_def) { @@ -378,7 +411,6 @@ class SwiftGenerator : public BaseGenerator { void GenTable(const StructDef &struct_def) { auto is_private_access = struct_def.attributes.Lookup("private"); code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public"); - GenObjectHeader(struct_def); GenTableAccessors(struct_def); GenTableReader(struct_def); @@ -389,6 +421,8 @@ class SwiftGenerator : public BaseGenerator { GenerateVerifier(struct_def); Outdent(); code_ += "}\n"; + if (parser_.opts.gen_json_coders) + GenerateJSONEncodingAPIs(struct_def); } // Generates the reader for swift @@ -846,6 +880,166 @@ class SwiftGenerator : public BaseGenerator { } } + void GenerateCodingKeys(const StructDef &struct_def) { + code_ += "enum CodingKeys: String, CodingKey {"; + Indent(); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto name = Name(field); + + code_.SetValue("RAWVALUENAME", field.name); + code_.SetValue("VALUENAME", name); + code_ += "case {{VALUENAME}} = \"{{RAWVALUENAME}}\""; + } + Outdent(); + code_ += "}"; + } + + void GenerateEncoderUnionBody(const FieldDef &field) { + EnumDef &union_def = *field.value.type.enum_def; + auto is_vector = field.value.type.base_type == BASE_TYPE_VECTOR || + field.value.type.base_type == BASE_TYPE_ARRAY; + if (field.value.type.base_type == BASE_TYPE_UTYPE || + (is_vector && + field.value.type.VectorType().base_type == BASE_TYPE_UTYPE)) + return; + if (is_vector) { + code_ += + "var enumsEncoder = container.nestedUnkeyedContainer(forKey: " + ".{{VALUENAME}}Type)"; + code_ += + "var contentEncoder = container.nestedUnkeyedContainer(forKey: " + ".{{VALUENAME}})"; + code_ += "for index in 0..<{{VALUENAME}}Count {"; + Indent(); + code_ += + "guard let type = {{VALUENAME}}Type(at: index) else { continue }"; + code_ += "try enumsEncoder.encode(type)"; + code_ += "switch type {"; + for (auto it = union_def.Vals().begin(); it != union_def.Vals().end(); + ++it) { + const auto &ev = **it; + + auto name = Name(ev); + auto type = GenType(ev.union_type); + code_.SetValue("KEY", name); + code_.SetValue("VALUETYPE", type); + if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } + code_ += "case .{{KEY}}:"; + Indent(); + code_ += "let _v = {{VALUENAME}}(at: index, type: {{VALUETYPE}}.self)"; + code_ += "try contentEncoder.encode(_v)"; + Outdent(); + } + code_ += "default: break;"; + code_ += "}"; + Outdent(); + code_ += "}"; + return; + } + + code_ += "switch {{VALUENAME}}Type {"; + for (auto it = union_def.Vals().begin(); it != union_def.Vals().end(); + ++it) { + const auto &ev = **it; + + auto name = Name(ev); + auto type = GenType(ev.union_type); + code_.SetValue("KEY", name); + code_.SetValue("VALUETYPE", type); + if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } + code_ += "case .{{KEY}}:"; + Indent(); + code_ += "let _v = {{VALUENAME}}(type: {{VALUETYPE}}.self)"; + code_ += "try container.encodeIfPresent(_v, forKey: .{{VALUENAME}})"; + Outdent(); + } + code_ += "default: break;"; + code_ += "}"; + } + + void GenerateEncoderBody(const StructDef &struct_def) { + code_ += "var container = encoder.container(keyedBy: CodingKeys.self)"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto name = Name(field); + auto type = field.value.type; + + auto is_non_union_vector = + (field.value.type.base_type == BASE_TYPE_ARRAY || + field.value.type.base_type == BASE_TYPE_VECTOR) && + field.value.type.VectorType().base_type != BASE_TYPE_UTYPE; + + code_.SetValue("RAWVALUENAME", field.name); + code_.SetValue("VALUENAME", name); + code_.SetValue("CONSTANT", field.value.constant); + bool should_indent = true; + if (is_non_union_vector) { + code_ += "if {{VALUENAME}}Count > 0 {"; + } else if (IsEnum(type) && !field.IsOptional()) { + code_.SetValue("CONSTANT", GenEnumDefaultValue(field)); + code_ += "if {{VALUENAME}} != {{CONSTANT}} {"; + } else if (IsScalar(type.base_type) && !IsEnum(type) && + !IsBool(type.base_type) && !field.IsOptional()) { + code_ += "if {{VALUENAME}} != {{CONSTANT}} {"; + } else if (IsBool(type.base_type) && !field.IsOptional()) { + std::string default_value = + "0" == field.value.constant ? "false" : "true"; + code_.SetValue("CONSTANT", default_value); + code_ += "if {{VALUENAME}} != {{CONSTANT}} {"; + } else { + should_indent = false; + } + if (should_indent) Indent(); + + if (IsUnion(type) && !IsEnum(type)) { + GenerateEncoderUnionBody(field); + } else if (is_non_union_vector && + (!IsScalar(type.VectorType().base_type) || + IsEnum(type.VectorType()))) { + code_ += + "var contentEncoder = container.nestedUnkeyedContainer(forKey: " + ".{{VALUENAME}})"; + code_ += "for index in 0..<{{VALUENAME}}Count {"; + Indent(); + code_ += "guard let type = {{VALUENAME}}(at: index) else { continue }"; + code_ += "try contentEncoder.encode(type)"; + Outdent(); + code_ += "}"; + } else { + code_ += + "try container.encodeIfPresent({{VALUENAME}}, forKey: " + ".{{VALUENAME}})"; + } + if (should_indent) Outdent(); + + if (is_non_union_vector || + (IsScalar(type.base_type) && !field.IsOptional())) { + code_ += "}"; + } + } + } + + void GenerateJSONEncodingAPIs(const StructDef &struct_def) { + code_ += "extension {{STRUCTNAME}}: Encodable {"; + Indent(); + code_ += ""; + if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def); + + code_ += "public func encode(to encoder: Encoder) throws {"; + Indent(); + if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def); + Outdent(); + code_ += "}"; + Outdent(); + code_ += "}"; + code_ += ""; + } + void GenerateVerifier(const StructDef &struct_def) { code_ += "public static func verify(_ verifier: inout Verifier, at position: " @@ -1002,6 +1196,9 @@ class SwiftGenerator : public BaseGenerator { AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min"); Outdent(); code_ += "}\n"; + if (parser_.opts.gen_json_coders) + EnumEncoder(enum_def); + code_ += ""; if (parser_.opts.generate_object_based_api && enum_def.is_union) { code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {"; Indent(); @@ -1026,6 +1223,27 @@ class SwiftGenerator : public BaseGenerator { } } + void EnumEncoder(const EnumDef &enum_def) { + code_ += "extension {{ENUM_NAME}}: Encodable {"; + Indent(); + code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {"; + Indent(); + code_ += "var container = encoder.singleValueContainer()"; + code_ += "switch self {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const auto &ev = **it; + auto name = Name(ev); + code_.SetValue("KEY", name); + code_.SetValue("RAWKEY", ev.name); + code_ += "case .{{KEY}}: try container.encode(\"{{RAWKEY}}\")"; + } + code_ += "}"; + Outdent(); + code_ += "}"; + Outdent(); + code_ += "}"; + } + // MARK: - Object API void GenerateObjectAPIExtensionHeader(std::string name) { diff --git a/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer_generated.swift b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer_generated.swift index dffeaa87b..705138005 100644 --- a/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer_generated.swift @@ -19,7 +19,18 @@ public enum Color: UInt8, Enum, Verifiable { public static var min: Color { return .red } } -public struct Test: NativeStruct, Verifiable { +extension Color: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .red: try container.encode("Red") + case .green: try container.encode("Green") + case .blue: try container.encode("Blue") + } + } +} + +public struct Test: NativeStruct, Verifiable, FlatbuffersInitializable { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -27,6 +38,12 @@ public struct Test: NativeStruct, Verifiable { private var _b: Int8 private let padding0__: UInt8 = 0 + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _a = _accessor.readBuffer(of: Int16.self, at: 0) + _b = _accessor.readBuffer(of: Int8.self, at: 2) + } + public init(a: Int16, b: Int8) { _a = a _b = b @@ -45,6 +62,23 @@ public struct Test: NativeStruct, Verifiable { } } +extension Test: Encodable { + + enum CodingKeys: String, CodingKey { + case a = "a" + case b = "b" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if a != 0 { + try container.encodeIfPresent(a, forKey: .a) + } + if b != 0 { + try container.encodeIfPresent(b, forKey: .b) + } + } +} + public struct Test_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -57,7 +91,7 @@ public struct Test_Mutable: FlatBufferObject { public var b: Int8 { return _accessor.readBuffer(of: Int8.self, at: 2) } } -public struct Vec3: NativeStruct, Verifiable { +public struct Vec3: NativeStruct, Verifiable, FlatbuffersInitializable { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -71,6 +105,16 @@ public struct Vec3: NativeStruct, Verifiable { private var _test3: Test private let padding2__: UInt16 = 0 + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _x = _accessor.readBuffer(of: Float32.self, at: 0) + _y = _accessor.readBuffer(of: Float32.self, at: 4) + _z = _accessor.readBuffer(of: Float32.self, at: 8) + _test1 = _accessor.readBuffer(of: Double.self, at: 16) + _test2 = _accessor.readBuffer(of: UInt8.self, at: 24) + _test3 = Test(_accessor.bb, o: _accessor.postion + 26) + } + public init(x: Float32, y: Float32, z: Float32, test1: Double, test2: Color, test3: Test) { _x = x _y = y @@ -101,6 +145,37 @@ public struct Vec3: NativeStruct, Verifiable { } } +extension Vec3: Encodable { + + enum CodingKeys: String, CodingKey { + case x = "x" + case y = "y" + case z = "z" + case test1 = "test1" + case test2 = "test2" + case test3 = "test3" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if x != 0.0 { + try container.encodeIfPresent(x, forKey: .x) + } + if y != 0.0 { + try container.encodeIfPresent(y, forKey: .y) + } + if z != 0.0 { + try container.encodeIfPresent(z, forKey: .z) + } + if test1 != 0.0 { + try container.encodeIfPresent(test1, forKey: .test1) + } + if test2 != .red { + try container.encodeIfPresent(test2, forKey: .test2) + } + try container.encodeIfPresent(test3, forKey: .test3) + } +} + public struct Vec3_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -222,3 +297,40 @@ public struct Monster: FlatBufferObject, Verifiable { } } +extension Monster: Encodable { + + enum CodingKeys: String, CodingKey { + case pos = "pos" + case mana = "mana" + case hp = "hp" + case name = "name" + case testarrayoftables = "testarrayoftables" + case inventory = "inventory" + case color = "color" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(pos, forKey: .pos) + if mana != 150 { + try container.encodeIfPresent(mana, forKey: .mana) + } + if hp != 100 { + try container.encodeIfPresent(hp, forKey: .hp) + } + try container.encodeIfPresent(name, forKey: .name) + if testarrayoftablesCount > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .testarrayoftables) + for index in 0.. 0 { + try container.encodeIfPresent(inventory, forKey: .inventory) + } + if color != .blue { + try container.encodeIfPresent(color, forKey: .color) + } + } +} + diff --git a/tests/FlatBuffers.Test.Swift/SwiftTest.sh b/tests/FlatBuffers.Test.Swift/SwiftTest.sh index 7edf81772..6972c562c 100755 --- a/tests/FlatBuffers.Test.Swift/SwiftTest.sh +++ b/tests/FlatBuffers.Test.Swift/SwiftTest.sh @@ -5,14 +5,14 @@ alias fbc='${test_dir}/../flatc' shopt -s expand_aliases cd ${swift_dir}/Tests/FlatBuffers.Test.SwiftTests -fbc --swift --gen-mutable --grpc --gen-object-api -I ${test_dir}/include_test ${test_dir}/monster_test.fbs ${test_dir}/union_vector/union_vector.fbs -fbc --swift ${test_dir}/optional_scalars.fbs -fbc --swift --gen-object-api ${test_dir}/more_defaults.fbs +fbc --swift --gen-mutable --grpc --gen-json-emit --gen-object-api -I ${test_dir}/include_test ${test_dir}/monster_test.fbs ${test_dir}/union_vector/union_vector.fbs +fbc --swift --gen-json-emit ${test_dir}/optional_scalars.fbs +fbc --swift --gen-json-emit --gen-object-api ${test_dir}/more_defaults.fbs cd ${swift_dir} cd ${swift_dir}/Sources/SwiftFlatBuffers # create better fuzzing test file -fbc --swift fuzzer.fbs +fbc --swift --gen-json-emit fuzzer.fbs cd ${swift_dir} swift build --build-tests diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift index 4b83e7471..9f02d8d94 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift @@ -372,4 +372,24 @@ class FlatBuffersMonsterWriterTests: XCTestCase { XCTAssertEqual(sum0 + sum1, 100) XCTAssertEqual(monster.testbool, true) } + + func testEncoding() { + let fbb = createMonster(withPrefix: false) + var sizedBuffer = fbb.sizedBuffer + do { + let reader: Monster = try getCheckedRoot(byteBuffer: &sizedBuffer) + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + let data = try encoder.encode(reader) + XCTAssertEqual(data, jsonData.data(using: .utf8)) + } catch { + XCTFail(error.localizedDescription) + } + } + + var jsonData: String { + """ + {\"hp\":80,\"inventory\":[0,1,2,3,4],\"test\":{\"name\":\"Fred\"},\"testarrayofstring\":[\"test1\",\"test2\"],\"testarrayoftables\":[{\"name\":\"Barney\"},{\"name\":\"Frodo\"},{\"name\":\"Wilma\"}],\"test4\":[{\"a\":30,\"b\":40},{\"a\":10,\"b\":20}],\"testbool\":true,\"test_type\":\"Monster\",\"pos\":{\"y\":2,\"test3\":{\"a\":5,\"b\":6},\"z\":3,\"x\":1,\"test1\":3,\"test2\":\"Green\"},\"name\":\"MyMonster\"} + """ + } } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift index 3b6f194a6..eb8a10c5c 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift @@ -207,6 +207,49 @@ final class FlatBuffersUnionTests: XCTestCase { 7) XCTAssertEqual(packedMovie.characters(at: 1, type: String.self), string) } + + func testEncoding() { + let string = "Awesome \\\\t\t\nstring!" + var fb = FlatBufferBuilder() + + let stringOffset = fb.create(string: string) + + let swordDmg: Int32 = 8 + let attackStart = Attacker.startAttacker(&fb) + Attacker.add(swordAttackDamage: swordDmg, &fb) + let attack = Attacker.endAttacker(&fb, start: attackStart) + + let characterType: [Character] = [.belle, .mulan, .bookfan, .other] + + let characters = [ + fb.create(struct: BookReader(booksRead: 7)), + attack, + fb.create(struct: BookReader(booksRead: 2)), + stringOffset, + ] + let types = fb.createVector(characterType) + let characterVector = fb.createVector(ofOffsets: characters) + let end = Movie.createMovie( + &fb, + charactersTypeVectorOffset: types, + charactersVectorOffset: characterVector) + Movie.finish(&fb, end: end) + + var sizedBuffer = fb.sizedBuffer + do { + let reader: Movie = try getCheckedRoot(byteBuffer: &sizedBuffer) + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + let data = try encoder.encode(reader) + XCTAssertEqual(data, jsonData.data(using: .utf8)) + } catch { + XCTFail(error.localizedDescription) + } + } + + var jsonData: String { + "{\"characters_type\":[\"Belle\",\"MuLan\",\"BookFan\",\"Other\"],\"characters\":[{\"books_read\":7},{\"sword_attack_damage\":8},{\"books_read\":2},\"Awesome \\\\\\\\t\\t\\nstring!\"]}" + } } public enum ColorsNameSpace { diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersMoreDefaults.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersMoreDefaults.swift index 2839d2a54..cd97f25a2 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersMoreDefaults.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersMoreDefaults.swift @@ -57,4 +57,24 @@ class FlatBuffersMoreDefaults: XCTestCase { XCTAssertEqual(fDefaults.abcsCount, 0) XCTAssertEqual(fDefaults.boolsCount, 0) } + + func testEncoding() { + var fbb = FlatBufferBuilder() + let root = MoreDefaults.createMoreDefaults(&fbb) + fbb.finish(offset: root) + var sizedBuffer = fbb.sizedBuffer + do { + let reader: MoreDefaults = try getCheckedRoot(byteBuffer: &sizedBuffer) + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + let data = try encoder.encode(reader) + XCTAssertEqual(data, jsonData.data(using: .utf8)) + } catch { + XCTFail(error.localizedDescription) + } + } + + var jsonData: String { + "{\"empty_string\":\"\",\"some_string\":\"some\"}" + } } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift index 9925ac3ce..786c73b7a 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift @@ -20,6 +20,17 @@ public enum MyGame_Example_Color: UInt8, Enum, Verifiable { public static var min: MyGame_Example_Color { return .red } } +extension MyGame_Example_Color: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .red: try container.encode("Red") + case .green: try container.encode("Green") + case .blue: try container.encode("Blue") + } + } +} + public enum MyGame_Example_Race: Int8, Enum, Verifiable { public typealias T = Int8 public static var byteSize: Int { return MemoryLayout.size } @@ -33,6 +44,18 @@ public enum MyGame_Example_Race: Int8, Enum, Verifiable { public static var min: MyGame_Example_Race { return .none_ } } +extension MyGame_Example_Race: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .none_: try container.encode("None") + case .human: try container.encode("Human") + case .dwarf: try container.encode("Dwarf") + case .elf: try container.encode("Elf") + } + } +} + public enum MyGame_Example_Any_: UInt8, UnionEnum { public typealias T = UInt8 @@ -51,6 +74,18 @@ public enum MyGame_Example_Any_: UInt8, UnionEnum { public static var min: MyGame_Example_Any_ { return .none_ } } +extension MyGame_Example_Any_: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .none_: try container.encode("NONE") + case .monster: try container.encode("Monster") + case .testsimpletablewithenum: try container.encode("TestSimpleTableWithEnum") + case .mygameExample2Monster: try container.encode("MyGame_Example2_Monster") + } + } +} + public struct MyGame_Example_Any_Union { public var type: MyGame_Example_Any_ public var value: NativeObject? @@ -91,6 +126,18 @@ public enum MyGame_Example_AnyUniqueAliases: UInt8, UnionEnum { public static var min: MyGame_Example_AnyUniqueAliases { return .none_ } } +extension MyGame_Example_AnyUniqueAliases: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .none_: try container.encode("NONE") + case .m: try container.encode("M") + case .ts: try container.encode("TS") + case .m2: try container.encode("M2") + } + } +} + public struct MyGame_Example_AnyUniqueAliasesUnion { public var type: MyGame_Example_AnyUniqueAliases public var value: NativeObject? @@ -131,6 +178,18 @@ public enum MyGame_Example_AnyAmbiguousAliases: UInt8, UnionEnum { public static var min: MyGame_Example_AnyAmbiguousAliases { return .none_ } } +extension MyGame_Example_AnyAmbiguousAliases: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .none_: try container.encode("NONE") + case .m1: try container.encode("M1") + case .m2: try container.encode("M2") + case .m3: try container.encode("M3") + } + } +} + public struct MyGame_Example_AnyAmbiguousAliasesUnion { public var type: MyGame_Example_AnyAmbiguousAliases public var value: NativeObject? @@ -153,7 +212,7 @@ public struct MyGame_Example_AnyAmbiguousAliasesUnion { } } } -public struct MyGame_Example_Test: NativeStruct, Verifiable, NativeObject { +public struct MyGame_Example_Test: NativeStruct, Verifiable, FlatbuffersInitializable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -161,6 +220,12 @@ public struct MyGame_Example_Test: NativeStruct, Verifiable, NativeObject { private var _b: Int8 private let padding0__: UInt8 = 0 + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _a = _accessor.readBuffer(of: Int16.self, at: 0) + _b = _accessor.readBuffer(of: Int8.self, at: 2) + } + public init(a: Int16, b: Int8) { _a = a _b = b @@ -184,6 +249,23 @@ public struct MyGame_Example_Test: NativeStruct, Verifiable, NativeObject { } } +extension MyGame_Example_Test: Encodable { + + enum CodingKeys: String, CodingKey { + case a = "a" + case b = "b" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if a != 0 { + try container.encodeIfPresent(a, forKey: .a) + } + if b != 0 { + try container.encodeIfPresent(b, forKey: .b) + } + } +} + public struct MyGame_Example_Test_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -211,7 +293,7 @@ public struct MyGame_Example_Test_Mutable: FlatBufferObject { } } -public struct MyGame_Example_Vec3: NativeStruct, Verifiable, NativeObject { +public struct MyGame_Example_Vec3: NativeStruct, Verifiable, FlatbuffersInitializable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -225,6 +307,16 @@ public struct MyGame_Example_Vec3: NativeStruct, Verifiable, NativeObject { private var _test3: MyGame_Example_Test private let padding2__: UInt16 = 0 + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _x = _accessor.readBuffer(of: Float32.self, at: 0) + _y = _accessor.readBuffer(of: Float32.self, at: 4) + _z = _accessor.readBuffer(of: Float32.self, at: 8) + _test1 = _accessor.readBuffer(of: Double.self, at: 16) + _test2 = _accessor.readBuffer(of: UInt8.self, at: 24) + _test3 = MyGame_Example_Test(_accessor.bb, o: _accessor.postion + 26) + } + public init(x: Float32, y: Float32, z: Float32, test1: Double, test2: MyGame_Example_Color, test3: MyGame_Example_Test) { _x = x _y = y @@ -265,6 +357,37 @@ public struct MyGame_Example_Vec3: NativeStruct, Verifiable, NativeObject { } } +extension MyGame_Example_Vec3: Encodable { + + enum CodingKeys: String, CodingKey { + case x = "x" + case y = "y" + case z = "z" + case test1 = "test1" + case test2 = "test2" + case test3 = "test3" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if x != 0.0 { + try container.encodeIfPresent(x, forKey: .x) + } + if y != 0.0 { + try container.encodeIfPresent(y, forKey: .y) + } + if z != 0.0 { + try container.encodeIfPresent(z, forKey: .z) + } + if test1 != 0.0 { + try container.encodeIfPresent(test1, forKey: .test1) + } + if test2 != .red { + try container.encodeIfPresent(test2, forKey: .test2) + } + try container.encodeIfPresent(test3, forKey: .test3) + } +} + public struct MyGame_Example_Vec3_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -299,13 +422,19 @@ public struct MyGame_Example_Vec3_Mutable: FlatBufferObject { } } -public struct MyGame_Example_Ability: NativeStruct, Verifiable, NativeObject { +public struct MyGame_Example_Ability: NativeStruct, Verifiable, FlatbuffersInitializable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } private var _id: UInt32 private var _distance: UInt32 + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _id = _accessor.readBuffer(of: UInt32.self, at: 0) + _distance = _accessor.readBuffer(of: UInt32.self, at: 4) + } + public init(id: UInt32, distance: UInt32) { _id = id _distance = distance @@ -329,6 +458,23 @@ public struct MyGame_Example_Ability: NativeStruct, Verifiable, NativeObject { } } +extension MyGame_Example_Ability: Encodable { + + enum CodingKeys: String, CodingKey { + case id = "id" + case distance = "distance" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if id != 0 { + try container.encodeIfPresent(id, forKey: .id) + } + if distance != 0 { + try container.encodeIfPresent(distance, forKey: .distance) + } + } +} + public struct MyGame_Example_Ability_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -356,7 +502,7 @@ public struct MyGame_Example_Ability_Mutable: FlatBufferObject { } } -public struct MyGame_Example_StructOfStructs: NativeStruct, Verifiable, NativeObject { +public struct MyGame_Example_StructOfStructs: NativeStruct, Verifiable, FlatbuffersInitializable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -364,6 +510,13 @@ public struct MyGame_Example_StructOfStructs: NativeStruct, Verifiable, NativeOb private var _b: MyGame_Example_Test private var _c: MyGame_Example_Ability + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _a = MyGame_Example_Ability(_accessor.bb, o: _accessor.postion + 0) + _b = MyGame_Example_Test(_accessor.bb, o: _accessor.postion + 8) + _c = MyGame_Example_Ability(_accessor.bb, o: _accessor.postion + 12) + } + public init(a: MyGame_Example_Ability, b: MyGame_Example_Test, c: MyGame_Example_Ability) { _a = a _b = b @@ -394,6 +547,21 @@ public struct MyGame_Example_StructOfStructs: NativeStruct, Verifiable, NativeOb } } +extension MyGame_Example_StructOfStructs: Encodable { + + enum CodingKeys: String, CodingKey { + case a = "a" + case b = "b" + case c = "c" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(a, forKey: .a) + try container.encodeIfPresent(b, forKey: .b) + try container.encodeIfPresent(c, forKey: .c) + } +} + public struct MyGame_Example_StructOfStructs_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -455,6 +623,12 @@ public struct MyGame_InParentNamespace: FlatBufferObject, Verifiable, ObjectAPIP } } +extension MyGame_InParentNamespace: Encodable { + + public func encode(to encoder: Encoder) throws { + } +} + public class MyGame_InParentNamespaceT: NativeObject { @@ -502,6 +676,12 @@ public struct MyGame_Example2_Monster: FlatBufferObject, Verifiable, ObjectAPIPa } } +extension MyGame_Example2_Monster: Encodable { + + public func encode(to encoder: Encoder) throws { + } +} + public class MyGame_Example2_MonsterT: NativeObject { @@ -568,6 +748,19 @@ internal struct MyGame_Example_TestSimpleTableWithEnum: FlatBufferObject, Verifi } } +extension MyGame_Example_TestSimpleTableWithEnum: Encodable { + + enum CodingKeys: String, CodingKey { + case color = "color" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if color != .green { + try container.encodeIfPresent(color, forKey: .color) + } + } +} + internal class MyGame_Example_TestSimpleTableWithEnumT: NativeObject { internal var color: MyGame_Example_Color @@ -684,6 +877,25 @@ public struct MyGame_Example_Stat: FlatBufferObject, Verifiable, ObjectAPIPacker } } +extension MyGame_Example_Stat: Encodable { + + enum CodingKeys: String, CodingKey { + case id = "id" + case val = "val" + case count = "count" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(id, forKey: .id) + if val != 0 { + try container.encodeIfPresent(val, forKey: .val) + } + if count != 0 { + try container.encodeIfPresent(count, forKey: .count) + } + } +} + public class MyGame_Example_StatT: NativeObject { public var id: String? @@ -782,6 +994,19 @@ public struct MyGame_Example_Referrable: FlatBufferObject, Verifiable, ObjectAPI } } +extension MyGame_Example_Referrable: Encodable { + + enum CodingKeys: String, CodingKey { + case id = "id" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if id != 0 { + try container.encodeIfPresent(id, forKey: .id) + } + } +} + public class MyGame_Example_ReferrableT: NativeObject { public var id: UInt64 @@ -1396,6 +1621,272 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac } } +extension MyGame_Example_Monster: Encodable { + + enum CodingKeys: String, CodingKey { + case pos = "pos" + case mana = "mana" + case hp = "hp" + case name = "name" + case inventory = "inventory" + case color = "color" + case testType = "test_type" + case test = "test" + case test4 = "test4" + case testarrayofstring = "testarrayofstring" + case testarrayoftables = "testarrayoftables" + case enemy = "enemy" + case testnestedflatbuffer = "testnestedflatbuffer" + case testempty = "testempty" + case testbool = "testbool" + case testhashs32Fnv1 = "testhashs32_fnv1" + case testhashu32Fnv1 = "testhashu32_fnv1" + case testhashs64Fnv1 = "testhashs64_fnv1" + case testhashu64Fnv1 = "testhashu64_fnv1" + case testhashs32Fnv1a = "testhashs32_fnv1a" + case testhashu32Fnv1a = "testhashu32_fnv1a" + case testhashs64Fnv1a = "testhashs64_fnv1a" + case testhashu64Fnv1a = "testhashu64_fnv1a" + case testarrayofbools = "testarrayofbools" + case testf = "testf" + case testf2 = "testf2" + case testf3 = "testf3" + case testarrayofstring2 = "testarrayofstring2" + case testarrayofsortedstruct = "testarrayofsortedstruct" + case flex = "flex" + case test5 = "test5" + case vectorOfLongs = "vector_of_longs" + case vectorOfDoubles = "vector_of_doubles" + case parentNamespaceTest = "parent_namespace_test" + case vectorOfReferrables = "vector_of_referrables" + case singleWeakReference = "single_weak_reference" + case vectorOfWeakReferences = "vector_of_weak_references" + case vectorOfStrongReferrables = "vector_of_strong_referrables" + case coOwningReference = "co_owning_reference" + case vectorOfCoOwningReferences = "vector_of_co_owning_references" + case nonOwningReference = "non_owning_reference" + case vectorOfNonOwningReferences = "vector_of_non_owning_references" + case anyUniqueType = "any_unique_type" + case anyUnique = "any_unique" + case anyAmbiguousType = "any_ambiguous_type" + case anyAmbiguous = "any_ambiguous" + case vectorOfEnums = "vector_of_enums" + case signedEnum = "signed_enum" + case testrequirednestedflatbuffer = "testrequirednestedflatbuffer" + case scalarKeySortedTables = "scalar_key_sorted_tables" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(pos, forKey: .pos) + if mana != 150 { + try container.encodeIfPresent(mana, forKey: .mana) + } + if hp != 100 { + try container.encodeIfPresent(hp, forKey: .hp) + } + try container.encodeIfPresent(name, forKey: .name) + if inventoryCount > 0 { + try container.encodeIfPresent(inventory, forKey: .inventory) + } + if color != .blue { + try container.encodeIfPresent(color, forKey: .color) + } + if testType != .none_ { + try container.encodeIfPresent(testType, forKey: .testType) + } + switch testType { + case .monster: + let _v = test(type: MyGame_Example_Monster.self) + try container.encodeIfPresent(_v, forKey: .test) + case .testsimpletablewithenum: + let _v = test(type: MyGame_Example_TestSimpleTableWithEnum.self) + try container.encodeIfPresent(_v, forKey: .test) + case .mygameExample2Monster: + let _v = test(type: MyGame_Example2_Monster.self) + try container.encodeIfPresent(_v, forKey: .test) + default: break; + } + if test4Count > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .test4) + for index in 0.. 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .testarrayofstring) + for index in 0.. 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .testarrayoftables) + for index in 0.. 0 { + try container.encodeIfPresent(testnestedflatbuffer, forKey: .testnestedflatbuffer) + } + try container.encodeIfPresent(testempty, forKey: .testempty) + if testbool != false { + try container.encodeIfPresent(testbool, forKey: .testbool) + } + if testhashs32Fnv1 != 0 { + try container.encodeIfPresent(testhashs32Fnv1, forKey: .testhashs32Fnv1) + } + if testhashu32Fnv1 != 0 { + try container.encodeIfPresent(testhashu32Fnv1, forKey: .testhashu32Fnv1) + } + if testhashs64Fnv1 != 0 { + try container.encodeIfPresent(testhashs64Fnv1, forKey: .testhashs64Fnv1) + } + if testhashu64Fnv1 != 0 { + try container.encodeIfPresent(testhashu64Fnv1, forKey: .testhashu64Fnv1) + } + if testhashs32Fnv1a != 0 { + try container.encodeIfPresent(testhashs32Fnv1a, forKey: .testhashs32Fnv1a) + } + if testhashu32Fnv1a != 0 { + try container.encodeIfPresent(testhashu32Fnv1a, forKey: .testhashu32Fnv1a) + } + if testhashs64Fnv1a != 0 { + try container.encodeIfPresent(testhashs64Fnv1a, forKey: .testhashs64Fnv1a) + } + if testhashu64Fnv1a != 0 { + try container.encodeIfPresent(testhashu64Fnv1a, forKey: .testhashu64Fnv1a) + } + if testarrayofboolsCount > 0 { + try container.encodeIfPresent(testarrayofbools, forKey: .testarrayofbools) + } + if testf != 3.14159 { + try container.encodeIfPresent(testf, forKey: .testf) + } + if testf2 != 3.0 { + try container.encodeIfPresent(testf2, forKey: .testf2) + } + if testf3 != 0.0 { + try container.encodeIfPresent(testf3, forKey: .testf3) + } + if testarrayofstring2Count > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .testarrayofstring2) + for index in 0.. 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .testarrayofsortedstruct) + for index in 0.. 0 { + try container.encodeIfPresent(flex, forKey: .flex) + } + if test5Count > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .test5) + for index in 0.. 0 { + try container.encodeIfPresent(vectorOfLongs, forKey: .vectorOfLongs) + } + if vectorOfDoublesCount > 0 { + try container.encodeIfPresent(vectorOfDoubles, forKey: .vectorOfDoubles) + } + try container.encodeIfPresent(parentNamespaceTest, forKey: .parentNamespaceTest) + if vectorOfReferrablesCount > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .vectorOfReferrables) + for index in 0.. 0 { + try container.encodeIfPresent(vectorOfWeakReferences, forKey: .vectorOfWeakReferences) + } + if vectorOfStrongReferrablesCount > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .vectorOfStrongReferrables) + for index in 0.. 0 { + try container.encodeIfPresent(vectorOfCoOwningReferences, forKey: .vectorOfCoOwningReferences) + } + if nonOwningReference != 0 { + try container.encodeIfPresent(nonOwningReference, forKey: .nonOwningReference) + } + if vectorOfNonOwningReferencesCount > 0 { + try container.encodeIfPresent(vectorOfNonOwningReferences, forKey: .vectorOfNonOwningReferences) + } + if anyUniqueType != .none_ { + try container.encodeIfPresent(anyUniqueType, forKey: .anyUniqueType) + } + switch anyUniqueType { + case .m: + let _v = anyUnique(type: MyGame_Example_Monster.self) + try container.encodeIfPresent(_v, forKey: .anyUnique) + case .ts: + let _v = anyUnique(type: MyGame_Example_TestSimpleTableWithEnum.self) + try container.encodeIfPresent(_v, forKey: .anyUnique) + case .m2: + let _v = anyUnique(type: MyGame_Example2_Monster.self) + try container.encodeIfPresent(_v, forKey: .anyUnique) + default: break; + } + if anyAmbiguousType != .none_ { + try container.encodeIfPresent(anyAmbiguousType, forKey: .anyAmbiguousType) + } + switch anyAmbiguousType { + case .m1: + let _v = anyAmbiguous(type: MyGame_Example_Monster.self) + try container.encodeIfPresent(_v, forKey: .anyAmbiguous) + case .m2: + let _v = anyAmbiguous(type: MyGame_Example_Monster.self) + try container.encodeIfPresent(_v, forKey: .anyAmbiguous) + case .m3: + let _v = anyAmbiguous(type: MyGame_Example_Monster.self) + try container.encodeIfPresent(_v, forKey: .anyAmbiguous) + default: break; + } + if vectorOfEnumsCount > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .vectorOfEnums) + for index in 0.. 0 { + try container.encodeIfPresent(testrequirednestedflatbuffer, forKey: .testrequirednestedflatbuffer) + } + if scalarKeySortedTablesCount > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .scalarKeySortedTables) + for index in 0.. 0 { + try container.encodeIfPresent(v8, forKey: .v8) + } + if vf64Count > 0 { + try container.encodeIfPresent(vf64, forKey: .vf64) + } + } +} + public class MyGame_Example_TypeAliasesT: NativeObject { public var i8: Int8 diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift index c43bfbc10..3ebaa2aa4 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift @@ -16,6 +16,17 @@ public enum ABC: Int32, Enum, Verifiable { public static var min: ABC { return .a } } +extension ABC: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .a: try container.encode("A") + case .b: try container.encode("B") + case .c: try container.encode("C") + } + } +} + public struct MoreDefaults: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -130,6 +141,39 @@ public struct MoreDefaults: FlatBufferObject, Verifiable, ObjectAPIPacker { } } +extension MoreDefaults: Encodable { + + enum CodingKeys: String, CodingKey { + case ints = "ints" + case floats = "floats" + case emptyString = "empty_string" + case someString = "some_string" + case abcs = "abcs" + case bools = "bools" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if intsCount > 0 { + try container.encodeIfPresent(ints, forKey: .ints) + } + if floatsCount > 0 { + try container.encodeIfPresent(floats, forKey: .floats) + } + try container.encodeIfPresent(emptyString, forKey: .emptyString) + try container.encodeIfPresent(someString, forKey: .someString) + if abcsCount > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .abcs) + for index in 0.. 0 { + try container.encodeIfPresent(bools, forKey: .bools) + } + } +} + public class MoreDefaultsT: NativeObject { public var ints: [Int32] diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift index 4fdd7183f..82a09b0d9 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift @@ -16,6 +16,17 @@ public enum optional_scalars_OptionalByte: Int8, Enum, Verifiable { public static var min: optional_scalars_OptionalByte { return .none_ } } +extension optional_scalars_OptionalByte: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .none_: try container.encode("None") + case .one: try container.encode("One") + case .two: try container.encode("Two") + } + } +} + public struct optional_scalars_ScalarStuff: FlatBufferObject, Verifiable { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -266,3 +277,132 @@ public struct optional_scalars_ScalarStuff: FlatBufferObject, Verifiable { } } +extension optional_scalars_ScalarStuff: Encodable { + + enum CodingKeys: String, CodingKey { + case justI8 = "just_i8" + case maybeI8 = "maybe_i8" + case defaultI8 = "default_i8" + case justU8 = "just_u8" + case maybeU8 = "maybe_u8" + case defaultU8 = "default_u8" + case justI16 = "just_i16" + case maybeI16 = "maybe_i16" + case defaultI16 = "default_i16" + case justU16 = "just_u16" + case maybeU16 = "maybe_u16" + case defaultU16 = "default_u16" + case justI32 = "just_i32" + case maybeI32 = "maybe_i32" + case defaultI32 = "default_i32" + case justU32 = "just_u32" + case maybeU32 = "maybe_u32" + case defaultU32 = "default_u32" + case justI64 = "just_i64" + case maybeI64 = "maybe_i64" + case defaultI64 = "default_i64" + case justU64 = "just_u64" + case maybeU64 = "maybe_u64" + case defaultU64 = "default_u64" + case justF32 = "just_f32" + case maybeF32 = "maybe_f32" + case defaultF32 = "default_f32" + case justF64 = "just_f64" + case maybeF64 = "maybe_f64" + case defaultF64 = "default_f64" + case justBool = "just_bool" + case maybeBool = "maybe_bool" + case defaultBool = "default_bool" + case justEnum = "just_enum" + case maybeEnum = "maybe_enum" + case defaultEnum = "default_enum" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if justI8 != 0 { + try container.encodeIfPresent(justI8, forKey: .justI8) + } + try container.encodeIfPresent(maybeI8, forKey: .maybeI8) + if defaultI8 != 42 { + try container.encodeIfPresent(defaultI8, forKey: .defaultI8) + } + if justU8 != 0 { + try container.encodeIfPresent(justU8, forKey: .justU8) + } + try container.encodeIfPresent(maybeU8, forKey: .maybeU8) + if defaultU8 != 42 { + try container.encodeIfPresent(defaultU8, forKey: .defaultU8) + } + if justI16 != 0 { + try container.encodeIfPresent(justI16, forKey: .justI16) + } + try container.encodeIfPresent(maybeI16, forKey: .maybeI16) + if defaultI16 != 42 { + try container.encodeIfPresent(defaultI16, forKey: .defaultI16) + } + if justU16 != 0 { + try container.encodeIfPresent(justU16, forKey: .justU16) + } + try container.encodeIfPresent(maybeU16, forKey: .maybeU16) + if defaultU16 != 42 { + try container.encodeIfPresent(defaultU16, forKey: .defaultU16) + } + if justI32 != 0 { + try container.encodeIfPresent(justI32, forKey: .justI32) + } + try container.encodeIfPresent(maybeI32, forKey: .maybeI32) + if defaultI32 != 42 { + try container.encodeIfPresent(defaultI32, forKey: .defaultI32) + } + if justU32 != 0 { + try container.encodeIfPresent(justU32, forKey: .justU32) + } + try container.encodeIfPresent(maybeU32, forKey: .maybeU32) + if defaultU32 != 42 { + try container.encodeIfPresent(defaultU32, forKey: .defaultU32) + } + if justI64 != 0 { + try container.encodeIfPresent(justI64, forKey: .justI64) + } + try container.encodeIfPresent(maybeI64, forKey: .maybeI64) + if defaultI64 != 42 { + try container.encodeIfPresent(defaultI64, forKey: .defaultI64) + } + if justU64 != 0 { + try container.encodeIfPresent(justU64, forKey: .justU64) + } + try container.encodeIfPresent(maybeU64, forKey: .maybeU64) + if defaultU64 != 42 { + try container.encodeIfPresent(defaultU64, forKey: .defaultU64) + } + if justF32 != 0.0 { + try container.encodeIfPresent(justF32, forKey: .justF32) + } + try container.encodeIfPresent(maybeF32, forKey: .maybeF32) + if defaultF32 != 42.0 { + try container.encodeIfPresent(defaultF32, forKey: .defaultF32) + } + if justF64 != 0.0 { + try container.encodeIfPresent(justF64, forKey: .justF64) + } + try container.encodeIfPresent(maybeF64, forKey: .maybeF64) + if defaultF64 != 42.0 { + try container.encodeIfPresent(defaultF64, forKey: .defaultF64) + } + if justBool != false { + try container.encodeIfPresent(justBool, forKey: .justBool) + } + try container.encodeIfPresent(maybeBool, forKey: .maybeBool) + if defaultBool != true { + try container.encodeIfPresent(defaultBool, forKey: .defaultBool) + } + if justEnum != .none_ { + try container.encodeIfPresent(justEnum, forKey: .justEnum) + } + try container.encodeIfPresent(maybeEnum, forKey: .maybeEnum) + if defaultEnum != .one { + try container.encodeIfPresent(defaultEnum, forKey: .defaultEnum) + } + } +} + diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift index 676b0570f..13abd04c8 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift @@ -25,6 +25,21 @@ public enum Character: UInt8, UnionEnum { public static var min: Character { return .none_ } } +extension Character: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .none_: try container.encode("NONE") + case .mulan: try container.encode("MuLan") + case .rapunzel: try container.encode("Rapunzel") + case .belle: try container.encode("Belle") + case .bookfan: try container.encode("BookFan") + case .other: try container.encode("Other") + case .unused: try container.encode("Unused") + } + } +} + public struct CharacterUnion { public var type: Character public var value: NativeObject? @@ -56,12 +71,17 @@ public struct CharacterUnion { } } } -public struct Rapunzel: NativeStruct, Verifiable, NativeObject { +public struct Rapunzel: NativeStruct, Verifiable, FlatbuffersInitializable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } private var _hairLength: Int32 + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _hairLength = _accessor.readBuffer(of: Int32.self, at: 0) + } + public init(hairLength: Int32) { _hairLength = hairLength } @@ -81,6 +101,19 @@ public struct Rapunzel: NativeStruct, Verifiable, NativeObject { } } +extension Rapunzel: Encodable { + + enum CodingKeys: String, CodingKey { + case hairLength = "hair_length" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if hairLength != 0 { + try container.encodeIfPresent(hairLength, forKey: .hairLength) + } + } +} + public struct Rapunzel_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -106,12 +139,17 @@ public struct Rapunzel_Mutable: FlatBufferObject { } } -public struct BookReader: NativeStruct, Verifiable, NativeObject { +public struct BookReader: NativeStruct, Verifiable, FlatbuffersInitializable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } private var _booksRead: Int32 + public init(_ bb: ByteBuffer, o: Int32) { + let _accessor = Struct(bb: bb, position: o) + _booksRead = _accessor.readBuffer(of: Int32.self, at: 0) + } + public init(booksRead: Int32) { _booksRead = booksRead } @@ -131,6 +169,19 @@ public struct BookReader: NativeStruct, Verifiable, NativeObject { } } +extension BookReader: Encodable { + + enum CodingKeys: String, CodingKey { + case booksRead = "books_read" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if booksRead != 0 { + try container.encodeIfPresent(booksRead, forKey: .booksRead) + } + } +} + public struct BookReader_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -210,6 +261,19 @@ public struct Attacker: FlatBufferObject, Verifiable, ObjectAPIPacker { } } +extension Attacker: Encodable { + + enum CodingKeys: String, CodingKey { + case swordAttackDamage = "sword_attack_damage" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if swordAttackDamage != 0 { + try container.encodeIfPresent(swordAttackDamage, forKey: .swordAttackDamage) + } + } +} + public class AttackerT: NativeObject { public var swordAttackDamage: Int32 @@ -344,6 +408,72 @@ public struct Movie: FlatBufferObject, Verifiable, ObjectAPIPacker { } } +extension Movie: Encodable { + + enum CodingKeys: String, CodingKey { + case mainCharacterType = "main_character_type" + case mainCharacter = "main_character" + case charactersType = "characters_type" + case characters = "characters" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if mainCharacterType != .none_ { + try container.encodeIfPresent(mainCharacterType, forKey: .mainCharacterType) + } + switch mainCharacterType { + case .mulan: + let _v = mainCharacter(type: Attacker.self) + try container.encodeIfPresent(_v, forKey: .mainCharacter) + case .rapunzel: + let _v = mainCharacter(type: Rapunzel.self) + try container.encodeIfPresent(_v, forKey: .mainCharacter) + case .belle: + let _v = mainCharacter(type: BookReader.self) + try container.encodeIfPresent(_v, forKey: .mainCharacter) + case .bookfan: + let _v = mainCharacter(type: BookReader.self) + try container.encodeIfPresent(_v, forKey: .mainCharacter) + case .other: + let _v = mainCharacter(type: String.self) + try container.encodeIfPresent(_v, forKey: .mainCharacter) + case .unused: + let _v = mainCharacter(type: String.self) + try container.encodeIfPresent(_v, forKey: .mainCharacter) + default: break; + } + if charactersCount > 0 { + var enumsEncoder = container.nestedUnkeyedContainer(forKey: .charactersType) + var contentEncoder = container.nestedUnkeyedContainer(forKey: .characters) + for index in 0..