diff --git a/.gitignore b/.gitignore
index d6ec9fd87..bfe065bc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,12 @@
*_wire.txt
*_wire.bin
.DS_Store
+**/.build
+**/Packages
+/*.xcodeproj
+**/xcuserdata/
+**/xcshareddata/
+**/.swiftpm/
*.o
*.o.d
*.class
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 815dadfbc..a1c7c00ee 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -102,6 +102,7 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
src/idl_gen_json_schema.cpp
+ src/idl_gen_swift.cpp
src/flatc.cpp
src/flatc_main.cpp
include/flatbuffers/code_generators.h
diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md
index c5768bd2d..9061051bd 100644
--- a/docs/source/Compiler.md
+++ b/docs/source/Compiler.md
@@ -47,6 +47,8 @@ For any schema input files, one or more generators can be specified:
- `--rust`, `-r` : Generate Rust code.
+- `--swift`: Generate Swift code.
+
For any data input files:
- `--binary`, `-b` : If data is contained in this file, generate a
diff --git a/docs/source/FlatBuffers.md b/docs/source/FlatBuffers.md
index a9d637aca..45ffbf22b 100644
--- a/docs/source/FlatBuffers.md
+++ b/docs/source/FlatBuffers.md
@@ -4,7 +4,7 @@ FlatBuffers {#flatbuffers_index}
# Overview {#flatbuffers_overview}
[FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform
-serialization library for C++, C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, and Rust.
+serialization library for C++, C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, Rust and Swift.
It was originally created at Google for game development and other
performance-critical applications.
@@ -148,6 +148,8 @@ sections provide a more in-depth usage guide.
own programs.
- How to [use the generated Rust code](@ref flatbuffers_guide_use_rust) in your
own programs.
+- How to [use the generated Swift code](@ref flatbuffers_guide_use_swift) in your
+ own programs.
- [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
using FlatBuffers.
diff --git a/docs/source/Support.md b/docs/source/Support.md
index c8ac7f7e8..1e435a663 100644
--- a/docs/source/Support.md
+++ b/docs/source/Support.md
@@ -18,23 +18,23 @@ In general:
NOTE: this table is a start, it needs to be extended.
-Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster | Rust
------------------------------- | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | ------- | ----
-Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes | Yes
-JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes | No
-Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No | No
-Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No
-Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No
-Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes
-Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes
-Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb
-Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes | Yes
-Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
-Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
-Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
-Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
-Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No | ?
-Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard* | rw
+Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster | Rust | Swift
+------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | ------- | ------- | ------
+Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes | Yes | Yes
+JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes | No | No
+Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No | No | No
+Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No | No
+Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No | No
+Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes | Yes
+Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes | No
+Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb | ?
+Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes | Yes | No
+Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes | Yes
+Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes | Yes
+Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ? | No
+Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ? | Yes
+Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No | ? | No
+Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard* | rw | mi*/mz*
* aard = aardappel (previously: gwvo)
* ev = evolutional
@@ -42,5 +42,7 @@ Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | ev
* mik = mikkelfj
* ch = chobie
* kr = krojew
+ * mi = mustiikhalil
+ * mz = mzaks
diff --git a/docs/source/SwiftUsage.md b/docs/source/SwiftUsage.md
new file mode 100644
index 000000000..fb8b1fd9b
--- /dev/null
+++ b/docs/source/SwiftUsage.md
@@ -0,0 +1,93 @@
+Use in Swift {#flatbuffers_guide_use_swift}
+=========
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Swift, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
+to general FlatBuffers usage in all of the supported languages (including Swift).
+This page is designed to cover the nuances of FlatBuffers usage, specific to
+Swift.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Swift library code location
+
+The code for the FlatBuffers Swift library can be found at
+`flatbuffers/swift`. You can browse the library code on the [FlatBuffers
+GitHub page](https://github.com/google/flatbuffers/tree/master/swift).
+
+## Testing the FlatBuffers Swift library
+
+The code to test the Swift library can be found at `flatbuffers/Flatbuffers.Test.Swift`.
+The test code itself is located in [Flatbuffers.Test.Swift](https://github.com/google/
+flatbuffers/blob/master/tests/FlatBuffers.Test.Swift).
+
+To run the tests, use the [SwiftTest.sh](https://github.com/google/flatbuffers/
+blob/master/tests/FlatBuffers.Test.Swift/SwiftTest.sh) shell script.
+
+*Note: The shell script requires [Swift](https://swift.org) to
+be installed.*
+
+## Using the FlatBuffers Swift library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Swift.*
+
+FlatBuffers supports reading and writing binary FlatBuffers in Swift.
+
+To use FlatBuffers in your own code, first generate Swift structs from your
+schema with the `--swift` option to `flatc`. Then include FlatBuffers using `SPM` in
+by adding the path to `FlatBuffers/swift` into it. The generated code should also be
+added to xcode or the path of the package you will be using. Note: sometimes xcode cant
+and wont see the generated files, so it's better that you copy them to xcode.
+
+For example, here is how you would read a FlatBuffer binary file in Swift: First,
+include the library and copy thegenerated code. Then read a FlatBuffer binary file or
+a data object from the server, which you can pass into the `GetRootAsMonster` function.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.swift}
+ import FlatBuffers
+
+ typealias Monster1 = MyGame.Sample.Monster
+ typealias Vec3 = MyGame.Sample.Vec3
+
+ let path = FileManager.default.currentDirectoryPath
+ let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon")
+ guard let data = try? Data(contentsOf: url) else { return }
+
+ let monster = Monster.getRootAsMonster(bb: ByteBuffer(data: data))
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.swift}
+ let hp = monster.hp
+ let pos = monster.pos
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+In some cases it's necessary to modify values in an existing FlatBuffer in place (without creating a copy). For this reason, scalar fields of a Flatbuffer table or struct can be mutated.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.swift}
+ let monster = Monster.getRootAsMonster(bb: ByteBuffer(data: data))
+
+ if !monster.mutate(hp: 10) {
+ fatalError("couldn't mutate")
+ }
+ // mutate a struct field
+ let vec = monster.pos.mutate(z: 4)
+
+ // This mutation will fail because the mana field is not available in
+ // the buffer. It should be set when creating the buffer.
+ if !monster.mutate(mana: 20) {
+ fatalError("couldn't mutate")
+ }
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The term `mutate` is used instead of `set` to indicate that this is a special use case. All mutate functions return a boolean value which is false if the field we're trying to mutate is not available in the buffer.
+
+
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index e8d8519be..00408b52e 100644
--- a/docs/source/Tutorial.md
+++ b/docs/source/Tutorial.md
@@ -35,6 +35,7 @@ Please select your desired language for our quest:
Lua
Lobster
Rust
+ Swift
\endhtmlonly
@@ -152,6 +153,9 @@ For your chosen language, please cross-reference with:
## Writing the Monsters' FlatBuffer Schema
@@ -363,6 +367,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools.
./../flatc --rust monster.fbs
~~~
+
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --swift monster.fbs
+~~~
+
For a more complete guide to using the `flatc` compiler, please read the
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
@@ -523,6 +533,21 @@ The first step is to import/include the library, generated files, etc.
~~~
+
+~~~{.swift}
+ /**
+ // make sure that monster_generated.swift is included in your project
+ */
+ import Flatbuffers
+
+ // typealiases for convenience
+ typealias Monster = MyGame1.Sample.Monster
+ typealias Weapon = MyGame1.Sample.Weapon
+ typealias Color = MyGame1.Sample.Color
+ typealias Vec3 = MyGame1.Sample.Vec3
+~~~
+
+
Now we are ready to start building some buffers. In order to start, we need
to create an instance of the `FlatBufferBuilder`, which will contain the buffer
as it grows. You can pass an initial size of the buffer (here 1024 bytes),
@@ -627,6 +652,12 @@ which will grow automatically if needed:
let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024);
~~~
+
+~~~{.swift}
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+~~~
+
After creating the `builder`, we can start serializing our data. Before we make
our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
@@ -878,6 +909,25 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
~~~
+
+~~~{.swift}
+ let weapon1Name = builder.create(string: "Sword")
+ let weapon2Name = builder.create(string: "Axe")
+
+ // start creating the weapon by calling startWeapon
+ let weapon1Start = Weapon.startWeapon(builder)
+ Weapon.add(name: weapon1Name, builder)
+ Weapon.add(damage: 3, builder)
+ // end the object by passing the start point for the weapon 1
+ let sword = Weapon.endWeapon(builder, start: weapon1Start)
+
+ let weapon2Start = Weapon.startWeapon(builder)
+ Weapon.add(name: weapon2Name, builder)
+ Weapon.add(damage: 5, builder)
+ let axe = Weapon.endWeapon(builder, start: weapon2Start)
+~~~
+
+
Now let's create our monster, the `orc`. For this `orc`, lets make him
`red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him
a large pool of hit points with `300`. We can give him a vector of weapons
@@ -1068,6 +1118,16 @@ traversal. This is generally easy to do on any tree structures.
let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
~~~
+
+~~~{.swift}
+ // Name of the Monster.
+ let name = builder.create(string: "Orc")
+
+ // create inventory
+ let inventory: [Byte] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ let inventoryOffset = builder.createVector(inventory)
+~~~
+
We serialized two built-in data types (`string` and `vector`) and captured
their return values. These values are offsets into the serialized data,
@@ -1212,6 +1272,13 @@ offsets.
let weapons = builder.create_vector(&[sword, axe]);
~~~
+
+~~~{.swift}
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+~~~
+
Note there's additional convenience overloads of `CreateVector`, allowing you
@@ -1348,6 +1415,15 @@ for the `path` field above:
// let path = builder.create_vector(&[&x, &y]);
~~~
+
+
We have now serialized the non-scalar components of the orc, so we
can serialize the monster itself:
@@ -1621,6 +1697,20 @@ can serialize the monster itself:
});
~~~
+
Note how we create `Vec3` struct in-line in the table. Unlike tables, structs
are simple combinations of scalars that are always stored inline, just like
@@ -1789,6 +1879,13 @@ Here is a repetition these lines, to help highlight them more clearly:
monster_builder.add_equipped(axe.as_union_value()); // Union data
~~~
+
+ ~~~{.swift}
+ Monster.add(equippedType: .weapon, builder) // Type of union
+ Monster.add(equipped: axe, builder) // Union data
+ ~~~
+
+
After you have created your buffer, you will have the offset to the root of the
data in the `orc` variable, so you can finish the buffer by calling the
@@ -1884,6 +1981,12 @@ appropriate `finish` method.
builder.finish(orc, None);
~~~
+
+~~~{.swift}
+ // Call `finish(offset:)` to instruct the builder that this monster is complete.
+ builder.finish(offset: orc)
+~~~
+
The buffer is now ready to be stored somewhere, sent over the network, be
compressed, or whatever you'd like to do with it. You can access the buffer
@@ -2012,6 +2115,15 @@ like so:
~~~
+
+~~~{.swift}
+ // This must be called after `finish()`.
+ // `sizedByteArray` returns the finished buf of type [UInt8].
+ let buf = builder.sizedByteArray
+ // or you can use to get an object of type Data
+ let bufData = ByteBuffer(data: builder.data)
+~~~
+
Now you can write the bytes to a file, send them over the network..
**Make sure your file mode (or transfer protocol) is set to BINARY, not text.**
@@ -2312,6 +2424,16 @@ myGame.Monster monster = new myGame.Monster(data);
~~~
+
+~~~{.swift}
+ // create a ByteBuffer(:) from an [UInt8] or Data()
+ let buf = // Get your data
+
+ // Get an accessor to the root object inside the buffer.
+ let monster = Monster.getRootAsMonster(bb: ByteBuffer(bytes: buf))
+~~~
+
+
If you look in the generated files from the schema compiler, you will see it generated
accessors for all non-`deprecated` fields. For example:
@@ -2419,6 +2541,14 @@ accessors for all non-`deprecated` fields. For example:
~~~
+
+~~~{.swift}
+ let hp = monster.hp
+ let mana = monster.mana
+ let name = monster.name // returns an optional string
+~~~
+
+
These should hold `300`, `150`, and `"Orc"` respectively.
*Note: The default value `150` wasn't stored in `mana`, but we are still able to retrieve it.*
@@ -2544,6 +2674,15 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
~~~
+
+~~~{.swift}
+ let pos = monster.pos
+ let x = pos.x
+ let y = pos.y
+ let z = pos.z
+~~~
+
+
`x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively.
*Note: Had we not set `pos` during serialization, it would be a `NULL`-value.*
@@ -2644,6 +2783,20 @@ FlatBuffers `vector`.
~~~
+
+~~~{.swift}
+ // Get a the count of objects in the vector
+ let count = monster.inventoryCount
+
+ // get item at index 4
+ let object = monster.inventory(at: 4)
+
+ // or you can fetch the entire array
+ let inv = monster.inventory
+ // inv[4] should equal object
+~~~
+
+
For `vector`s of `table`s, you can access the elements like any other vector,
except your need to handle the result as a FlatBuffer `table`:
@@ -2756,6 +2909,16 @@ except your need to handle the result as a FlatBuffer `table`:
let second_weapon_damage = wep2.damage();
~~~
+
+~~~{.swift}
+ // Get the count of weapon objects
+ let wepsCount = monster.weaponsCount
+
+ let weapon2 = monster.weapons(at: 1)
+ let weaponName = weapon2.name
+ let weaponDmg = weapon2.damage
+~~~
+
Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created
the `union`, we need to get both parts of the `union`: the type and the data.
@@ -2943,6 +3106,17 @@ We can access the type to dynamically cast the data as needed (since the
~~~
+
+~~~{.swift}
+ // Get and check if the monster has an equipped item
+ if monster.equippedType == .weapon {
+ let _weapon = monster.equipped(type: Weapon.self)
+ let name = _weapon.name // should return "Axe"
+ let dmg = _weapon.damage // should return 5
+ }
+~~~
+
+
## Mutating FlatBuffers
As you saw above, typically once you have created a FlatBuffer, it is read-only
@@ -3046,6 +3220,15 @@ mutators like so:
~~~
+
+~~~{.swift}
+ let monster = Monster.getRootAsMonster(bb: ByteBuffer(bytes: buf))
+ monster.mutate(hp: 10) // mutates a value in a table
+ monster.pos.mutate(z: 4) // mutates a value in a struct
+ monster.mutate(inventory: 6, at index: 0) // mutates a value in an Scalar array
+~~~
+
+
We use the somewhat verbose term `mutate` instead of `set` to indicate that this
is a special use case, not to be confused with the default way of constructing
FlatBuffer data.
@@ -3215,5 +3398,7 @@ For your chosen language, see:
[Use in Rust](@ref flatbuffers_guide_use_rust)
-
+
+[Use in Swift](@ref flatbuffers_guide_use_swift)
+
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index 1f013a8b6..eac70d9ed 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -47,26 +47,26 @@ namespace flatbuffers {
// of type tokens.
// clang-format off
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
- TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8, UByte) \
- TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8, UByte) /* begin scalar/int */ \
- TD(BOOL, "bool", uint8_t, boolean,bool, bool, bool, bool, Boolean) \
- TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8, Byte) \
- TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8, UByte) \
- TD(SHORT, "short", int16_t, short, int16, short, int16, i16, Short) \
- TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16, UShort) \
- TD(INT, "int", int32_t, int, int32, int, int32, i32, Int) \
- TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32, UInt) \
- TD(LONG, "long", int64_t, long, int64, long, int64, i64, Long) \
- TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64, ULong) /* end int */ \
- TD(FLOAT, "float", float, float, float32, float, float32, f32, Float) /* begin float */ \
- TD(DOUBLE, "double", double, double, float64, double, float64, f64, Double) /* end float/scalar */
+ TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) \
+ TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) /* begin scalar/int */ \
+ TD(BOOL, "bool", uint8_t, boolean,bool, bool, bool, bool, Boolean, Bool) \
+ TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8, Byte, Int8) \
+ TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) \
+ TD(SHORT, "short", int16_t, short, int16, short, int16, i16, Short, Int16) \
+ TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16, UShort, UInt16) \
+ TD(INT, "int", int32_t, int, int32, int, int32, i32, Int, Int32) \
+ TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32, UInt, UInt32) \
+ TD(LONG, "long", int64_t, long, int64, long, int64, i64, Long, Int64) \
+ TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64, ULong, UInt64) /* end int */ \
+ TD(FLOAT, "float", float, float, float32, float, float32, f32, Float, Float32) /* begin float */ \
+ TD(DOUBLE, "double", double, double, float64, double, float64, f64, Double, Double) /* end float/scalar */
#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
- TD(STRING, "string", Offset, int, int, StringOffset, int, unused, Int) \
- TD(VECTOR, "", Offset, int, int, VectorOffset, int, unused, Int) \
- TD(STRUCT, "", Offset, int, int, int, int, unused, Int) \
- TD(UNION, "", Offset, int, int, int, int, unused, Int)
+ TD(STRING, "string", Offset, int, int, StringOffset, int, unused, Int, Offset) \
+ TD(VECTOR, "", Offset, int, int, VectorOffset, int, unused, Int, Offset) \
+ TD(STRUCT, "", Offset, int, int, int, int, unused, Int, Offset) \
+ TD(UNION, "", Offset, int, int, int, int, unused, Int, Offset)
#define FLATBUFFERS_GEN_TYPE_ARRAY(TD) \
- TD(ARRAY, "", int, int, int, int, int, unused, Int)
+ TD(ARRAY, "", int, int, int, int, int, unused, Int, Offset)
// The fields are:
// - enum
// - FlatBuffers schema type.
@@ -577,6 +577,7 @@ struct IDLOptions {
kLobster = 1 << 13,
kRust = 1 << 14,
kKotlin = 1 << 15,
+ kSwift = 1 << 16,
kMAX
};
@@ -1051,6 +1052,11 @@ extern bool GenerateJsonSchema(const Parser &parser, const std::string &path,
extern bool GenerateKotlin(const Parser &parser, const std::string &path,
const std::string &file_name);
+// Generate Swift classes.
+// See idl_gen_swift.cpp
+extern bool GenerateSwift(const Parser &parser, const std::string &path,
+ const std::string &file_name);
+
// Generate a schema file from the internal representation, useful after
// parsing a .proto schema.
extern std::string GenerateFBS(const Parser &parser,
diff --git a/samples/sample_binary.swift b/samples/sample_binary.swift
new file mode 100644
index 000000000..e334fab70
--- /dev/null
+++ b/samples/sample_binary.swift
@@ -0,0 +1,68 @@
+ // THIS IS JUST TO SHOW THE CODE, PLEASE DO IMPORT FLATBUFFERS WITH SPM..
+import Flatbuffers
+
+typealias Monster = MyGame1.Sample.Monster
+typealias Weapon = MyGame1.Sample.Weapon
+typealias Color = MyGame1.Sample.Color
+typealias Vec3 = MyGame1.Sample.Vec3
+
+func main() {
+ let expectedDMG: [Int16] = [3, 5]
+ let expectedNames = ["Sword", "Axe"]
+
+ let builder = FlatBufferBuilder(initialSize: 1024)
+ let weapon1Name = builder.create(string: expectedNames[0])
+ let weapon2Name = builder.create(string: expectedNames[1])
+
+ let weapon1Start = Weapon.startWeapon(builder)
+ Weapon.add(name: weapon1Name, builder)
+ Weapon.add(damage: expectedDMG[0], builder)
+ let sword = Weapon.endWeapon(builder, start: weapon1Start)
+ let weapon2Start = Weapon.startWeapon(builder)
+ Weapon.add(name: weapon2Name, builder)
+ Weapon.add(damage: expectedDMG[1], builder)
+ let axe = Weapon.endWeapon(builder, start: weapon2Start)
+
+ let name = builder.create(string: "Orc")
+ let inventory: [Byte] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ let inventoryOffset = builder.createVector(inventory)
+
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+ let pos = builder.create(struct: MyGame.Sample.createVec3(x: 1, y: 2, z: 3), type: Vec3.self)
+
+ let start = Monster.startMonster(builder)
+ Monster.add(pos: pos, builder)
+ Monster.add(hp: 300, builder)
+ Monster.add(name: name, builder)
+ Monster.add(inventory: inventoryOffset, builder)
+ Monster.add(color: .red, builder)
+ Monster.add(weapons: weaponsOffset, builder)
+ Monster.add(equippedType: .weapon, builder)
+ Monster.add(equipped: axe, builder)
+ var orc = Monster.endMonster(builder, start: start)
+ builder.finish(offset: orc)
+
+ var buf = builder.sizedByteArray
+ var monster = Monster.getRootAsMonster(bb: ByteBuffer(bytes: buf))
+
+ assert(monster.mana == 150)
+ assert(monster.hp == 300)
+ assert(monster.name == "Orc")
+ assert(monster.color == MyGame1.Sample.Color.red)
+ assert(monster.pos != nil)
+ for i in 0..
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+namespace swift {
+
+inline std::string GenIndirect(const std::string &reading) {
+ return "{{ACCESS}}.indirect(" + reading + ")";
+}
+
+inline std::string GenArrayMainBody(const std::string &optional) {
+ return "\tpublic func {{VALUENAME}}(at index: Int32) -> {{VALUETYPE}}" +
+ optional + " { ";
+}
+
+inline char LowerCase(char c) {
+ return static_cast(::tolower(static_cast(c)));
+}
+
+class SwiftGenerator : public BaseGenerator {
+ private:
+ const Namespace *cur_name_space_;
+ CodeWriter code_;
+ std::unordered_set keywords_;
+ std::set namespaces_;
+ int namespace_depth;
+
+ public:
+ SwiftGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "."),
+ cur_name_space_(nullptr) {
+ namespace_depth = 0;
+ static const char *const keywords[] = {
+ "enum", "private", "public", "internal", "fileprivate", "static", "var",
+ "URL", "struct", "let", "class", "Any", "nil", nullptr,
+ };
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+
+ bool generate() {
+ code_.Clear();
+ code_.SetValue("ACCESS", "_accessor");
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n";
+ code_ += "import FlatBuffers\n";
+ // Generate code for all the enum declarations.
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (!enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenEnum(enum_def);
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenStructReader(struct_def);
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenStructWriter(struct_def);
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenTable(struct_def);
+ }
+ }
+
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ const auto filename = GeneratedFileName(path_, file_name_);
+ const auto final_code = code_.ToString();
+ return SaveFile(filename.c_str(), final_code, false);
+ }
+
+ void mark(const std::string &str) {
+ code_.SetValue("MARKVALUE", str);
+ code_ += "\n// MARK: - {{MARKVALUE}}\n";
+ }
+
+ // Generates the create function for swift
+ void GenStructWriter(const StructDef &struct_def) {
+ code_.SetValue("STRUCTNAME", Name(struct_def));
+ std::string static_type = this->namespace_depth == 0 ? "" : "static ";
+ code_ += "public " + static_type + "func create{{STRUCTNAME}}(\\";
+ std::string func_header = "";
+ GenerateStructArgs(struct_def, &func_header, "");
+ code_ += func_header.substr(0, func_header.size() - 2) + "\\";
+ code_ += ") -> UnsafeMutableRawPointer {";
+ code_ +=
+ "\tlet memory = UnsafeMutableRawPointer.allocate(byteCount: "
+ "{{STRUCTNAME}}.size, alignment: {{STRUCTNAME}}.alignment)";
+ code_ +=
+ "\tmemory.initializeMemory(as: UInt8.self, repeating: 0, count: "
+ "{{STRUCTNAME}}.size)";
+ GenerateStructBody(struct_def, "");
+ code_ += "\treturn memory";
+ code_ += "}\n";
+ }
+
+ void GenerateStructBody(const StructDef &struct_def,
+ const std::string &nameprefix, int offset = 0) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto name = nameprefix + Name(field);
+ const auto &field_type = field.value.type;
+ auto type = GenTypeBasic(field_type, false);
+ if (IsStruct(field.value.type)) {
+ GenerateStructBody(*field_type.struct_def, (nameprefix + field.name),
+ static_cast(field.value.offset));
+ } else {
+ auto off = NumToString(offset + field.value.offset);
+ code_ += "\tmemory.storeBytes(of: " + name +
+ (field_type.enum_def ? ".rawValue" : "") +
+ ", toByteOffset: " + off + ", as: " + type + ".self)";
+ }
+ }
+ }
+
+ void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const std::string &nameprefix) {
+ auto &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ const auto &field_type = field.value.type;
+ if (IsStruct(field.value.type)) {
+ GenerateStructArgs(*field_type.struct_def, code_ptr,
+ (nameprefix + field.name));
+ } else {
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code += nameprefix + name + ": " + type;
+ code += ", ";
+ }
+ }
+ }
+
+ void GenObjectHeader(const StructDef &struct_def) {
+ code_.SetValue("STRUCTNAME", Name(struct_def));
+ code_.SetValue("PROTOCOL",
+ struct_def.fixed ? "Readable" : "FlatBufferObject");
+ code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
+ code_ += "public struct {{STRUCTNAME}}: {{PROTOCOL}} {";
+ code_ += "\tprivate var {{ACCESS}}: {{OBJECTTYPE}}";
+ if (struct_def.fixed) {
+ code_.SetValue("BYTESIZE", NumToString(struct_def.bytesize));
+ code_.SetValue("MINALIGN", NumToString(struct_def.minalign));
+ code_ += "\tpublic static var size = {{BYTESIZE}}";
+ code_ += "\tpublic static var alignment = {{MINALIGN}}\t";
+ } else {
+ if (parser_.file_identifier_.length()) {
+ code_.SetValue("FILENAME", parser_.file_identifier_);
+ code_ +=
+ "\tpublic static func finish(_ fbb: FlatBufferBuilder, end: "
+ "Offset, prefix: Bool = false) { fbb.finish(offset: end, "
+ "fileId: "
+ "\"{{FILENAME}}\", addPrefix: prefix) }";
+ }
+ code_ +=
+ "\tpublic static func getRootAs{{STRUCTNAME}}(bb: ByteBuffer) -> "
+ "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
+ "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
+ "Int32(bb.reader))) }\n";
+ code_ += "\tprivate init(_ t: Table) { {{ACCESS}} = t }";
+ }
+ code_ +=
+ "\tpublic init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
+ "{{OBJECTTYPE}}(bb: "
+ "bb, position: o) }";
+ code_ += "";
+ }
+
+ // Generates the reader for swift
+ void GenTable(const StructDef &struct_def) {
+ GenObjectHeader(struct_def);
+ GenTableReader(struct_def);
+ GenTableWriter(struct_def);
+ code_ += "}\n";
+ }
+
+ void GenTableReader(const StructDef &struct_def) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenTableReaderFields(field);
+ }
+ }
+
+ void GenTableWriter(const StructDef &struct_def) {
+ flatbuffers::FieldDef *key_field = nullptr;
+
+ code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
+ code_ +=
+ "\tpublic static func start{{STRUCTNAME}}(_ fbb: FlatBufferBuilder) -> "
+ "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
+
+ std::vector require_fields;
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ if (field.required)
+ require_fields.push_back(NumToString(field.value.offset));
+
+ GenTableWriterFields(
+ field, static_cast(it - struct_def.fields.vec.begin()));
+ }
+ code_ +=
+ "\tpublic static func end{{STRUCTNAME}}(_ fbb: FlatBufferBuilder, "
+ "start: "
+ "UOffset) -> Offset { let end = Offset(offset: "
+ "fbb.endTable(at: start))\\";
+ if (require_fields.capacity() != 0) {
+ std::string fields = "";
+ for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
+ fields += *it + ", ";
+ code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
+ code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
+ }
+ code_ += "; return end }";
+
+ std::string spacing = "\t\t";
+
+ if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
+ code_.SetValue("VALUENAME", struct_def.name);
+ code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
+
+ code_ +=
+ "\tpublic static func "
+ "sortVectorOf{{VALUENAME}}(offsets:[Offset], "
+ "_ fbb: FlatBufferBuilder) -> Offset {";
+ code_ += spacing + "var off = offsets";
+ code_ +=
+ spacing +
+ "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
+ "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
+ "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
+ code_ += spacing + "return fbb.createVector(ofOffsets: off)";
+ code_ += "\t}";
+ GenLookup(*key_field);
+ }
+ }
+
+ void GenTableWriterFields(const FieldDef &field, const int position) {
+ std::string builder_string = ", _ fbb: FlatBufferBuilder) { fbb.add(";
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ code_.SetValue("OFFSET", NumToString(position));
+ code_.SetValue("CONSTANT", field.value.constant);
+ std::string check_if_vector =
+ (field.value.type.base_type == BASE_TYPE_VECTOR ||
+ field.value.type.base_type == BASE_TYPE_ARRAY)
+ ? "VectorOf"
+ : "";
+ code_ +=
+ "\tpublic static func add" + check_if_vector + "({{VALUENAME}}: \\";
+
+ if (IsScalar(field.value.type.base_type) &&
+ !IsBool(field.value.type.base_type)) {
+ auto is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
+ code_ += "{{VALUETYPE}}" + builder_string + "element: {{VALUENAME}}" +
+ is_enum + ", def: {{CONSTANT}}, at: {{OFFSET}}) }";
+ return;
+ }
+ if (IsBool(field.value.type.base_type)) {
+ code_.SetValue("VALUETYPE", "Bool");
+ code_.SetValue("CONSTANT",
+ "0" == field.value.constant ? "false" : "true");
+ code_ += "{{VALUETYPE}}" + builder_string +
+ "condition: {{VALUENAME}}, def: {{CONSTANT}}, at: {{OFFSET}}) }";
+ return;
+ }
+
+ auto offset_type = field.value.type.base_type == BASE_TYPE_STRING
+ ? "Offset"
+ : "Offset";
+ auto reader_type =
+ IsStruct(field.value.type) && field.value.type.struct_def->fixed
+ ? "structOffset: {{OFFSET}}) }"
+ : "offset: {{VALUENAME}}, at: {{OFFSET}}) }";
+ code_ += offset_type + builder_string + reader_type;
+ }
+
+ void GenTableReaderFields(const FieldDef &field) {
+ auto offset = NumToString(field.value.offset);
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ code_.SetValue("OFFSET", offset);
+ code_.SetValue("CONSTANT", field.value.constant);
+ std::string const_string = "return o == 0 ? {{CONSTANT}} : ";
+
+ if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
+ !IsBool(field.value.type.base_type)) {
+ code_ += GenReaderMainBody() + GenOffset() + const_string +
+ GenReader("VALUETYPE", "o") + " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
+ return;
+ }
+
+ if (IsBool(field.value.type.base_type)) {
+ code_.SetValue("VALUETYPE", "Bool");
+ code_ += GenReaderMainBody() + "\\";
+ code_.SetValue("VALUETYPE", "Byte");
+ code_ += GenOffset() +
+ "return o == 0 ? false : 0 != " + GenReader("VALUETYPE", "o") +
+ " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
+ return;
+ }
+
+ if (IsEnum(field.value.type)) {
+ auto default_value = GenEnumDefaultValue(field);
+ code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
+ code_ += GenReaderMainBody() + "\\";
+ code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
+ GenEnumConstructor("o") + "?? " + default_value + " }";
+ if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
+ code_ += GenMutate("o", GenOffset(), true);
+ return;
+ }
+
+ if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody("?") + GenOffset() + const_string +
+ GenConstructor("o + {{ACCESS}}.postion");
+ return;
+ }
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody("?") + GenOffset() + const_string +
+ GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
+ break;
+
+ case BASE_TYPE_STRING:
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody("?") + GenOffset() + const_string +
+ "{{ACCESS}}.string(at: o) }";
+ code_ +=
+ "\tpublic var {{VALUENAME}}SegmentArray: [UInt8]? { return "
+ "{{ACCESS}}.getVector(at: {{OFFSET}}) }";
+ break;
+
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR:
+ GenTableReaderVectorFields(field, const_string);
+ break;
+ case BASE_TYPE_UNION:
+ code_.SetValue("CONSTANT", "nil");
+ code_ +=
+ "\tpublic func {{VALUENAME}}(type: "
+ "T.Type) -> T? { " +
+ GenOffset() + const_string + "{{ACCESS}}.union(o) }";
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+
+ void GenTableReaderVectorFields(const FieldDef &field,
+ const std::string &const_string) {
+ auto vectortype = field.value.type.VectorType();
+ code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
+ code_ += "\tpublic var {{VALUENAME}}Count: Int32 { " + GenOffset() +
+ const_string + "{{ACCESS}}.vector(count: o) }";
+ code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) == true
+ ? field.value.constant
+ : "nil");
+ auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?";
+ nullable = IsEnum(vectortype) == true ? "?" : nullable;
+ if (vectortype.base_type != BASE_TYPE_UNION) {
+ code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
+ } else {
+ code_ +=
+ "\tpublic func {{VALUENAME}}(at index: "
+ "Int32, type: T.Type) -> T? { " +
+ GenOffset() + "\\";
+ }
+
+ if (IsBool(vectortype.base_type)) {
+ code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
+ code_.SetValue("VALUETYPE", "Byte");
+ }
+ if (!IsEnum(vectortype))
+ code_ +=
+ const_string + (IsBool(vectortype.base_type) ? "0 != " : "") + "\\";
+
+ if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
+ !IsBool(field.value.type.base_type)) {
+ code_ +=
+ "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ code_ +=
+ "\tpublic var {{VALUENAME}}: [{{VALUETYPE}}] { return "
+ "{{ACCESS}}.getVector(at: {{OFFSET}}) ?? [] }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
+ return;
+ }
+ if (vectortype.base_type == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code_ += GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
+ return;
+ }
+
+ if (vectortype.base_type == BASE_TYPE_STRING) {
+ code_ +=
+ "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}}) }";
+ return;
+ }
+
+ if (IsEnum(vectortype)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
+ code_ += "return o == 0 ? " + GenEnumDefaultValue(field) +
+ " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
+ "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}})) }";
+ return;
+ }
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ code_ +=
+ "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}}) }";
+ return;
+ }
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ code_ += GenConstructor(
+ "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
+ "{{SIZE}})");
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ GenByKeyFunctions(key_field);
+ break;
+ }
+ }
+ }
+ }
+
+ void GenByKeyFunctions(const FieldDef &key_field) {
+ code_.SetValue("TYPE", GenType(key_field.value.type));
+ code_ +=
+ "\tpublic func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? { \\";
+ code_ += GenOffset() +
+ "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
+ "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
+ }
+
+ // Generates the reader for swift
+ void GenStructReader(const StructDef &struct_def) {
+ GenObjectHeader(struct_def);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = NumToString(field.value.offset);
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ code_.SetValue("OFFSET", offset);
+ if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
+ code_ +=
+ GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("{{OFFSET}}", "");
+ } else if (IsEnum(field.value.type)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
+ code_ += GenReaderMainBody() + "return " +
+ GenEnumConstructor("{{OFFSET}}") + "?? " +
+ GenEnumDefaultValue(field) + " }";
+ } else if (IsStruct(field.value.type)) {
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_ += GenReaderMainBody() + "return " +
+ GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
+ }
+ }
+
+ code_ += "}\n";
+ }
+
+ void GenEnum(const EnumDef &enum_def) {
+ if (enum_def.generated) return;
+ code_.SetValue("ENUM_NAME", GenEnumDecl(enum_def));
+ code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
+ code_ += "public {{ENUM_NAME}}: {{BASE_TYPE}}, Enum { ";
+ code_ += "\tpublic typealias T = {{BASE_TYPE}}";
+ code_ +=
+ "\tpublic static var byteSize: Int { return "
+ "MemoryLayout<{{BASE_TYPE}}>.size "
+ "}";
+ code_ += "\tpublic var value: {{BASE_TYPE}} { return self.rawValue }";
+
+ std::string enum_code = "\tcase ";
+ int keyCount = 0;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ auto key = "KEY" + NumToString(keyCount);
+ auto value = "VALUE" + NumToString(keyCount);
+ auto name = Name(ev);
+ std::transform(name.begin(), name.end(), name.begin(), LowerCase);
+ code_.SetValue(key, name);
+ code_.SetValue(value, enum_def.ToString(ev));
+ enum_code += "{{" + key + "}} = {{" + value + "}}, ";
+ keyCount++;
+ }
+ code_ += enum_code.substr(0, enum_code.size() - 2);
+ code_ += "}\n";
+ }
+
+ void GenLookup(const FieldDef &key_field) {
+ code_.SetValue("OFFSET", NumToString(key_field.value.offset));
+ auto offset_reader =
+ "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
+ "fbb: fbb)";
+ std::string spacing = "\t\t";
+ std::string double_spacing = spacing + "\t";
+
+ code_.SetValue("TYPE", GenType(key_field.value.type));
+ code_ +=
+ "\tfileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
+ "fbb: "
+ "ByteBuffer) -> {{VALUENAME}}? {";
+
+ if (key_field.value.type.base_type == BASE_TYPE_STRING)
+ code_ += spacing + "let key = key.utf8.map { $0 }";
+ code_ += spacing +
+ "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
+ code_ += spacing + "var start: Int32 = 0";
+ code_ += spacing + "while span != 0 {";
+ code_ += double_spacing + "var middle = span / 2";
+ code_ +=
+ double_spacing +
+ "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
+ if (key_field.value.type.base_type == BASE_TYPE_STRING) {
+ code_ += double_spacing + "let comp = Table.compare(" + offset_reader +
+ ", key, fbb: fbb)";
+ } else {
+ code_ += double_spacing +
+ "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
+ offset_reader + "))";
+ }
+
+ code_ += double_spacing + "if comp > 0 {";
+ code_ += double_spacing + "\tspan = middle";
+ code_ += double_spacing + "} else if comp < 0 {";
+ code_ += double_spacing + "\tmiddle += 1";
+ code_ += double_spacing + "\tstart += middle";
+ code_ += double_spacing + "\tspan -= middle";
+ code_ += double_spacing + "} else {";
+ code_ += double_spacing + "\treturn {{VALUENAME}}(fbb, o: tableOffset)";
+ code_ += double_spacing + "}";
+ code_ += spacing + "}";
+ code_ += spacing + "return nil";
+ code_ += "\t}";
+ }
+
+ std::string GenOffset() { return "let o = {{ACCESS}}.offset({{OFFSET}}); "; }
+
+ std::string GenReaderMainBody(const std::string &optional = "") {
+ return "\tpublic var {{VALUENAME}}: {{VALUETYPE}}" + optional + " { ";
+ }
+
+ std::string GenReader(const std::string &type,
+ const std::string &at = "{{OFFSET}}") {
+ return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
+ }
+
+ std::string GenConstructor(const std::string &offset) {
+ return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
+ }
+
+ std::string GenMutate(const std::string &offset,
+ const std::string &get_offset, bool isRaw = false) {
+ return "\tpublic func mutate({{VALUENAME}}: {{VALUETYPE}}) -> Bool {" +
+ get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" +
+ (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
+ }
+
+ std::string GenMutateArray() {
+ return "\tpublic func mutate({{VALUENAME}}: {{VALUETYPE}}, at index: "
+ "Int32) -> Bool { " +
+ GenOffset() +
+ "return {{ACCESS}}.directMutate({{VALUENAME}}, index: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ auto enum_val = enum_def.FindByValue(value.constant);
+ std::string name;
+ if (enum_val) {
+ name = enum_val->name;
+ } else {
+ const auto &ev = **enum_def.Vals().begin();
+ name = ev.name;
+ }
+ std::transform(name.begin(), name.end(), name.begin(), LowerCase);
+ return "{{VALUETYPE}}." + name;
+ }
+
+ std::string GenEnumConstructor(const std::string &at) {
+ return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
+ }
+
+ std::string GenType(const Type &type) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenType(type.VectorType())
+ : GenTypePointer(type));
+ }
+
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ case BASE_TYPE_UNION:
+ default: return "FlatBufferObject";
+ }
+ }
+
+ std::string GenTypeBasic(const Type &type) const {
+ return GenTypeBasic(type, true);
+ }
+
+ std::string GenTypeBasic(const Type &type, bool can_override) const {
+ // clang-format off
+ static const char * const swift_type[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
+ #STYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ if (can_override) {
+ if (type.enum_def)
+ return WrapInNameSpace(type.enum_def->defined_namespace,
+ Name(*type.enum_def));
+ if (type.base_type == BASE_TYPE_BOOL) return "Bool";
+ }
+ return swift_type[static_cast(type.base_type)];
+ }
+
+ std::string GenEnumDecl(const EnumDef &enum_def) const {
+ return "enum " + Name(enum_def);
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(MakeCamel(def.name, false));
+ }
+
+ static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.swift";
+ }
+ // MARK: - Copied from the cpp implementation, needs revisiting
+ void SetNameSpace(const Namespace *ns) {
+ if (cur_name_space_ == ns) { return; }
+ // Compute the size of the longest common namespace prefix.
+ // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+ // and common_prefix_size = 2
+ size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+ size_t new_size = ns ? ns->components.size() : 0;
+
+ size_t common_prefix_size = 0;
+ while (common_prefix_size < old_size && common_prefix_size < new_size &&
+ ns->components[common_prefix_size] ==
+ cur_name_space_->components[common_prefix_size]) {
+ common_prefix_size++;
+ }
+
+ // Close cur_name_space in reverse order to reach the common prefix.
+ // In the previous example, D then C are closed.
+ for (size_t j = old_size; j > common_prefix_size; --j) {
+ if (namespace_depth != 0) {
+ code_ += "}";
+ namespace_depth -= 1;
+ }
+ mark(cur_name_space_->components[j - 1]);
+ }
+ if (old_size != common_prefix_size) { code_ += ""; }
+
+ // open namespace parts to reach the ns namespace
+ // in the previous example, E, then F, then G are opened
+ bool is_extension = false;
+ for (auto j = common_prefix_size; j < new_size; ++j) {
+ std::string name = ns->components[j];
+ if (namespaces_.find(name) == namespaces_.end()) {
+ code_ += "public enum " + name + " {";
+ namespace_depth += 1;
+ namespaces_.insert(name);
+ } else {
+ code_ += "}";
+ is_extension = true;
+ }
+ }
+ if (is_extension) {
+ code_.SetValue("EXTENSION", FullNamespace(".", *ns));
+ code_ += "extension {{EXTENSION}} {";
+ }
+ if (new_size != common_prefix_size) { code_ += ""; }
+ cur_name_space_ = ns;
+ }
+};
+} // namespace swift
+bool GenerateSwift(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ swift::SwiftGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index 7c3c46dc1..13c8c3add 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -2195,7 +2195,8 @@ bool Parser::SupportsAdvancedUnionFeatures() const {
(opts.lang_to_generate &
~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs |
IDLOptions::kPhp | IDLOptions::kJava | IDLOptions::kCSharp |
- IDLOptions::kKotlin | IDLOptions::kBinary)) == 0;
+ IDLOptions::kKotlin | IDLOptions::kBinary | IDLOptions::kSwift)) ==
+ 0;
}
bool Parser::SupportsAdvancedArrayFeatures() const {
diff --git a/swift/Package.swift b/swift/Package.swift
new file mode 100644
index 000000000..18bb90a4e
--- /dev/null
+++ b/swift/Package.swift
@@ -0,0 +1,22 @@
+// swift-tools-version:5.1
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "FlatBuffers",
+ platforms: [
+ .iOS(.v11),
+ .macOS(.v10_14),
+ ],
+ products: [
+ .library(
+ name: "FlatBuffers",
+ targets: ["FlatBuffers"]),
+ ],
+ targets: [
+ .target(
+ name: "FlatBuffers",
+ dependencies: []),
+ ]
+)
diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift
new file mode 100644
index 000000000..654b265cf
--- /dev/null
+++ b/swift/Sources/FlatBuffers/ByteBuffer.swift
@@ -0,0 +1,243 @@
+import Foundation
+
+public final class ByteBuffer {
+
+ /// pointer to the start of the buffer object in memory
+ private var _memory: UnsafeMutableRawPointer
+ /// The size of the elements written to the buffer + their paddings
+ private var _writerSize: Int = 0
+ /// Capacity of UInt8 the buffer can hold
+ private var _capacity: Int
+
+ /// Aliginment of the current memory being written to the buffer
+ internal var alignment = 1
+ /// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer
+ internal var writerIndex: Int { return _capacity - _writerSize }
+
+ /// Reader is the position of the current Writer Index (capacity - size)
+ public var reader: Int { return writerIndex }
+ /// Current size of the buffer
+ public var size: UOffset { return UOffset(_writerSize) }
+ /// Public Pointer to the buffer object in memory. This should NOT be modified for any reason
+ public var memory: UnsafeMutableRawPointer { return _memory }
+ /// Current capacity for the buffer
+ public var capacity: Int { return _capacity }
+
+ /// Constructor that creates a Flatbuffer object from a UInt8
+ /// - Parameter bytes: Array of UInt8
+ public init(bytes: [UInt8]) {
+ let ptr = UnsafePointer(bytes)
+ _memory = UnsafeMutableRawPointer.allocate(byteCount: bytes.count, alignment: alignment)
+ _memory.copyMemory(from: ptr, byteCount: bytes.count)
+ _capacity = bytes.count
+ _writerSize = _capacity
+ }
+
+ /// Constructor that creates a Flatbuffer from the Swift Data type object
+ /// - Parameter data: Swift data Object
+ public init(data: Data) {
+ let pointer = UnsafeMutablePointer.allocate(capacity: data.count)
+ data.copyBytes(to: pointer, count: data.count)
+ _memory = UnsafeMutableRawPointer(pointer)
+ _capacity = data.count
+ _writerSize = _capacity
+ }
+
+ /// Constructor that creates a Flatbuffer instance with a size
+ /// - Parameter size: Length of the buffer
+ init(initialSize size: Int) {
+ let size = size.convertToPowerofTwo
+ _memory = UnsafeMutableRawPointer.allocate(byteCount: size, alignment: alignment)
+ _memory.initializeMemory(as: UInt8.self, repeating: 0, count: size)
+ _capacity = size
+ }
+
+ /// Creates a copy of the existing flatbuffer, by copying it to a different memory.
+ /// - Parameters:
+ /// - memory: Current memory of the buffer
+ /// - count: count of bytes
+ /// - removeBytes: Removes a number of bytes from the current size
+ internal init(memory: UnsafeMutableRawPointer, count: Int, removing removeBytes: Int) {
+ _memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment)
+ _memory.copyMemory(from: memory, byteCount: count)
+ _capacity = count
+ _writerSize = removeBytes
+ }
+
+ deinit { _memory.deallocate() }
+
+ /// Fills the buffer with padding by adding to the writersize
+ /// - Parameter padding: Amount of padding between two to be serialized objects
+ func fill(padding: UInt32) {
+ ensureSpace(size: UInt8(padding))
+ _writerSize += (MemoryLayout.size * Int(padding))
+ }
+
+ ///Adds an array of type Scalar to the buffer memory
+ /// - Parameter elements: An array of Scalars
+ func push(elements: [T]) {
+ let size = elements.count * MemoryLayout.size
+ ensureSpace(size: UInt8(size))
+ elements.lazy.reversed().forEach { (s) in
+ push(value: s, len: MemoryLayout.size(ofValue: s))
+ }
+ }
+
+ /// A custom type of structs that are padded according to the flatbuffer padding,
+ /// - Parameters:
+ /// - value: Pointer to the object in memory
+ /// - size: Size of Value being written to the buffer
+ func push(struct value: UnsafeMutableRawPointer, size: Int) {
+ ensureSpace(size: UInt8(size))
+ _memory.advanced(by: writerIndex - size).copyMemory(from: value, byteCount: size)
+ defer { value.deallocate() }
+ _writerSize += size
+ }
+
+ /// Adds an object of type Scalar into the buffer
+ /// - Parameters:
+ /// - value: Object that will be written to the buffer
+ /// - len: Offset to subtract from the WriterIndex
+ func push(value: T, len: Int) {
+ ensureSpace(size: UInt8(len))
+ var v = value.convertedEndian
+ memcpy(_memory.advanced(by: writerIndex - len), &v, len)
+ _writerSize += len
+ }
+
+ /// Adds a string to the buffer using swift.utf8 object
+ /// - Parameter str: String that will be added to the buffer
+ /// - Parameter len: length of the string
+ func push(string str: String, len: Int) {
+ ensureSpace(size: UInt8(len))
+ if str.utf8.withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != nil {
+ } else {
+ let utf8View = str.utf8
+ for c in utf8View.lazy.reversed() {
+ push(value: c, len: 1)
+ }
+ }
+ }
+
+ /// Writes a string to Bytebuffer using UTF8View
+ /// - Parameters:
+ /// - bytes: Pointer to the view
+ /// - len: Size of string
+ private func push(bytes: UnsafeBufferPointer, len: Int) -> Bool {
+ _memory.advanced(by: writerIndex - len).copyMemory(from:
+ UnsafeRawPointer(bytes.baseAddress!), byteCount: len)
+ _writerSize += len
+ return true
+ }
+
+ /// Write stores an object into the buffer directly or indirectly.
+ ///
+ /// Direct: ignores the capacity of buffer which would mean we are referring to the direct point in memory
+ /// indirect: takes into respect the current capacity of the buffer (capacity - index), writing to the buffer from the end
+ /// - Parameters:
+ /// - value: Value that needs to be written to the buffer
+ /// - index: index to write to
+ /// - direct: Should take into consideration the capacity of the buffer
+ func write(value: T, index: Int, direct: Bool = false) {
+ var index = index
+ if !direct {
+ index = _capacity - index
+ }
+ _memory.storeBytes(of: value, toByteOffset: index, as: T.self)
+ }
+
+ /// Makes sure that buffer has enouch space for each of the objects that will be written into it
+ /// - Parameter size: size of object
+ @discardableResult
+ func ensureSpace(size: UInt8) -> UInt8 {
+ if Int(size) + _writerSize > _capacity { reallocate(size) }
+ assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes")
+ return size
+ }
+
+ /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer
+ /// - Parameter size: Size of the current object
+ fileprivate func reallocate(_ size: UInt8) {
+ let currentWritingIndex = writerIndex
+ while _capacity <= _writerSize + Int(size) {
+ _capacity = _capacity << 1
+ }
+
+ /// solution take from Apple-NIO
+ _capacity = _capacity.convertToPowerofTwo
+
+ let newData = UnsafeMutableRawPointer.allocate(byteCount: _capacity, alignment: alignment)
+ newData.initializeMemory(as: UInt8.self, repeating: 0, count: _capacity)
+ newData
+ .advanced(by: writerIndex)
+ .copyMemory(from: _memory.advanced(by: currentWritingIndex), byteCount: _writerSize)
+ _memory.deallocate()
+ _memory = newData
+ }
+
+ /// Clears the current size of the buffer
+ public func clearSize() {
+ _writerSize = 0
+ }
+
+ /// Clears the current instance of the buffer, replacing it with new memory
+ public func clear() {
+ _writerSize = 0
+ alignment = 1
+ _memory.deallocate()
+ _memory = UnsafeMutableRawPointer.allocate(byteCount: _capacity, alignment: alignment)
+ }
+
+ /// Resizes the buffer size
+ /// - Parameter size: new size for the buffer
+ internal func resize(_ size: Int) {
+ _writerSize = size
+ }
+
+ /// Reads an object from the buffer
+ /// - Parameters:
+ /// - def: Type of the object
+ /// - position: the index of the object in the buffer
+ public func read(def: T.Type, position: Int) -> T {
+ return _memory.advanced(by: position).load(as: T.self)
+ }
+
+ /// Reads a slice from the memory assuming a type of T
+ /// - Parameters:
+ /// - index: index of the object to be read from the buffer
+ /// - count: count of bytes in memory
+ public func readSlice(index: Int32,
+ count: Int32) -> [T] {
+ let start = _memory.advanced(by: Int(index)).assumingMemoryBound(to: T.self)
+ let array = UnsafeBufferPointer(start: start, count: Int(count))
+ return Array(array)
+ }
+
+ /// Reads a string from the buffer and encodes it to a swift string
+ /// - Parameters:
+ /// - index: index of the string in the buffer
+ /// - count: length of the string
+ /// - type: Encoding of the string
+ public func readString(at index: Int32,
+ count: Int32,
+ type: String.Encoding = .utf8) -> String? {
+ let start = _memory.advanced(by: Int(index)).assumingMemoryBound(to: UInt8.self)
+ let bufprt = UnsafeBufferPointer(start: start, count: Int(count))
+ return String(bytes: Array(bufprt), encoding: type)
+ }
+
+ /// Creates a new Flatbuffer object that's duplicated from the current one
+ /// - Parameter removeBytes: the amount of bytes to remove from the current Size
+ public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
+ return ByteBuffer(memory: _memory, count: _capacity, removing: _writerSize - removeBytes)
+ }
+
+ #if DEBUG
+ func debugMemory(str: String) {
+ let bufprt = UnsafeBufferPointer(start: _memory.assumingMemoryBound(to: UInt8.self),
+ count: _capacity)
+ let a = Array(bufprt)
+ print(str, a, " \nwith buffer size: \(a.count) and writer size: \(_writerSize)")
+ }
+ #endif
+}
diff --git a/swift/Sources/FlatBuffers/Constants.swift b/swift/Sources/FlatBuffers/Constants.swift
new file mode 100644
index 000000000..889b0cc3c
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Constants.swift
@@ -0,0 +1,89 @@
+#if os(Linux)
+import CoreFoundation
+#else
+import Foundation
+#endif
+
+/// A boolean to see if the system is littleEndian
+let isLitteEndian = CFByteOrderGetCurrent() == Int(CFByteOrderLittleEndian.rawValue)
+/// Constant for the file id length
+let FileIdLength = 4
+/// Type aliases
+public typealias Byte = UInt8
+public typealias UOffset = UInt32
+public typealias SOffset = Int32
+public typealias VOffset = UInt16
+/// Maximum size for a buffer
+public let FlatBufferMaxSize = UInt32.max << ((MemoryLayout.size * 8 - 1) - 1)
+
+/// Protocol that confirms all the numbers
+///
+/// Scalar is used to confirm all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer.
+public protocol Scalar: Equatable {
+ associatedtype NumericValue
+ var convertedEndian: NumericValue { get }
+}
+
+extension Scalar where Self: FixedWidthInteger {
+ /// Converts the value from BigEndian to LittleEndian
+ ///
+ /// Converts values to little endian on machines that work with BigEndian, however this is NOT TESTED yet.
+ public var convertedEndian: NumericValue {
+ if isLitteEndian { return self as! Self.NumericValue }
+ fatalError("This is not tested! please report an issue on the offical flatbuffers repo")
+ }
+}
+
+extension Double: Scalar {
+ public typealias NumericValue = UInt64
+
+ public var convertedEndian: UInt64 {
+ if isLitteEndian { return self.bitPattern }
+ return self.bitPattern.littleEndian
+ }
+}
+
+extension Float32: Scalar {
+ public typealias NumericValue = UInt32
+
+ public var convertedEndian: UInt32 {
+ if isLitteEndian { return self.bitPattern }
+ return self.bitPattern.littleEndian
+ }
+}
+
+extension Int: Scalar {
+ public typealias NumericValue = Int
+}
+
+extension Int8: Scalar {
+ public typealias NumericValue = Int8
+}
+
+extension Int16: Scalar {
+ public typealias NumericValue = Int16
+}
+
+extension Int32: Scalar {
+ public typealias NumericValue = Int32
+}
+
+extension Int64: Scalar {
+ public typealias NumericValue = Int64
+}
+
+extension UInt8: Scalar {
+ public typealias NumericValue = UInt8
+}
+
+extension UInt16: Scalar {
+ public typealias NumericValue = UInt16
+}
+
+extension UInt32: Scalar {
+ public typealias NumericValue = UInt32
+}
+
+extension UInt64: Scalar {
+ public typealias NumericValue = UInt64
+}
diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift
new file mode 100644
index 000000000..84fba1be9
--- /dev/null
+++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift
@@ -0,0 +1,486 @@
+import Foundation
+
+public final class FlatBufferBuilder {
+
+ /// Vtables used in the buffer are stored in here, so they would be written later in EndTable
+ private var _vtable: [UInt32] = []
+ /// Reference Vtables that were already written to the buffer
+ private var _vtables: [UOffset] = []
+ /// Flatbuffer data will be written into
+ private var _bb: ByteBuffer
+ /// A check if the buffer is being written into by a different table
+ private var isNested = false
+ /// Dictonary that stores a map of all the strings that were written to the buffer
+ private var stringOffsetMap: [String: Offset] = [:]
+ /// A check to see if finish(::) was ever called to retreive data object
+ private var finished = false
+ /// A check to see if the buffer should serialize Default values
+ private var serializeDefaults: Bool
+
+ /// Current alignment for the buffer
+ var _minAlignment: Int = 0 {
+ didSet {
+ _bb.alignment = _minAlignment
+ }
+ }
+
+ /// Gives a read access to the buffer's size
+ public var size: UOffset { return _bb.size }
+ /// Data representation of the buffer
+ public var data: Data {
+ assert(finished, "Data shouldn't be called before finish()")
+ return Data(bytes: _bb.memory.advanced(by: _bb.writerIndex),
+ count: _bb.capacity - _bb.writerIndex)
+ }
+ /// Get's the fully sized buffer stored in memory
+ public var fullSizedByteArray: [UInt8] {
+ let ptr = UnsafeBufferPointer(start: _bb.memory.assumingMemoryBound(to: UInt8.self),
+ count: _bb.capacity)
+ return Array(ptr)
+ }
+ /// Returns the written size of the buffer
+ public var sizedByteArray: [UInt8] {
+ let cp = _bb.capacity - _bb.writerIndex
+ let start = _bb.memory.advanced(by: _bb.writerIndex)
+ .bindMemory(to: UInt8.self, capacity: cp)
+
+ let ptr = UnsafeBufferPointer(start: start, count: cp)
+ return Array(ptr)
+ }
+ /// Returns the buffer
+ public var buffer: ByteBuffer { return _bb }
+
+ // MARK: - Init
+
+ /// initialize the buffer with a size
+ /// - Parameters:
+ /// - initialSize: Initial size for the buffer
+ /// - force: Allows default to be serialized into the buffer
+ public init(initialSize: Int32 = 1024, serializeDefaults force: Bool = false) {
+ assert(initialSize > 0, "Size should be greater than zero!")
+ guard isLitteEndian else {
+ fatalError("Reading/Writing a buffer in big endian machine is not supported on swift")
+ }
+ serializeDefaults = force
+ _bb = ByteBuffer(initialSize: Int(initialSize))
+ }
+
+ /// Clears the buffer and the builder from it's data
+ public func clear() {
+ _minAlignment = 0
+ isNested = false
+ _bb.clear()
+ stringOffsetMap = [:]
+ }
+
+ /// Removes all the offsets from the VTable
+ public func clearOffsets() {
+ _vtable = []
+ }
+}
+
+// MARK: - Create Tables
+
+extension FlatBufferBuilder {
+
+ /// Checks if the required fields were serialized into the buffer
+ /// - Parameters:
+ /// - table: offset for the table
+ /// - fields: Array of all the important fields to be serialized
+ public func require(table: Offset, fields: [Int32]) {
+ for field in fields {
+ let start = _bb.capacity - Int(table.o)
+ let startTable = start - Int(_bb.read(def: Int32.self, position: start))
+ let isOkay = _bb.read(def: VOffset.self, position: startTable + Int(field)) != 0
+ assert(isOkay, "Flatbuffers requires the following field")
+ }
+ }
+
+ /// Finished the buffer by adding the file id and then calling finish
+ /// - Parameters:
+ /// - offset: Offset of the table
+ /// - fileId: Takes the fileId
+ /// - prefix: if false it wont add the size of the buffer
+ public func finish(offset: Offset, fileId: String, addPrefix prefix: Bool = false) {
+ let size = MemoryLayout.size
+ preAlign(len: size + (prefix ? size : 0) + FileIdLength, alignment: _minAlignment)
+ assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4")
+ _bb.push(string: fileId, len: 4)
+ finish(offset: offset, addPrefix: prefix)
+ }
+
+ /// Finished the buffer by adding the file id, offset, and prefix to it.
+ /// - Parameters:
+ /// - offset: Offset of the table
+ /// - prefix: if false it wont add the size of the buffer
+ public func finish(offset: Offset, addPrefix prefix: Bool = false) {
+ notNested()
+ let size = MemoryLayout.size
+ preAlign(len: size + (prefix ? size : 0), alignment: _minAlignment)
+ push(element: refer(to: offset.o))
+ if prefix { push(element: _bb.size) }
+ clearOffsets()
+ finished = true
+ }
+
+ /// starttable will let the builder know, that a new object is being serialized.
+ ///
+ /// The function will fatalerror if called while there is another object being serialized
+ /// - Parameter numOfFields: Number of elements to be written to the buffer
+ public func startTable(with numOfFields: Int) -> UOffset {
+ notNested()
+ isNested = true
+ _vtable = [UInt32](repeating: 0, count: numOfFields)
+ return _bb.size
+ }
+
+
+ /// Endtable will let the builder know that the object that's written to it is completed
+ ///
+ /// This would be called after all the elements are serialized, it will add the vtable into the buffer.
+ /// it will fatalError in case the object is called without starttable, or the object has exceeded the limit of
+ /// 2GB,
+ /// - Parameter startOffset:Start point of the object written
+ /// - returns: The root of the table
+ public func endTable(at startOffset: UOffset) -> UOffset {
+ assert(isNested, "Calling endtable without calling starttable")
+ let sizeofVoffset = MemoryLayout.size
+ let vTableOffset = push(element: SOffset(0))
+
+ let tableObjectSize = vTableOffset - startOffset
+ assert(tableObjectSize < 0x10000, "Buffer can't grow beyond 2 Gigabytes")
+
+ var writeIndex = 0
+ for (index,j) in _vtable.lazy.reversed().enumerated() {
+ if j != 0 {
+ writeIndex = _vtable.count - index
+ break
+ }
+ }
+
+ for i in stride(from: writeIndex - 1, to: -1, by: -1) {
+ let off = _vtable[i] == 0 ? 0 : vTableOffset - _vtable[i]
+ _bb.push(value: VOffset(off), len: sizeofVoffset)
+ }
+
+ _bb.push(value: VOffset(tableObjectSize), len: sizeofVoffset)
+ _bb.push(value: (UInt16(writeIndex + 2) * UInt16(sizeofVoffset)), len: sizeofVoffset)
+
+ clearOffsets()
+ let vt_use = _bb.size
+
+ var isAlreadyAdded: Int?
+
+ mainLoop: for table in _vtables {
+ let vt1 = _bb.capacity - Int(table)
+ let vt2 = _bb.writerIndex
+ let len = _bb.read(def: Int16.self, position: vt1)
+ guard len == _bb.read(def: Int16.self, position: vt2) else { break }
+ for i in stride(from: sizeofVoffset, to: Int(len), by: sizeofVoffset) {
+ let vt1ReadValue = _bb.read(def: Int16.self, position: vt1 + i)
+ let vt2ReadValue = _bb.read(def: Int16.self, position: vt2 + i)
+ if vt1ReadValue != vt2ReadValue {
+ break mainLoop
+ }
+ }
+ isAlreadyAdded = Int(table)
+ }
+
+ if let offset = isAlreadyAdded {
+ let vTableOff = Int(vTableOffset)
+ let space = _bb.capacity - vTableOff
+ _bb.write(value: Int32(offset - vTableOff), index: space, direct: true)
+ _bb.resize(_bb.capacity - space)
+ } else {
+ _bb.write(value: Int32(vt_use) - Int32(vTableOffset), index: Int(vTableOffset))
+ _vtables.append(_bb.size)
+ }
+ isNested = false
+ return vTableOffset
+ }
+
+ // MARK: - Builds Buffer
+
+ /// asserts to see if the object is not nested
+ fileprivate func notNested() {
+ assert(!isNested, "Object serialization must not be nested")
+ }
+
+ /// Changes the minimuim alignment of the buffer
+ /// - Parameter size: size of the current alignment
+ fileprivate func minAlignment(size: Int) {
+ if size > _minAlignment {
+ _minAlignment = size
+ }
+ }
+
+ /// Gets the padding for the current element
+ /// - Parameters:
+ /// - bufSize: Current size of the buffer + the offset of the object to be written
+ /// - elementSize: Element size
+ fileprivate func padding(bufSize: UInt32, elementSize: UInt32) -> UInt32 {
+ ((~bufSize) + 1) & (elementSize - 1)
+ }
+
+ /// Prealigns the buffer before writting a new object into the buffer
+ /// - Parameters:
+ /// - len:Length of the object
+ /// - alignment: Alignment type
+ fileprivate func preAlign(len: Int, alignment: Int) {
+ minAlignment(size: alignment)
+ _bb.fill(padding: padding(bufSize: _bb.size + UOffset(len), elementSize: UOffset(alignment)))
+ }
+
+ /// Prealigns the buffer before writting a new object into the buffer
+ /// - Parameters:
+ /// - len: Length of the object
+ /// - type: Type of the object to be written
+ fileprivate func preAlign(len: Int, type: T.Type) {
+ preAlign(len: len, alignment: MemoryLayout.size)
+ }
+
+ /// Refers to an object that's written in the buffer
+ /// - Parameter off: the objects index value
+ fileprivate func refer(to off: UOffset) -> UOffset {
+ let size = MemoryLayout.size
+ preAlign(len: size, alignment: size)
+ return _bb.size - off + UInt32(size)
+ }
+
+ /// Tracks the elements written into the buffer
+ /// - Parameters:
+ /// - offset: The offset of the element witten
+ /// - position: The position of the element
+ fileprivate func track(offset: UOffset, at position: VOffset) {
+ _vtable[Int(position)] = offset
+ }
+
+ // MARK: - Vectors
+
+ /// Starts a vector of length and Element size
+ public func startVector(_ len: Int, elementSize: Int) {
+ notNested()
+ isNested = true
+ preAlign(len: len * elementSize, type: UOffset.self)
+ preAlign(len: len * elementSize, alignment: elementSize)
+ }
+
+ /// Ends the vector of at length
+ ///
+ /// The current function will fatalError if startVector is called before serializing the vector
+ /// - Parameter len: Length of the buffer
+ public func endVector(len: Int) -> UOffset {
+ assert(isNested, "Calling endVector without calling startVector")
+ isNested = false
+ return push(element: Int32(len))
+ }
+
+ /// Creates a vector of type Scalar in the buffer
+ /// - Parameter elements: elements to be written into the buffer
+ /// - returns: Offset of the vector
+ public func createVector(_ elements: [T]) -> Offset {
+ return createVector(elements, size: elements.count)
+ }
+
+ /// Creates a vector of type Scalar in the buffer
+ /// - Parameter elements: Elements to be written into the buffer
+ /// - Parameter size: Count of elements
+ /// - returns: Offset of the vector
+ public func createVector(_ elements: [T], size: Int) -> Offset {
+ let size = size
+ startVector(size, elementSize: MemoryLayout.size)
+ _bb.push(elements: elements)
+ return Offset(offset: endVector(len: size))
+ }
+
+ /// Creates a vector of type Enums in the buffer
+ /// - Parameter elements: elements to be written into the buffer
+ /// - returns: Offset of the vector
+ public func createVector(_ elements: [T]) -> Offset {
+ return createVector(elements, size: elements.count)
+ }
+
+ /// Creates a vector of type Enums in the buffer
+ /// - Parameter elements: Elements to be written into the buffer
+ /// - Parameter size: Count of elements
+ /// - returns: Offset of the vector
+ public func createVector(_ elements: [T], size: Int) -> Offset {
+ let size = size
+ startVector(size, elementSize: T.byteSize)
+ for e in elements.lazy.reversed() {
+ _bb.push(value: e.value, len: T.byteSize)
+ }
+ return Offset(offset: endVector(len: size))
+ }
+
+ /// Creates a vector of type Offsets in the buffer
+ /// - Parameter offsets:Array of offsets of type T
+ /// - returns: Offset of the vector
+ public func createVector(ofOffsets offsets: [Offset]) -> Offset {
+ createVector(ofOffsets: offsets, len: offsets.count)
+ }
+
+ /// Creates a vector of type Offsets in the buffer
+ /// - Parameter elements: Array of offsets of type T
+ /// - Parameter size: Count of elements
+ /// - returns: Offset of the vector
+ public func createVector(ofOffsets offsets: [Offset], len: Int) -> Offset {
+ startVector(len, elementSize: MemoryLayout>.size)
+ for o in offsets.lazy.reversed() {
+ push(element: o)
+ }
+ return Offset(offset: endVector(len: len))
+ }
+
+ /// Creates a vector of Strings
+ /// - Parameter str: a vector of strings that will be written into the buffer
+ /// - returns: Offset of the vector
+ public func createVector(ofStrings str: [String]) -> Offset {
+ var offsets: [Offset] = []
+ for s in str {
+ offsets.append(create(string: s))
+ }
+ return createVector(ofOffsets: offsets)
+ }
+
+ /// Creates a vector of Flatbuffer structs.
+ ///
+ /// The function takes a Type to know what size it is, and alignment
+ /// - Parameters:
+ /// - structs: An array of UnsafeMutableRawPointer
+ /// - type: Type of the struct being written
+ /// - returns: Offset of the vector
+ public func createVector(structs: [UnsafeMutableRawPointer],
+ type: T.Type) -> Offset {
+ startVector(structs.count * T.size, elementSize: T.alignment)
+ for i in structs.lazy.reversed() {
+ create(struct: i, type: T.self)
+ }
+ return Offset(offset: endVector(len: structs.count))
+ }
+
+ // MARK: - Inserting Structs
+
+ /// Writes a Flatbuffer struct into the buffer
+ /// - Parameters:
+ /// - s: Flatbuffer struct
+ /// - type: Type of the element to be serialized
+ /// - returns: Offset of the Object
+ @discardableResult
+ public func create(struct s: UnsafeMutableRawPointer,
+ type: T.Type) -> Offset {
+ let size = T.size
+ preAlign(len: size, alignment: T.alignment)
+ _bb.push(struct: s, size: size)
+ return Offset(offset: _bb.size)
+ }
+
+ /// Adds the offset of a struct into the vTable
+ ///
+ /// The function fatalErrors if we pass an offset that is out of range
+ /// - Parameter o: offset
+ public func add(structOffset o: UOffset) {
+ guard Int(o) < _vtable.count else { fatalError("Out of the table range") }
+ _vtable[Int(o)] = _bb.size
+ }
+
+ // MARK: - Inserting Strings
+
+ /// Insets a string into the buffer using UTF8
+ /// - Parameter str: String to be serialized
+ /// - returns: The strings offset in the buffer
+ public func create(string str: String) -> Offset {
+ let len = str.count
+ notNested()
+ preAlign(len: len + 1, type: UOffset.self)
+ _bb.fill(padding: 1)
+ _bb.push(string: str, len: len)
+ push(element: UOffset(len))
+ return Offset(offset: _bb.size)
+ }
+
+ /// Inserts a shared string to the buffer
+ ///
+ /// The function checks the stringOffsetmap if it's seen a similar string before
+ /// - Parameter str: String to be serialized
+ /// - returns: The strings offset in the buffer
+ public func createShared(string str: String) -> Offset {
+ if let offset = stringOffsetMap[str] {
+ return offset
+ }
+ let offset = create(string: str)
+ stringOffsetMap[str] = offset
+ return offset
+ }
+
+ // MARK: - Inseting offsets
+
+ /// Adds the offset of an object into the buffer
+ /// - Parameters:
+ /// - offset: Offset of another object to be written
+ /// - position: The predefined position of the object
+ public func add(offset: Offset, at position: VOffset) {
+ if offset.isEmpty {
+ track(offset: 0, at: position)
+ return
+ }
+ add(element: refer(to: offset.o), def: 0, at: position)
+ }
+
+ /// Pushes a value of type offset into the buffer
+ /// - Parameter o: Offset
+ /// - returns: Position of the offset
+ @discardableResult
+ public func push(element o: Offset) -> UOffset {
+ push(element: refer(to: o.o))
+ }
+
+ // MARK: - Inserting Scalars to Buffer
+
+ /// Adds a value into the buffer of type Scalar
+ ///
+ /// - Parameters:
+ /// - element: Element to insert
+ /// - def: Default value for that element
+ /// - position: The predefined position of the element
+ public func add(element: T, def: T, at position: VOffset) {
+ if (element == def && !serializeDefaults) {
+ track(offset: 0, at: position)
+ return
+ }
+ let off = push(element: element)
+ track(offset: off, at: position)
+ }
+
+ /// Adds Boolean values into the buffer
+ /// - Parameters:
+ /// - condition: Condition to insert
+ /// - def: Default condition
+ /// - position: The predefined position of the element
+ public func add(condition: Bool, def: Bool, at position: VOffset) {
+ if (condition == def && !serializeDefaults) {
+ track(offset: 0, at: position)
+ return
+ }
+ let off = push(element: Byte(condition ? 1 : 0))
+ track(offset: off, at: position)
+ }
+
+ /// Pushes the values into the buffer
+ /// - Parameter element: Element to insert
+ /// - returns: Postion of the Element
+ @discardableResult
+ public func push(element: T) -> UOffset {
+ preAlign(len: MemoryLayout.size,
+ alignment: MemoryLayout.size)
+ _bb.push(value: element, len: MemoryLayout.size)
+ return _bb.size
+ }
+
+ #if DEBUG
+ /// Used to debug the buffer and the implementation
+ public func debug(str: String = "normal memory: ") {
+ _bb.debugMemory(str: str)
+ }
+ #endif
+}
diff --git a/swift/Sources/FlatBuffers/FlatBufferObject.swift b/swift/Sources/FlatBuffers/FlatBufferObject.swift
new file mode 100644
index 000000000..6e405f5b2
--- /dev/null
+++ b/swift/Sources/FlatBuffers/FlatBufferObject.swift
@@ -0,0 +1,87 @@
+import Foundation
+
+/// FlatbufferObject structures all the Flatbuffers objects
+public protocol FlatBufferObject {
+ init(_ bb: ByteBuffer, o: Int32)
+}
+
+/// Readable is structures all the Flatbuffers structs
+///
+/// Readable is a procotol that each Flatbuffer struct should confirm to since
+/// FlatBufferBuilder would require a Type to both create(struct:) and createVector(structs:) functions
+public protocol Readable: FlatBufferObject {
+ static var size: Int { get }
+ static var alignment: Int { get }
+}
+
+public protocol Enum {
+ associatedtype T: Scalar
+ static var byteSize: Int { get }
+ var value: T { get }
+}
+
+/// Mutable is a protocol that allows us to mutate Scalar values within the buffer
+public protocol Mutable {
+ /// makes Flatbuffer accessed within the Protocol
+ var bb: ByteBuffer { get }
+ /// makes position of the table/struct accessed within the Protocol
+ var postion: Int32 { get }
+}
+
+extension Mutable {
+
+ /// Mutates the memory in the buffer, this is only called from the access function of table and structs
+ /// - Parameters:
+ /// - value: New value to be inserted to the buffer
+ /// - index: index of the Element
+ func mutate(value: T, o: Int32) -> Bool {
+ guard o != 0 else { return false }
+ bb.write(value: value, index: Int(o), direct: true)
+ return true
+ }
+}
+
+extension Mutable where Self == Table {
+
+ /// Mutates a value by calling mutate with respect to the position in the table
+ /// - Parameters:
+ /// - value: New value to be inserted to the buffer
+ /// - index: index of the Element
+ public func mutate(_ value: T, index: Int32) -> Bool {
+ guard index != 0 else { return false }
+ return mutate(value: value, o: index + postion)
+ }
+
+ /// Directly mutates the element by calling mutate
+ ///
+ /// Mutates the Element at index ignoring the current position by calling mutate
+ /// - Parameters:
+ /// - value: New value to be inserted to the buffer
+ /// - index: index of the Element
+ public func directMutate(_ value: T, index: Int32) -> Bool {
+ return mutate(value: value, o: index)
+ }
+}
+
+extension Mutable where Self == Struct {
+
+ /// Mutates a value by calling mutate with respect to the position in the struct
+ /// - Parameters:
+ /// - value: New value to be inserted to the buffer
+ /// - index: index of the Element
+ public func mutate(_ value: T, index: Int32) -> Bool {
+ return mutate(value: value, o: index + postion)
+ }
+
+ /// Directly mutates the element by calling mutate
+ ///
+ /// Mutates the Element at index ignoring the current position by calling mutate
+ /// - Parameters:
+ /// - value: New value to be inserted to the buffer
+ /// - index: index of the Element
+ public func directMutate(_ value: T, index: Int32) -> Bool {
+ return mutate(value: value, o: index)
+ }
+}
+extension Struct: Mutable {}
+extension Table: Mutable {}
diff --git a/swift/Sources/FlatBuffers/FlatBuffersUtils.swift b/swift/Sources/FlatBuffers/FlatBuffersUtils.swift
new file mode 100644
index 000000000..6838f8623
--- /dev/null
+++ b/swift/Sources/FlatBuffers/FlatBuffersUtils.swift
@@ -0,0 +1,16 @@
+import Foundation
+
+public final class FlatBuffersUtils {
+
+ /// Gets the size of the prefix
+ /// - Parameter bb: Flatbuffer object
+ public static func getSizePrefix(bb: ByteBuffer) -> Int32 {
+ return bb.read(def: Int32.self, position: bb.reader)
+ }
+
+ /// Removes the prefix by duplicating the Flatbuffer
+ /// - Parameter bb: Flatbuffer object
+ public static func removeSizePrefix(bb: ByteBuffer) -> ByteBuffer {
+ return bb.duplicate(removing: MemoryLayout.size)
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Int+extension.swift b/swift/Sources/FlatBuffers/Int+extension.swift
new file mode 100644
index 000000000..e52bdab62
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Int+extension.swift
@@ -0,0 +1,31 @@
+import Foundation
+
+extension Int {
+
+ /// Moves the current int into the nearest power of two
+ ///
+ /// This is used since the UnsafeMutableRawPointer will face issues when writing/reading
+ /// if the buffer alignment exceeds that actual size of the buffer
+ var convertToPowerofTwo: Int {
+ guard self > 0 else { return 1 }
+ var n = UOffset(self)
+
+ #if arch(arm) || arch(i386)
+ let max = UInt32(Int.max)
+ #else
+ let max = UInt32.max
+ #endif
+
+ n -= 1
+ n |= n >> 1
+ n |= n >> 2
+ n |= n >> 4
+ n |= n >> 8
+ n |= n >> 16
+ if n != max {
+ n += 1
+ }
+
+ return Int(n)
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Offset.swift b/swift/Sources/FlatBuffers/Offset.swift
new file mode 100644
index 000000000..cdb02278b
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Offset.swift
@@ -0,0 +1,12 @@
+import Foundation
+
+/// Offset object for all the Objects that are written into the buffer
+public struct Offset {
+ /// Offset of the object in the buffer
+ public var o: UOffset
+ /// Returns false if the offset is equal to zero
+ public var isEmpty: Bool { return o == 0 }
+
+ public init(offset: UOffset) { o = offset }
+ public init() { o = 0 }
+}
diff --git a/swift/Sources/FlatBuffers/Struct.swift b/swift/Sources/FlatBuffers/Struct.swift
new file mode 100644
index 000000000..88e3a41a2
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Struct.swift
@@ -0,0 +1,16 @@
+import Foundation
+
+public struct Struct {
+ public private(set) var bb: ByteBuffer
+ public private(set) var postion: Int32
+
+ public init(bb: ByteBuffer, position: Int32 = 0) {
+ self.bb = bb
+ self.postion = position
+ }
+
+ public func readBuffer(of type: T.Type, at o: Int32) -> T {
+ let r = bb.read(def: T.self, position: Int(o + postion))
+ return r
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Table.swift b/swift/Sources/FlatBuffers/Table.swift
new file mode 100644
index 000000000..0f783bfeb
--- /dev/null
+++ b/swift/Sources/FlatBuffers/Table.swift
@@ -0,0 +1,144 @@
+import Foundation
+
+public struct Table {
+ public private(set) var bb: ByteBuffer
+ public private(set) var postion: Int32
+
+ public init(bb: ByteBuffer, position: Int32 = 0) {
+ guard isLitteEndian else {
+ fatalError("Reading/Writing a buffer in big endian machine is not supported on swift")
+ }
+ self.bb = bb
+ self.postion = position
+ }
+
+ public func offset(_ o: Int32) -> Int32 {
+ let vtable = postion - bb.read(def: Int32.self, position: Int(postion))
+ return o < bb.read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read(def: Int16.self, position: Int(vtable + o))) : 0
+ }
+
+ public func indirect(_ o: Int32) -> Int32 { return o + bb.read(def: Int32.self, position: Int(o)) }
+
+ /// String reads from the buffer with respect to position of the current table.
+ /// - Parameter offset: Offset of the string
+ public func string(at offset: Int32) -> String? {
+ return directString(at: offset + postion)
+ }
+
+ /// Direct string reads from the buffer disregarding the position of the table.
+ /// It would be preferable to use string unless the current position of the table is not needed
+ /// - Parameter offset: Offset of the string
+ public func directString(at offset: Int32) -> String? {
+ var offset = offset
+ offset += bb.read(def: Int32.self, position: Int(offset))
+ let count = bb.read(def: Int32.self, position: Int(offset))
+ let position = offset + Int32(MemoryLayout.size)
+ return bb.readString(at: position, count: count)
+ }
+
+ /// Reads from the buffer with respect to the position in the table.
+ /// - Parameters:
+ /// - type: Type of Scalar that needs to be read from the buffer
+ /// - o: Offset of the Element
+ public func readBuffer(of type: T.Type, at o: Int32) -> T {
+ return directRead(of: T.self, offset: o + postion)
+ }
+
+ /// Reads from the buffer disregarding the position of the table.
+ /// It would be used when reading from an
+ /// ```
+ /// let offset = __t.offset(10)
+ /// //Only used when the we already know what is the
+ /// // position in the table since __t.vector(at:)
+ /// // returns the index with respect to the position
+ /// __t.directRead(of: Byte.self,
+ /// offset: __t.vector(at: offset) + index * 1)
+ /// ```
+ /// - Parameters:
+ /// - type: Type of Scalar that needs to be read from the buffer
+ /// - o: Offset of the Element
+ public func directRead(of type: T.Type, offset o: Int32) -> T {
+ let r = bb.read(def: T.self, position: Int(o))
+ return r
+ }
+
+ public func union(_ o: Int32) -> T {
+ let o = o + postion
+ return directUnion(o)
+ }
+
+ public func directUnion(_ o: Int32) -> T {
+ return T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o)))
+ }
+
+ public func getVector(at off: Int32) -> [T]? {
+ let o = offset(off)
+ guard o != 0 else { return nil }
+ return bb.readSlice(index: vector(at: o), count: vector(count: o))
+ }
+
+ /// Vector count gets the count of Elements within the array
+ /// - Parameter o: start offset of the vector
+ /// - returns: Count of elements
+ public func vector(count o: Int32) -> Int32 {
+ var o = o
+ o += postion
+ o += bb.read(def: Int32.self, position: Int(o))
+ return bb.read(def: Int32.self, position: Int(o))
+ }
+
+ /// Vector start index in the buffer
+ /// - Parameter o:start offset of the vector
+ /// - returns: the start index of the vector
+ public func vector(at o: Int32) -> Int32 {
+ var o = o
+ o += postion
+ return o + bb.read(def: Int32.self, position: Int(o)) + 4
+ }
+}
+
+extension Table {
+
+ static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { return o + fbb.read(def: Int32.self, position: Int(o)) }
+
+ static public func offset(_ o: Int32, vOffset: Int32, fbb: ByteBuffer) -> Int32 {
+ let vTable = Int32(fbb.capacity) - o
+ return vTable + Int32(fbb.read(def: Int16.self, position: Int(vTable + vOffset - fbb.read(def: Int32.self, position: Int(vTable)))))
+ }
+
+ static public func compare(_ off1: Int32, _ off2: Int32, fbb: ByteBuffer) -> Int32 {
+ let memorySize = Int32(MemoryLayout.size)
+ let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
+ let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2))
+ let len1 = fbb.read(def: Int32.self, position: Int(_off1))
+ let len2 = fbb.read(def: Int32.self, position: Int(_off2))
+ let startPos1 = _off1 + memorySize
+ let startPos2 = _off2 + memorySize
+ let minValue = min(len1, len2)
+ for i in 0...minValue {
+ let b1 = fbb.read(def: Int8.self, position: Int(i + startPos1))
+ let b2 = fbb.read(def: Int8.self, position: Int(i + startPos2))
+ if b1 != b2 {
+ return Int32(b2 - b1)
+ }
+ }
+ return len1 - len2
+ }
+
+ static public func compare(_ off1: Int32, _ key: [Byte], fbb: ByteBuffer) -> Int32 {
+ let memorySize = Int32(MemoryLayout.size)
+ let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
+ let len1 = fbb.read(def: Int32.self, position: Int(_off1))
+ let len2 = Int32(key.count)
+ let startPos1 = _off1 + memorySize
+ let minValue = min(len1, len2)
+ for i in 0.. Void) -> Benchmark {
+ action()
+ let start = CFAbsoluteTimeGetCurrent()
+ for _ in 0.. String {
+ let separator = "-------------------------------------"
+ var document = "\(separator)\n"
+ document += "\(String(format: "|\t%@\t\t|\t\t%@\t\t|", "Name", "Scores"))\n"
+ document += "\(separator)\n"
+ for i in Benchmarks {
+ document += "\(i.description) \n"
+ document += "\(separator)\n"
+ }
+ return document
+}
+
+@inlinable func create10Strings() {
+ let fb = FlatBufferBuilder(initialSize: 1<<20)
+ for _ in 0..<10_000 {
+ _ = fb.create(string: "foobarbaz")
+ }
+}
+
+@inlinable func create100Strings(str: String) {
+ let fb = FlatBufferBuilder(initialSize: 1<<20)
+ for _ in 0..<10_000 {
+ _ = fb.create(string: str)
+ }
+}
+
+@inlinable func benchmarkFiveHundredAdds() {
+ let fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32)
+ for _ in 0..<500_000 {
+ let off = fb.create(string: "T")
+ let s = fb.startTable(with: 4)
+ fb.add(element: 3.2, def: 0, at: 0)
+ fb.add(element: 4.2, def: 0, at: 1)
+ fb.add(element: 5.2, def: 0, at: 2)
+ fb.add(offset: off, at: 3)
+ _ = fb.endTable(at: s)
+ }
+}
+
+func benchmark(numberOfRuns runs: Int) {
+ var benchmarks: [Benchmark] = []
+ let str = (0...99).map { _ -> String in return "x" }.joined()
+ benchmarks.append(run(name: "500_000", runs: runs, action: benchmarkFiveHundredAdds))
+ benchmarks.append(run(name: "10 str", runs: runs, action: create10Strings))
+ let hundredStr = run(name: "100 str", runs: runs) {
+ create100Strings(str: str)
+ }
+ benchmarks.append(hundredStr)
+ print(createDocument(Benchmarks: benchmarks))
+}
+
+benchmark(numberOfRuns: 20)
diff --git a/tests/FlatBuffers.Test.Swift/Package.swift b/tests/FlatBuffers.Test.Swift/Package.swift
new file mode 100644
index 000000000..bbe5a6ab6
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Package.swift
@@ -0,0 +1,20 @@
+// swift-tools-version:5.1
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "FlatBuffers.Test.Swift",
+ platforms: [
+ .iOS(.v11),
+ .macOS(.v10_14),
+ ],
+ dependencies: [
+ .package(path: "../../swift/")
+ ],
+ targets: [
+ .testTarget(
+ name: "FlatBuffers.Test.SwiftTests",
+ dependencies: ["FlatBuffers"]),
+ ]
+)
diff --git a/tests/FlatBuffers.Test.Swift/SwiftTest.sh b/tests/FlatBuffers.Test.Swift/SwiftTest.sh
new file mode 100644
index 000000000..aa8b5aca7
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/SwiftTest.sh
@@ -0,0 +1,10 @@
+swift_dir=`pwd`
+cd ..
+test_dir=`pwd`
+
+${test_dir}/../flatc --swift --gen-mutable -I ${test_dir}/include_test ${test_dir}/monster_test.fbs ${test_dir}/union_vector/union_vector.fbs
+cd ${test_dir}
+mv *_generated.swift ${swift_dir}/Tests/FlatBuffers.Test.SwiftTests
+cd ${swift_dir}
+swift build --build-tests
+swift test
\ No newline at end of file
diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift
new file mode 100644
index 000000000..486cd1a4b
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift
@@ -0,0 +1,190 @@
+import XCTest
+import Foundation
+@testable import FlatBuffers
+
+typealias Test1 = MyGame.Example.Test
+typealias Monster1 = MyGame.Example.Monster
+typealias Vec3 = MyGame.Example.Vec3
+
+class FlatBuffersMonsterWriterTests: XCTestCase {
+
+ func testData() {
+ let data = Data([48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0])
+ let _data = ByteBuffer(data: data)
+ readMonster(fb: _data)
+ }
+
+ func testReadFromOtherLangagues() {
+ let path = FileManager.default.currentDirectoryPath
+ let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon")
+ guard let data = try? Data(contentsOf: url) else { return }
+ let _data = ByteBuffer(data: data)
+ readMonster(fb: _data)
+ }
+
+ func testCreateMonster() {
+ let bytes = createMonster(withPrefix: false)
+ XCTAssertEqual(bytes.sizedByteArray, [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0])
+ readMonster(fb: bytes.buffer)
+ mutateMonster(fb: bytes.buffer)
+ readMonster(fb: bytes.buffer)
+ }
+
+ func testCreateMonsterResizedBuffer() {
+ let bytes = createMonster(withPrefix: false)
+ XCTAssertEqual(bytes.sizedByteArray, [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0])
+ readMonster(fb: ByteBuffer(data: bytes.data))
+ }
+
+ func testCreateMonsterPrefixed() {
+ let bytes = createMonster(withPrefix: true)
+ XCTAssertEqual(bytes.sizedByteArray, [44, 1, 0, 0, 44, 0, 0, 0, 77, 79, 78, 83, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0])
+
+ let newBuf = FlatBuffersUtils.removeSizePrefix(bb: bytes.buffer)
+ readMonster(fb: newBuf)
+ }
+
+ func createMonster(withPrefix prefix: Bool) -> FlatBufferBuilder {
+ let fbb = FlatBufferBuilder(initialSize: 1)
+ let names = [fbb.create(string: "Frodo"), fbb.create(string: "Barney"), fbb.create(string: "Wilma")]
+ var offsets: [Offset] = []
+ let start1 = Monster1.startMonster(fbb)
+ Monster1.add(name: names[0], fbb)
+ offsets.append(Monster1.endMonster(fbb, start: start1))
+ let start2 = Monster1.startMonster(fbb)
+ Monster1.add(name: names[1], fbb)
+ offsets.append(Monster1.endMonster(fbb, start: start2))
+ let start3 = Monster1.startMonster(fbb)
+ Monster1.add(name: names[2], fbb)
+ offsets.append(Monster1.endMonster(fbb, start: start3))
+
+ let sortedArray = Monster1.sortVectorOfMonster(offsets: offsets, fbb)
+
+ let str = fbb.create(string: "MyMonster")
+ let test1 = fbb.create(string: "test1")
+ let test2 = fbb.create(string: "test2")
+ let _inv: [Byte] = [0, 1, 2, 3, 4]
+ let inv = fbb.createVector(_inv)
+
+ let fred = fbb.create(string: "Fred")
+ let mon1Start = Monster1.startMonster(fbb)
+ Monster1.add(name: fred, fbb)
+ let mon2 = Monster1.endMonster(fbb, start: mon1Start)
+ let test4 = fbb.createVector(structs: [MyGame.Example.createTest(a: 30, b: 40),
+ MyGame.Example.createTest(a: 10, b: 20)],
+ type: Test1.self)
+
+ let stringTestVector = fbb.createVector(ofOffsets: [test1, test2])
+
+ let mStart = Monster1.startMonster(fbb)
+ let posOffset = fbb.create(struct: MyGame.Example.createVec3(x: 1, y: 2, z: 3, test1: 3, test2: .green, test3a: 5, test3b: 6), type: Vec3.self)
+ Monster1.add(pos: posOffset, fbb)
+ Monster1.add(hp: 80, fbb)
+ Monster1.add(name: str, fbb)
+ Monster1.addVectorOf(inventory: inv, fbb)
+ Monster1.add(testType: .monster, fbb)
+ Monster1.add(test: mon2, fbb)
+ Monster1.addVectorOf(test4: test4, fbb)
+ Monster1.addVectorOf(testarrayofstring: stringTestVector, fbb)
+ Monster1.add(testbool: true, fbb)
+ Monster1.addVectorOf(testarrayoftables: sortedArray, fbb)
+ let end = Monster1.endMonster(fbb, start: mStart)
+ Monster1.finish(fbb, end: end, prefix: prefix)
+ return fbb
+ }
+
+ func mutateMonster(fb: ByteBuffer) {
+ let monster = Monster1.getRootAsMonster(bb: fb)
+ XCTAssertFalse(monster.mutate(mana: 10))
+ XCTAssertEqual(monster.testarrayoftables(at: 0)?.name, "Barney")
+ XCTAssertEqual(monster.testarrayoftables(at: 1)?.name, "Frodo")
+ XCTAssertEqual(monster.testarrayoftables(at: 2)?.name, "Wilma")
+
+ // Example of searching for a table by the key
+ XCTAssertNotNil(monster.testarrayoftablesBy(key: "Frodo"))
+ XCTAssertNotNil(monster.testarrayoftablesBy(key: "Barney"))
+ XCTAssertNotNil(monster.testarrayoftablesBy(key: "Wilma"))
+
+ XCTAssertEqual(monster.testType, .monster)
+
+ XCTAssertEqual(monster.mutate(inventory: 1, at: 0), true)
+ XCTAssertEqual(monster.mutate(inventory: 2, at: 1), true)
+ XCTAssertEqual(monster.mutate(inventory: 3, at: 2), true)
+ XCTAssertEqual(monster.mutate(inventory: 4, at: 3), true)
+ XCTAssertEqual(monster.mutate(inventory: 5, at: 4), true)
+
+ for i in 0.. UnsafeMutableRawPointer{
+ let memory = UnsafeMutableRawPointer.allocate(byteCount: Vec.size, alignment: Vec.alignment)
+ memory.initializeMemory(as: UInt8.self, repeating: 0, count: Vec.size)
+ memory.storeBytes(of: x, toByteOffset: 0, as: Float32.self)
+ memory.storeBytes(of: y, toByteOffset: 4, as: Float32.self)
+ memory.storeBytes(of: z, toByteOffset: 8, as: Float32.self)
+ return memory
+}
+
+struct Vec: Readable {
+ static var size = 12
+ static var alignment = 4
+ private var __p: Struct
+ init(_ fb: ByteBuffer, o: Int32) { __p = Struct(bb: fb, position: o) }
+ var x: Float32 { return __p.readBuffer(of: Float32.self, at: 0)}
+ var y: Float32 { return __p.readBuffer(of: Float32.self, at: 4)}
+ var z: Float32 { return __p.readBuffer(of: Float32.self, at: 8)}
+}
+
+struct VPointerVec {
+
+ private var __t: Table
+
+ private init(_ t: Table) {
+ __t = t
+ }
+
+ var vec: Vec? { let o = __t.offset(4); return o == 0 ? nil : Vec(__t.bb, o: o + __t.postion) }
+
+ @inlinable static func getRootAsCountry(_ bb: ByteBuffer) -> VPointerVec {
+ return VPointerVec(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0))))
+ }
+
+ static func startVPointer(b: FlatBufferBuilder) -> UOffset { b.startTable(with: 1) }
+ static func finish(b: FlatBufferBuilder, s: UOffset) -> Offset { return Offset(offset: b.endTable(at: s)) }
+
+ static func createVPointer(b: FlatBufferBuilder, o: Offset) -> Offset {
+ let s = VPointerVec.startVPointer(b: b)
+ b.add(structOffset: 0)
+ return VPointerVec.finish(b: b, s: s)
+ }
+}
+
+enum Color: UInt32 { case red = 0, green = 1, blue = 2 }
+
+private let VPointerVectorVecOffsets: (color: VOffset, vector: VOffset) = (0, 1)
+
+struct VPointerVectorVec {
+
+ static func startVPointer(b: FlatBufferBuilder) -> UOffset { b.startTable(with: 2) }
+
+ static func addVector(b: FlatBufferBuilder, v: Offset) { b.add(offset: v, at: VPointerVectorVecOffsets.vector) }
+
+ static func addColor(b: FlatBufferBuilder, color: Color) { b.add(element: color.rawValue, def: 1, at: VPointerVectorVecOffsets.color) }
+
+ static func finish(b: FlatBufferBuilder, s: UOffset) -> Offset { return Offset(offset: b.endTable(at: s)) }
+
+ static func createVPointer(b: FlatBufferBuilder, color: Color = .green, v: Offset) -> Offset {
+ let s = VPointerVectorVec.startVPointer(b: b)
+ VPointerVectorVec.addVector(b: b, v: v)
+ VPointerVectorVec.addColor(b: b, color: color)
+ return VPointerVectorVec.finish(b: b, s: s)
+ }
+}
+
+enum Color2: Int32 { case red = 0, green = 1, blue = 2 }
+enum Test: Byte { case none = 0, vec = 1 }
+
+func createVec2(x: Float32 = 0, y: Float32 = 0, z: Float32 = 0, color: Color2) -> UnsafeMutableRawPointer {
+ let memory = UnsafeMutableRawPointer.allocate(byteCount: Vec2.size, alignment: Vec2.alignment)
+ memory.initializeMemory(as: UInt8.self, repeating: 0, count: Vec2.size)
+ memory.storeBytes(of: x, toByteOffset: 0, as: Float32.self)
+ memory.storeBytes(of: y, toByteOffset: 4, as: Float32.self)
+ memory.storeBytes(of: z, toByteOffset: 8, as: Float32.self)
+ return memory
+}
+
+struct Vec2: Readable {
+ static var size = 13
+ static var alignment = 4
+ private var __p: Struct
+
+ init(_ fb: ByteBuffer, o: Int32) { __p = Struct(bb: fb, position: o) }
+ var c: Color2 { return Color2(rawValue: __p.readBuffer(of: Int32.self, at: 12)) ?? .red }
+ var x: Float32 { return __p.readBuffer(of: Float32.self, at: 0)}
+ var y: Float32 { return __p.readBuffer(of: Float32.self, at: 4)}
+ var z: Float32 { return __p.readBuffer(of: Float32.self, at: 8)}
+}
+
+struct VPointerVec2 {
+
+ private var __t: Table
+
+ private init(_ t: Table) {
+ __t = t
+ }
+
+ var vec: Vec2? { let o = __t.offset(4); return o == 0 ? nil : Vec2( __t.bb, o: o + __t.postion) }
+ var UType: Test? { let o = __t.offset(6); return o == 0 ? Test.none : Test(rawValue: __t.readBuffer(of: Byte.self, at: o)) }
+
+ @inlinable static func getRootAsCountry(_ bb: ByteBuffer) -> VPointerVec2 {
+ return VPointerVec2(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0))))
+ }
+
+ static func startVPointer(b: FlatBufferBuilder) -> UOffset { b.startTable(with: 3) }
+ static func finish(b: FlatBufferBuilder, s: UOffset) -> Offset { return Offset(offset: b.endTable(at: s)) }
+
+ static func createVPointer(b: FlatBufferBuilder, o: Offset, type: Test) -> Offset {
+ let s = VPointerVec2.startVPointer(b: b)
+ b.add(structOffset: 0)
+ b.add(element: type.rawValue, def: Test.none.rawValue, at: 1)
+ b.add(offset: o, at: 2)
+ return VPointerVec2.finish(b: b, s: s)
+ }
+}
diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift
new file mode 100644
index 000000000..e8e737e2f
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift
@@ -0,0 +1,118 @@
+import XCTest
+@testable import FlatBuffers
+
+final class FlatBuffersTests: XCTestCase {
+
+ let country = "Norway"
+
+ func testEndian() { XCTAssertEqual(isLitteEndian, true) }
+
+ func testOffset() {
+ let o = Offset()
+ let b = Offset(offset: 1)
+ XCTAssertEqual(o.isEmpty, true)
+ XCTAssertEqual(b.isEmpty, false)
+ }
+
+ func testCreateString() {
+ let helloWorld = "Hello, world!"
+ let b = FlatBufferBuilder(initialSize: 16)
+ XCTAssertEqual(b.create(string: country).o, 12)
+ XCTAssertEqual(b.create(string: helloWorld).o, 32)
+ b.clear()
+ XCTAssertEqual(b.create(string: helloWorld).o, 20)
+ XCTAssertEqual(b.create(string: country).o, 32)
+ }
+
+ func testStartTable() {
+ let b = FlatBufferBuilder(initialSize: 16)
+ XCTAssertNoThrow(b.startTable(with: 0))
+ b.clear()
+ XCTAssertEqual(b.create(string: country).o, 12)
+ XCTAssertEqual(b.startTable(with: 0), 12)
+ }
+
+ func testCreate() {
+ var b = FlatBufferBuilder(initialSize: 16)
+ _ = Country.createCountry(builder: &b, name: country, log: 200, lan: 100)
+ let v: [UInt8] = [10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 12, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]
+ XCTAssertEqual(b.sizedByteArray, v)
+ }
+
+ func testCreateFinish() {
+ var b = FlatBufferBuilder(initialSize: 16)
+ let countryOff = Country.createCountry(builder: &b, name: country, log: 200, lan: 100)
+ b.finish(offset: countryOff)
+ let v: [UInt8] = [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 12, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]
+ XCTAssertEqual(b.sizedByteArray, v)
+ }
+
+ func testCreateFinishWithPrefix() {
+ var b = FlatBufferBuilder(initialSize: 16)
+ let countryOff = Country.createCountry(builder: &b, name: country, log: 200, lan: 100)
+ b.finish(offset: countryOff, addPrefix: true)
+ let v: [UInt8] = [44, 0, 0, 0, 16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 12, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]
+ XCTAssertEqual(b.sizedByteArray, v)
+ }
+
+ func testReadCountry() {
+ let v: [UInt8] = [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 12, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]
+ let buffer = ByteBuffer(bytes: v)
+ let c = Country.getRootAsCountry(buffer)
+ XCTAssertEqual(c.lan, 100)
+ XCTAssertEqual(c.log, 200)
+ XCTAssertEqual(c.nameVector, [78, 111, 114, 119, 97, 121])
+ XCTAssertEqual(c.name, country)
+ }
+}
+
+class Country {
+
+ static let offsets: (name: VOffset, lan: VOffset, lng: VOffset) = (0, 1, 2)
+ private var __t: Table
+
+ private init(_ t: Table) {
+ __t = t
+ }
+
+ var lan: Int32 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(of: Int32.self, at: o) }
+ var log: Int32 { let o = __t.offset(8); return o == 0 ? 0 : __t.readBuffer(of: Int32.self, at: o) }
+ var nameVector: [UInt8]? { return __t.getVector(at: 4) }
+ var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
+
+ @inlinable static func getRootAsCountry(_ bb: ByteBuffer) -> Country {
+ return Country(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0))))
+ }
+
+ @inlinable static func createCountry(builder: inout FlatBufferBuilder, name: String, log: Int32, lan: Int32) -> Offset {
+ return createCountry(builder: &builder, offset: builder.create(string: name), log: log, lan: lan)
+ }
+
+ @inlinable static func createCountry(builder: inout FlatBufferBuilder, offset: Offset, log: Int32, lan: Int32) -> Offset {
+ let _start = builder.startTable(with: 3)
+ Country.add(builder: &builder, lng: log)
+ Country.add(builder: &builder, lan: lan)
+ Country.add(builder: &builder, name: offset)
+ return Country.end(builder: &builder, startOffset: _start)
+ }
+
+ @inlinable static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset {
+ return Offset(offset: builder.endTable(at: startOffset))
+ }
+
+ @inlinable static func add(builder: inout FlatBufferBuilder, name: String) {
+ add(builder: &builder, name: builder.create(string: name))
+ }
+
+ @inlinable static func add(builder: inout FlatBufferBuilder, name: Offset) {
+ builder.add(offset: name, at: Country.offsets.name)
+ }
+
+ @inlinable static func add(builder: inout FlatBufferBuilder, lan: Int32) {
+ builder.add(element: lan, def: 0, at: Country.offsets.lan)
+ }
+
+ @inlinable static func add(builder: inout FlatBufferBuilder, lng: Int32) {
+ builder.add(element: lng, def: 0, at: Country.offsets.lng)
+ }
+}
diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift
new file mode 100644
index 000000000..d65242934
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift
@@ -0,0 +1,229 @@
+import XCTest
+@testable import FlatBuffers
+
+final class FlatBuffersUnionTests: XCTestCase {
+
+ func testCreateMonstor() {
+
+ var b = FlatBufferBuilder(initialSize: 20)
+ let dmg: Int16 = 5
+ let str = "Axe"
+ let axe = b.create(string: str)
+ let weapon = Weapon.createWeapon(builder: &b, offset: axe, dmg: dmg)
+ let weapons = b.createVector(ofOffsets: [weapon])
+ let root = Monster.createMonster(builder: &b,
+ offset: weapons,
+ equipment: .Weapon,
+ equippedOffset: weapon.o)
+ b.finish(offset: root)
+ let buffer = b.sizedByteArray
+ XCTAssertEqual(buffer, [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 8, 0, 7, 0, 12, 0, 10, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 20, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 5, 0, 4, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0])
+ let monster = Monster.getRootAsMonster(bb: ByteBuffer(bytes: buffer))
+ XCTAssertEqual(monster.weapon(at: 0)?.dmg, dmg)
+ XCTAssertEqual(monster.weapon(at: 0)?.name, str)
+ XCTAssertEqual(monster.weapon(at: 0)?.nameVector, [65, 120, 101])
+ let p: Weapon? = monster.equiped()
+ XCTAssertEqual(p?.dmg, dmg)
+ XCTAssertEqual(p?.name, str)
+ XCTAssertEqual(p?.nameVector, [65, 120, 101])
+ }
+
+ func testEndTableFinish() {
+ var builder = FlatBufferBuilder(initialSize: 20)
+ let sword = builder.create(string: "Sword")
+ let axe = builder.create(string: "Axe")
+ let weaponOne = Weapon.createWeapon(builder: &builder, offset: sword, dmg: 3)
+ let weaponTwo = Weapon.createWeapon(builder: &builder, offset: axe, dmg: 5)
+ let name = builder.create(string: "Orc")
+ let inventory: [UInt8] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ let inv = builder.createVector(inventory, size: 10)
+ let weapons = builder.createVector(ofOffsets: [weaponOne, weaponTwo])
+ var vecArray: [UnsafeMutableRawPointer] = []
+ vecArray.append(createVecWrite(x: 4.0, y: 5.0, z: 6.0))
+ vecArray.append(createVecWrite(x: 1.0, y: 2.0, z: 3.0))
+ let path = builder.createVector(structs: vecArray, type: Vec.self)
+ let orc = FinalMonster.createMonster(builder: &builder,
+ position: builder.create(struct: createVecWrite(x: 1.0, y: 2.0, z: 3.0), type: Vec.self),
+ hp: 300,
+ name: name,
+ inventory: inv,
+ color: .red,
+ weapons: weapons,
+ equipment: .Weapon,
+ equippedOffset: weaponTwo,
+ path: path)
+ builder.finish(offset: orc)
+ XCTAssertEqual(builder.sizedByteArray, [32, 0, 0, 0, 0, 0, 26, 0, 36, 0, 36, 0, 0, 0, 34, 0, 28, 0, 0, 0, 24, 0, 23, 0, 16, 0, 15, 0, 8, 0, 4, 0, 26, 0, 0, 0, 44, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 76, 0, 0, 0, 0, 0, 44, 1, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 52, 0, 0, 0, 28, 0, 0, 0, 10, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 3, 0, 0, 0, 79, 114, 99, 0, 244, 255, 255, 255, 0, 0, 5, 0, 24, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 3, 0, 12, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0, 5, 0, 0, 0, 83, 119, 111, 114, 100, 0, 0, 0])
+ }
+
+ func testEnumVector() {
+ let vectorOfEnums: [ColorsNameSpace.RGB] = [.blue, .green]
+
+ let builder = FlatBufferBuilder(initialSize: 1)
+ let off = builder.createVector(vectorOfEnums)
+ let start = ColorsNameSpace.Monster.startMonster(builder)
+ ColorsNameSpace.Monster.add(colors: off, builder)
+ let end = ColorsNameSpace.Monster.endMonster(builder, start: start)
+ builder.finish(offset: end)
+ XCTAssertEqual(builder.sizedByteArray, [12, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0])
+ let monster = ColorsNameSpace.Monster.getRootAsMonster(bb: builder.buffer)
+ XCTAssertEqual(monster.colorsCount, 2)
+ XCTAssertEqual(monster.colors(at: 0), .blue)
+ XCTAssertEqual(monster.colors(at: 1), .green)
+ }
+
+ func testUnionVector() {
+ let fb = FlatBufferBuilder()
+
+ 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]
+ let characters = [
+ fb.create(struct: createBookReader(booksRead: 7), type: BookReader.self),
+ attack,
+ fb.create(struct: createBookReader(booksRead: 2), type: BookReader.self),
+ ]
+ let types = fb.createVector(characterType)
+ let characterVector = fb.createVector(ofOffsets: characters)
+
+ let movieStart = Movie.startMovie(fb)
+ Movie.addVectorOf(charactersType: types, fb)
+ Movie.addVectorOf(characters: characterVector, fb)
+ let end = Movie.endMovie(fb, start: movieStart)
+ Movie.finish(fb, end: end)
+
+ let movie = Movie.getRootAsMovie(bb: fb.buffer)
+ XCTAssertEqual(movie.charactersTypeCount, Int32(characterType.count))
+ XCTAssertEqual(movie.charactersCount, Int32(characters.count))
+
+ for i in 0...size }
+ var value: Int32 { return self.rawValue }
+ case red = 0, green = 1, blue = 2
+}
+
+struct Monster: FlatBufferObject {
+ private var _accessor: Table
+ static func getRootAsMonster(bb: ByteBuffer) -> Monster { return Monster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ init(_ t: Table) { _accessor = t }
+ init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var colorsCount: Int32 { let o = _accessor.offset(4); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func colors(at index: Int32) -> ColorsNameSpace.RGB? { let o = _accessor.offset(4); return o == 0 ? ColorsNameSpace.RGB(rawValue: 0)! : ColorsNameSpace.RGB(rawValue: _accessor.directRead(of: Int32.self, offset: _accessor.vector(at: o) + index * 4)) }
+ static func startMonster(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
+ static func add(colors: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: colors, at: 0) }
+ static func endMonster(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+}
+
+
+enum Equipment: Byte { case none, Weapon }
+
+enum Color3: Int8 { case red = 0, green, blue }
+
+struct FinalMonster {
+
+ @inlinable static func createMonster(builder: inout FlatBufferBuilder,
+ position: Offset,
+ hp: Int16,
+ name: Offset,
+ inventory: Offset,
+ color: Color3,
+ weapons: Offset,
+ equipment: Equipment = .none,
+ equippedOffset: Offset,
+ path: Offset) -> Offset {
+ let start = builder.startTable(with: 11)
+ builder.add(structOffset: 0)
+ builder.add(element: hp, def: 100, at: 2)
+ builder.add(offset: name, at: 3)
+ builder.add(offset: inventory, at: 5)
+ builder.add(element: color.rawValue, def: Color3.green.rawValue, at: 6)
+ builder.add(offset: weapons, at: 7)
+ builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 8)
+ builder.add(offset: equippedOffset, at: 9)
+ builder.add(offset: path, at: 10)
+ return Offset(offset: builder.endTable(at: start))
+ }
+}
+
+struct Monster {
+
+ private var __t: Table
+
+ init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o) }
+ init(_ t: Table) { __t = t }
+
+ func weapon(at index: Int32) -> Weapon? { let o = __t.offset(4); return o == 0 ? nil : Weapon.assign(__t.indirect(__t.vector(at: o) + (index * 4)), __t.bb) }
+
+ func equiped() -> T? {
+ let o = __t.offset(8); return o == 0 ? nil : __t.union(o)
+ }
+
+ static func getRootAsMonster(bb: ByteBuffer) -> Monster {
+ return Monster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0))))
+ }
+
+ @inlinable static func createMonster(builder: inout FlatBufferBuilder,
+ offset: Offset,
+ equipment: Equipment = .none,
+ equippedOffset: UOffset) -> Offset {
+ let start = builder.startTable(with: 3)
+ builder.add(element: equippedOffset, def: 0, at: 2)
+ builder.add(offset: offset, at: 0)
+ builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 1)
+ return Offset(offset: builder.endTable(at: start))
+ }
+}
+
+
+struct Weapon: FlatBufferObject {
+
+ static let offsets: (name: VOffset, dmg: VOffset) = (0, 1)
+ private var __t: Table
+
+ init(_ t: Table) { __t = t }
+ init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o)}
+
+ var dmg: Int16 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(of: Int16.self, at: o) }
+ var nameVector: [UInt8]? { return __t.getVector(at: 4) }
+ var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
+
+ static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { return Weapon(Table(bb: bb, position: i)) }
+
+ @inlinable static func createWeapon(builder: inout FlatBufferBuilder, offset: Offset, dmg: Int16) -> Offset {
+ let _start = builder.startTable(with: 2)
+ Weapon.add(builder: &builder, name: offset)
+ Weapon.add(builder: &builder, dmg: dmg)
+ return Weapon.end(builder: &builder, startOffset: _start)
+ }
+
+ @inlinable static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset {
+ return Offset(offset: builder.endTable(at: startOffset))
+ }
+
+ @inlinable static func add(builder: inout FlatBufferBuilder, name: Offset) {
+ builder.add(offset: name, at: Weapon.offsets.name)
+ }
+
+ @inlinable static func add(builder: inout FlatBufferBuilder, dmg: Int16) {
+ builder.add(element: dmg, def: 0, at: Weapon.offsets.dmg)
+ }
+}
diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift
new file mode 100644
index 000000000..5e6301ffe
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift
@@ -0,0 +1,108 @@
+import XCTest
+@testable import FlatBuffers
+
+final class FlatBuffersVectors: XCTestCase {
+
+ func testCreatingTwoCountries() {
+ let norway = "Norway"
+ let denmark = "Denmark"
+ var b = FlatBufferBuilder(initialSize: 20)
+ let noStr = b.create(string: norway)
+ let deStr = b.create(string: denmark)
+ let n = Country.createCountry(builder: &b, offset: noStr, log: 888, lan: 700)
+ let d = Country.createCountry(builder: &b, offset: deStr, log: 200, lan: 100)
+ let vector = [n, d]
+ let vectorOffset = b.createVector(ofOffsets: vector)
+ b.finish(offset: vectorOffset)
+ XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 2, 0, 0, 0, 48, 0, 0, 0, 16, 0, 0, 0, 0, 0, 10, 0, 18, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 40, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 24, 0, 0, 0, 188, 2, 0, 0, 120, 3, 0, 0, 7, 0, 0, 0, 68, 101, 110, 109, 97, 114, 107, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0])
+ }
+
+ func testCreateIntArray() {
+ let numbers: [Int32] = [1, 2, 3, 4, 5]
+ let b = FlatBufferBuilder(initialSize: 20)
+ let o = b.createVector(numbers, size: numbers.count)
+ b.finish(offset: o)
+ XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0])
+ }
+
+ func testCreateVectorOfStrings() {
+ let strs = ["Denmark", "Norway"]
+ let b = FlatBufferBuilder(initialSize: 20)
+ let o = b.createVector(ofStrings: strs)
+ b.finish(offset: o)
+ XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 2, 0, 0, 0, 20, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0, 7, 0, 0, 0, 68, 101, 110, 109, 97, 114, 107, 0])
+ }
+ func testCreateSharedStringVector() {
+ let norway = "Norway"
+ let denmark = "Denmark"
+ let b = FlatBufferBuilder(initialSize: 20)
+ let noStr = b.createShared(string: norway)
+ let deStr = b.createShared(string: denmark)
+ let _noStr = b.createShared(string: norway)
+ let _deStr = b.createShared(string: denmark)
+ let v = [noStr, deStr, _noStr, _deStr]
+ let end = b.createVector(ofOffsets: v)
+ b.finish(offset: end)
+ XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 4, 0, 0, 0, 28, 0, 0, 0, 12, 0, 0, 0, 20, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 68, 101, 110, 109, 97, 114, 107, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0])
+ }
+
+ func testReadInt32Array() {
+ let data: [Int32] = [1, 2, 3, 4, 5]
+ let b = FlatBufferBuilder(initialSize: 20)
+ let v = Numbers.createNumbersVector(b: b, array: data)
+ let end = Numbers.createNumbers(b: b, o: v)
+ b.finish(offset: end)
+ let number = Numbers.getRootAsNumbers(ByteBuffer(bytes: b.sizedByteArray))
+ XCTAssertEqual(number.vArrayInt32, [1, 2, 3, 4, 5])
+ }
+
+ func testReadDoubleArray() {
+ let data: [Double] = [1, 2, 3, 4, 5]
+ let b = FlatBufferBuilder(initialSize: 20)
+ let v = Numbers.createNumbersVector(b: b, array: data)
+ let end = Numbers.createNumbers(b: b, o: v)
+ b.finish(offset: end)
+ let number = Numbers.getRootAsNumbers(ByteBuffer(bytes: b.sizedByteArray))
+ XCTAssertEqual(number.vArrayDouble, [1, 2, 3, 4, 5])
+ }
+}
+
+struct Numbers {
+
+ private var __t: Table
+
+ private init(_ t: Table) {
+ __t = t
+ }
+
+ @inlinable static func getRootAsNumbers(_ bb: ByteBuffer) -> Numbers {
+ return Numbers(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0))))
+ }
+
+ var vArrayInt: [Int]? { return __t.getVector(at: 4) }
+ var vArrayInt32: [Int32]? { return __t.getVector(at: 4) }
+ var vArrayDouble: [Double]? { return __t.getVector(at: 4) }
+ var vArrayFloat: [Float32]? { return __t.getVector(at: 4) }
+
+ static func createNumbersVector(b: FlatBufferBuilder, array: [Int]) -> Offset {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbersVector(b: FlatBufferBuilder, array: [Int32]) -> Offset {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbersVector(b: FlatBufferBuilder, array: [Double]) -> Offset {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbersVector(b: FlatBufferBuilder, array: [Float32]) -> Offset {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbers(b: FlatBufferBuilder, o: Offset) -> Offset {
+ let start = b.startTable(with: 1)
+ b.add(offset: o, at: 0)
+ return Offset(offset: b.endTable(at: start))
+ }
+}
diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift
new file mode 100644
index 000000000..c044c5ca8
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift
@@ -0,0 +1,76 @@
+import XCTest
+@testable import FlatBuffers
+
+final class FlatBuffersDoubleTests: XCTestCase {
+
+ let country = "Norway"
+
+ func testCreateCountry() {
+ var b = FlatBufferBuilder(initialSize: 16)
+ _ = CountryDouble.createCountry(builder: &b, name: country, log: 200, lan: 100)
+ let v: [UInt8] = [10, 0, 28, 0, 4, 0, 8, 0, 16, 0, 10, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 64, 0, 0, 0, 0, 0, 0, 105, 64, 0, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]
+ XCTAssertEqual(b.sizedByteArray, v)
+ }
+
+ func testCreateFinish() {
+ var b = FlatBufferBuilder(initialSize: 16)
+ let countryOff = CountryDouble.createCountry(builder: &b, name: country, log: 200, lan: 100)
+ b.finish(offset: countryOff)
+ let v: [UInt8] = [16, 0, 0, 0, 0, 0, 10, 0, 28, 0, 4, 0, 8, 0, 16, 0, 10, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 64, 0, 0, 0, 0, 0, 0, 105, 64, 0, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]
+ XCTAssertEqual(b.sizedByteArray, v)
+ }
+
+ func testCreateFinishWithPrefix() {
+ var b = FlatBufferBuilder(initialSize: 16)
+ let countryOff = CountryDouble.createCountry(builder: &b, name: country, log: 200, lan: 100)
+ b.finish(offset: countryOff, addPrefix: true)
+ let v: [UInt8] = [60, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 28, 0, 4, 0, 8, 0, 16, 0, 10, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 64, 0, 0, 0, 0, 0, 0, 105, 64, 0, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]
+ XCTAssertEqual(b.sizedByteArray, v)
+ }
+}
+
+class CountryDouble {
+
+ static let offsets: (name: VOffset, lan: VOffset, lng: VOffset) = (4,6,8)
+
+ private var table: Table
+
+ private init(table t: Table) { table = t }
+
+ static func getRootAsCountry(_ bb: ByteBuffer) -> CountryDouble {
+ let pos = bb.read(def: Int32.self, position: Int(bb.size))
+ return CountryDouble(table: Table(bb: bb, position: Int32(pos)))
+ }
+
+ static func createCountry(builder: inout FlatBufferBuilder, name: String, log: Double, lan: Double) -> Offset {
+ return createCountry(builder: &builder, offset: builder.create(string: name), log: log, lan: lan)
+ }
+
+ static func createCountry(builder: inout FlatBufferBuilder, offset: Offset, log: Double, lan: Double) -> Offset {
+ let _start = builder.startTable(with: 3)
+ CountryDouble.add(builder: &builder, lng: log)
+ CountryDouble.add(builder: &builder, lan: lan)
+ CountryDouble.add(builder: &builder, name: offset)
+ return CountryDouble.end(builder: &builder, startOffset: _start)
+ }
+
+ static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset {
+ return Offset(offset: builder.endTable(at: startOffset))
+ }
+
+ static func add(builder: inout FlatBufferBuilder, name: String) {
+ add(builder: &builder, name: builder.create(string: name))
+ }
+
+ static func add(builder: inout FlatBufferBuilder, name: Offset) {
+ builder.add(offset: name, at: Country.offsets.name)
+ }
+
+ static func add(builder: inout FlatBufferBuilder, lan: Double) {
+ builder.add(element: lan, def: 0, at: Country.offsets.lan)
+ }
+
+ static func add(builder: inout FlatBufferBuilder, lng: Double) {
+ builder.add(element: lng, def: 0, at: Country.offsets.lng)
+ }
+}
diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift
new file mode 100644
index 000000000..d53a7a6c8
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift
@@ -0,0 +1,94 @@
+#if !canImport(ObjectiveC)
+import XCTest
+
+extension FlatBuffersDoubleTests {
+ // DO NOT MODIFY: This is autogenerated, use:
+ // `swift test --generate-linuxmain`
+ // to regenerate.
+ static let __allTests__FlatBuffersDoubleTests = [
+ ("testCreateCountry", testCreateCountry),
+ ("testCreateFinish", testCreateFinish),
+ ("testCreateFinishWithPrefix", testCreateFinishWithPrefix),
+ ]
+}
+
+extension FlatBuffersMonsterWriterTests {
+ // DO NOT MODIFY: This is autogenerated, use:
+ // `swift test --generate-linuxmain`
+ // to regenerate.
+ static let __allTests__FlatBuffersMonsterWriterTests = [
+ ("testCreateMonster", testCreateMonster),
+ ("testCreateMonsterPrefixed", testCreateMonsterPrefixed),
+ ("testCreateMonsterResizedBuffer", testCreateMonsterResizedBuffer),
+ ("testData", testData),
+ ("testReadFromOtherLangagues", testReadFromOtherLangagues),
+ ]
+}
+
+extension FlatBuffersStructsTests {
+ // DO NOT MODIFY: This is autogenerated, use:
+ // `swift test --generate-linuxmain`
+ // to regenerate.
+ static let __allTests__FlatBuffersStructsTests = [
+ ("testCreatingEnums", testCreatingEnums),
+ ("testCreatingStruct", testCreatingStruct),
+ ("testCreatingVectorStruct", testCreatingVectorStruct),
+ ("testCreatingVectorStructWithForcedDefaults", testCreatingVectorStructWithForcedDefaults),
+ ("testReadingStruct", testReadingStruct),
+ ("testReadingStructWithEnums", testReadingStructWithEnums),
+ ]
+}
+
+extension FlatBuffersTests {
+ // DO NOT MODIFY: This is autogenerated, use:
+ // `swift test --generate-linuxmain`
+ // to regenerate.
+ static let __allTests__FlatBuffersTests = [
+ ("testCreate", testCreate),
+ ("testCreateFinish", testCreateFinish),
+ ("testCreateFinishWithPrefix", testCreateFinishWithPrefix),
+ ("testCreateString", testCreateString),
+ ("testEndian", testEndian),
+ ("testOffset", testOffset),
+ ("testReadCountry", testReadCountry),
+ ("testStartTable", testStartTable),
+ ]
+}
+
+extension FlatBuffersUnionTests {
+ // DO NOT MODIFY: This is autogenerated, use:
+ // `swift test --generate-linuxmain`
+ // to regenerate.
+ static let __allTests__FlatBuffersUnionTests = [
+ ("testCreateMonstor", testCreateMonstor),
+ ("testEndTableFinish", testEndTableFinish),
+ ("testEnumVector", testEnumVector),
+ ("testUnionVector", testUnionVector),
+ ]
+}
+
+extension FlatBuffersVectors {
+ // DO NOT MODIFY: This is autogenerated, use:
+ // `swift test --generate-linuxmain`
+ // to regenerate.
+ static let __allTests__FlatBuffersVectors = [
+ ("testCreateIntArray", testCreateIntArray),
+ ("testCreateSharedStringVector", testCreateSharedStringVector),
+ ("testCreateVectorOfStrings", testCreateVectorOfStrings),
+ ("testCreatingTwoCountries", testCreatingTwoCountries),
+ ("testReadDoubleArray", testReadDoubleArray),
+ ("testReadInt32Array", testReadInt32Array),
+ ]
+}
+
+public func __allTests() -> [XCTestCaseEntry] {
+ return [
+ testCase(FlatBuffersDoubleTests.__allTests__FlatBuffersDoubleTests),
+ testCase(FlatBuffersMonsterWriterTests.__allTests__FlatBuffersMonsterWriterTests),
+ testCase(FlatBuffersStructsTests.__allTests__FlatBuffersStructsTests),
+ testCase(FlatBuffersTests.__allTests__FlatBuffersTests),
+ testCase(FlatBuffersUnionTests.__allTests__FlatBuffersUnionTests),
+ testCase(FlatBuffersVectors.__allTests__FlatBuffersVectors),
+ ]
+}
+#endif
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
new file mode 100644
index 000000000..aa6675d71
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift
@@ -0,0 +1,479 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import FlatBuffers
+
+public enum MyGame {
+public enum Example {
+
+public enum Color: UInt8, Enum {
+ public typealias T = UInt8
+ public static var byteSize: Int { return MemoryLayout.size }
+ public var value: UInt8 { return self.rawValue }
+ case red = 1, green = 2, blue = 8
+}
+
+public enum Race: Int8, Enum {
+ public typealias T = Int8
+ public static var byteSize: Int { return MemoryLayout.size }
+ public var value: Int8 { return self.rawValue }
+ case none = -1, human = 0, dwarf = 1, elf = 2
+}
+
+public enum Any_: UInt8, Enum {
+ public typealias T = UInt8
+ public static var byteSize: Int { return MemoryLayout.size }
+ public var value: UInt8 { return self.rawValue }
+ case none = 0, monster = 1, testsimpletablewithenum = 2, mygame_example2_monster = 3
+}
+
+public enum AnyUniqueAliases: UInt8, Enum {
+ public typealias T = UInt8
+ public static var byteSize: Int { return MemoryLayout.size }
+ public var value: UInt8 { return self.rawValue }
+ case none = 0, m = 1, ts = 2, m2 = 3
+}
+
+public enum AnyAmbiguousAliases: UInt8, Enum {
+ public typealias T = UInt8
+ public static var byteSize: Int { return MemoryLayout.size }
+ public var value: UInt8 { return self.rawValue }
+ case none = 0, m1 = 1, m2 = 2, m3 = 3
+}
+
+public struct Test: Readable {
+ private var _accessor: Struct
+ public static var size = 4
+ public static var alignment = 2
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }
+
+ public var a: Int16 { return _accessor.readBuffer(of: Int16.self, at: 0) }
+ public func mutate(a: Int16) -> Bool { return _accessor.mutate(a, index: 0) }
+ public var b: Int8 { return _accessor.readBuffer(of: Int8.self, at: 2) }
+ public func mutate(b: Int8) -> Bool { return _accessor.mutate(b, index: 2) }
+}
+
+public struct Vec3: Readable {
+ private var _accessor: Struct
+ public static var size = 32
+ public static var alignment = 8
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }
+
+ public var x: Float32 { return _accessor.readBuffer(of: Float32.self, at: 0) }
+ public func mutate(x: Float32) -> Bool { return _accessor.mutate(x, index: 0) }
+ public var y: Float32 { return _accessor.readBuffer(of: Float32.self, at: 4) }
+ public func mutate(y: Float32) -> Bool { return _accessor.mutate(y, index: 4) }
+ public var z: Float32 { return _accessor.readBuffer(of: Float32.self, at: 8) }
+ public func mutate(z: Float32) -> Bool { return _accessor.mutate(z, index: 8) }
+ public var test1: Double { return _accessor.readBuffer(of: Double.self, at: 16) }
+ public func mutate(test1: Double) -> Bool { return _accessor.mutate(test1, index: 16) }
+ public var test2: MyGame.Example.Color { return MyGame.Example.Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: 24)) ?? MyGame.Example.Color.red }
+ public var test3: MyGame.Example.Test { return MyGame.Example.Test(_accessor.bb, o: _accessor.postion + 26) }
+}
+
+public struct Ability: Readable {
+ private var _accessor: Struct
+ public static var size = 8
+ public static var alignment = 4
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }
+
+ public var id: UInt32 { return _accessor.readBuffer(of: UInt32.self, at: 0) }
+ public func mutate(id: UInt32) -> Bool { return _accessor.mutate(id, index: 0) }
+ public var distance: UInt32 { return _accessor.readBuffer(of: UInt32.self, at: 4) }
+ public func mutate(distance: UInt32) -> Bool { return _accessor.mutate(distance, index: 4) }
+}
+
+public static func createTest(a: Int16, b: Int8) -> UnsafeMutableRawPointer {
+ let memory = UnsafeMutableRawPointer.allocate(byteCount: Test.size, alignment: Test.alignment)
+ memory.initializeMemory(as: UInt8.self, repeating: 0, count: Test.size)
+ memory.storeBytes(of: a, toByteOffset: 0, as: Int16.self)
+ memory.storeBytes(of: b, toByteOffset: 2, as: Int8.self)
+ return memory
+}
+
+public static func createVec3(x: Float32, y: Float32, z: Float32, test1: Double, test2: MyGame.Example.Color, test3a: Int16, test3b: Int8) -> UnsafeMutableRawPointer {
+ let memory = UnsafeMutableRawPointer.allocate(byteCount: Vec3.size, alignment: Vec3.alignment)
+ memory.initializeMemory(as: UInt8.self, repeating: 0, count: Vec3.size)
+ memory.storeBytes(of: x, toByteOffset: 0, as: Float32.self)
+ memory.storeBytes(of: y, toByteOffset: 4, as: Float32.self)
+ memory.storeBytes(of: z, toByteOffset: 8, as: Float32.self)
+ memory.storeBytes(of: test1, toByteOffset: 16, as: Double.self)
+ memory.storeBytes(of: test2.rawValue, toByteOffset: 24, as: UInt8.self)
+ memory.storeBytes(of: test3a, toByteOffset: 26, as: Int16.self)
+ memory.storeBytes(of: test3b, toByteOffset: 28, as: Int8.self)
+ return memory
+}
+
+public static func createAbility(id: UInt32, distance: UInt32) -> UnsafeMutableRawPointer {
+ let memory = UnsafeMutableRawPointer.allocate(byteCount: Ability.size, alignment: Ability.alignment)
+ memory.initializeMemory(as: UInt8.self, repeating: 0, count: Ability.size)
+ memory.storeBytes(of: id, toByteOffset: 0, as: UInt32.self)
+ memory.storeBytes(of: distance, toByteOffset: 4, as: UInt32.self)
+ return memory
+}
+
+}
+
+// MARK: - Example
+
+
+public struct InParentNamespace: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) }
+ public static func getRootAsInParentNamespace(bb: ByteBuffer) -> InParentNamespace { return InParentNamespace(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public static func startInParentNamespace(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 0) }
+ public static func endInParentNamespace(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+
+public enum Example2 {
+
+public struct Monster: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) }
+ public static func getRootAsMonster(bb: ByteBuffer) -> Monster { return Monster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public static func startMonster(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 0) }
+ public static func endMonster(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+
+}
+
+// MARK: - Example2
+
+
+}
+extension MyGame.Example {
+
+public struct TestSimpleTableWithEnum: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) }
+ public static func getRootAsTestSimpleTableWithEnum(bb: ByteBuffer) -> TestSimpleTableWithEnum { return TestSimpleTableWithEnum(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var color: MyGame.Example.Color { let o = _accessor.offset(4); return o == 0 ? MyGame.Example.Color.green : MyGame.Example.Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? MyGame.Example.Color.green }
+ public func mutate(color: MyGame.Example.Color) -> Bool {let o = _accessor.offset(4); return _accessor.mutate(color.rawValue, index: o) }
+ public static func startTestSimpleTableWithEnum(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
+ public static func add(color: MyGame.Example.Color, _ fbb: FlatBufferBuilder) { fbb.add(element: color.rawValue, def: 2, at: 0) }
+ public static func endTestSimpleTableWithEnum(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+
+public struct Stat: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) }
+ public static func getRootAsStat(bb: ByteBuffer) -> Stat { return Stat(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var id: String? { let o = _accessor.offset(4); return o == 0 ? nil : _accessor.string(at: o) }
+ public var idSegmentArray: [UInt8]? { return _accessor.getVector(at: 4) }
+ public var val: Int64 { let o = _accessor.offset(6); return o == 0 ? 0 : _accessor.readBuffer(of: Int64.self, at: o) }
+ public func mutate(val: Int64) -> Bool {let o = _accessor.offset(6); return _accessor.mutate(val, index: o) }
+ public var count: UInt16 { let o = _accessor.offset(8); return o == 0 ? 0 : _accessor.readBuffer(of: UInt16.self, at: o) }
+ public func mutate(count: UInt16) -> Bool {let o = _accessor.offset(8); return _accessor.mutate(count, index: o) }
+ public static func startStat(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 3) }
+ public static func add(id: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: id, at: 0) }
+ public static func add(val: Int64, _ fbb: FlatBufferBuilder) { fbb.add(element: val, def: 0, at: 1) }
+ public static func add(count: UInt16, _ fbb: FlatBufferBuilder) { fbb.add(element: count, def: 0, at: 2) }
+ public static func endStat(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+
+public struct Referrable: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) }
+ public static func getRootAsReferrable(bb: ByteBuffer) -> Referrable { return Referrable(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var id: UInt64 { let o = _accessor.offset(4); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) }
+ public func mutate(id: UInt64) -> Bool {let o = _accessor.offset(4); return _accessor.mutate(id, index: o) }
+ public static func startReferrable(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
+ public static func add(id: UInt64, _ fbb: FlatBufferBuilder) { fbb.add(element: id, def: 0, at: 0) }
+ public static func endReferrable(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+ public static func sortVectorOfReferrable(offsets:[Offset], _ fbb: FlatBufferBuilder) -> Offset {
+ var off = offsets
+ off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 4, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 4, fbb: fbb.buffer), fbb: fbb.buffer) < 0 }
+ return fbb.createVector(ofOffsets: off)
+ }
+ fileprivate static func lookupByKey(vector: Int32, key: UInt64, fbb: ByteBuffer) -> Referrable? {
+ var span = fbb.read(def: Int32.self, position: Int(vector - 4))
+ var start: Int32 = 0
+ while span != 0 {
+ var middle = span / 2
+ let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)
+ let comp = fbb.read(def: UInt64.self, position: Int(Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: 4, fbb: fbb)))
+ if comp > 0 {
+ span = middle
+ } else if comp < 0 {
+ middle += 1
+ start += middle
+ span -= middle
+ } else {
+ return Referrable(fbb, o: tableOffset)
+ }
+ }
+ return nil
+ }
+}
+
+public struct Monster: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) }
+ public static func getRootAsMonster(bb: ByteBuffer) -> Monster { return Monster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var pos: MyGame.Example.Vec3? { let o = _accessor.offset(4); return o == 0 ? nil : MyGame.Example.Vec3(_accessor.bb, o: o + _accessor.postion) }
+ public var mana: Int16 { let o = _accessor.offset(6); return o == 0 ? 150 : _accessor.readBuffer(of: Int16.self, at: o) }
+ public func mutate(mana: Int16) -> Bool {let o = _accessor.offset(6); return _accessor.mutate(mana, index: o) }
+ public var hp: Int16 { let o = _accessor.offset(8); return o == 0 ? 100 : _accessor.readBuffer(of: Int16.self, at: o) }
+ public func mutate(hp: Int16) -> Bool {let o = _accessor.offset(8); return _accessor.mutate(hp, index: o) }
+ public var name: String? { let o = _accessor.offset(10); return o == 0 ? nil : _accessor.string(at: o) }
+ public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: 10) }
+ public var inventoryCount: Int32 { let o = _accessor.offset(14); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func inventory(at index: Int32) -> UInt8 { let o = _accessor.offset(14); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) }
+ public var inventory: [UInt8] { return _accessor.getVector(at: 14) ?? [] }
+ public func mutate(inventory: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(14); return _accessor.directMutate(inventory, index: _accessor.vector(at: o) + index * 1) }
+ public var color: MyGame.Example.Color { let o = _accessor.offset(16); return o == 0 ? MyGame.Example.Color.blue : MyGame.Example.Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? MyGame.Example.Color.blue }
+ public func mutate(color: MyGame.Example.Color) -> Bool {let o = _accessor.offset(16); return _accessor.mutate(color.rawValue, index: o) }
+ public var testType: MyGame.Example.Any_ { let o = _accessor.offset(18); return o == 0 ? MyGame.Example.Any_.none : MyGame.Example.Any_(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? MyGame.Example.Any_.none }
+ public func test(type: T.Type) -> T? { let o = _accessor.offset(20); return o == 0 ? nil : _accessor.union(o) }
+ public var test4Count: Int32 { let o = _accessor.offset(22); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func test4(at index: Int32) -> MyGame.Example.Test? { let o = _accessor.offset(22); return o == 0 ? nil : MyGame.Example.Test(_accessor.bb, o: _accessor.vector(at: o) + index * 4) }
+ public var testarrayofstringCount: Int32 { let o = _accessor.offset(24); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func testarrayofstring(at index: Int32) -> String? { let o = _accessor.offset(24); return o == 0 ? nil : _accessor.directString(at: _accessor.vector(at: o) + index * 4) }
+ public var testarrayoftablesCount: Int32 { let o = _accessor.offset(26); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func testarrayoftables(at index: Int32) -> MyGame.Example.Monster? { let o = _accessor.offset(26); return o == 0 ? nil : MyGame.Example.Monster(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) }
+ public func testarrayoftablesBy(key: String) -> MyGame.Example.Monster? { let o = _accessor.offset(26); return o == 0 ? nil : MyGame.Example.Monster.lookupByKey(vector: _accessor.vector(at: o), key: key, fbb: _accessor.bb) }
+ public var enemy: MyGame.Example.Monster? { let o = _accessor.offset(28); return o == 0 ? nil : MyGame.Example.Monster(_accessor.bb, o: _accessor.indirect(o + _accessor.postion)) }
+ public var testnestedflatbufferCount: Int32 { let o = _accessor.offset(30); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func testnestedflatbuffer(at index: Int32) -> UInt8 { let o = _accessor.offset(30); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) }
+ public var testnestedflatbuffer: [UInt8] { return _accessor.getVector(at: 30) ?? [] }
+ public func mutate(testnestedflatbuffer: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(30); return _accessor.directMutate(testnestedflatbuffer, index: _accessor.vector(at: o) + index * 1) }
+ public var testempty: MyGame.Example.Stat? { let o = _accessor.offset(32); return o == 0 ? nil : MyGame.Example.Stat(_accessor.bb, o: _accessor.indirect(o + _accessor.postion)) }
+ public var testbool: Bool { let o = _accessor.offset(34); return o == 0 ? false : 0 != _accessor.readBuffer(of: Byte.self, at: o) }
+ public func mutate(testbool: Byte) -> Bool {let o = _accessor.offset(34); return _accessor.mutate(testbool, index: o) }
+ public var testhashs32Fnv1: Int32 { let o = _accessor.offset(36); return o == 0 ? 0 : _accessor.readBuffer(of: Int32.self, at: o) }
+ public func mutate(testhashs32Fnv1: Int32) -> Bool {let o = _accessor.offset(36); return _accessor.mutate(testhashs32Fnv1, index: o) }
+ public var testhashu32Fnv1: UInt32 { let o = _accessor.offset(38); return o == 0 ? 0 : _accessor.readBuffer(of: UInt32.self, at: o) }
+ public func mutate(testhashu32Fnv1: UInt32) -> Bool {let o = _accessor.offset(38); return _accessor.mutate(testhashu32Fnv1, index: o) }
+ public var testhashs64Fnv1: Int64 { let o = _accessor.offset(40); return o == 0 ? 0 : _accessor.readBuffer(of: Int64.self, at: o) }
+ public func mutate(testhashs64Fnv1: Int64) -> Bool {let o = _accessor.offset(40); return _accessor.mutate(testhashs64Fnv1, index: o) }
+ public var testhashu64Fnv1: UInt64 { let o = _accessor.offset(42); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) }
+ public func mutate(testhashu64Fnv1: UInt64) -> Bool {let o = _accessor.offset(42); return _accessor.mutate(testhashu64Fnv1, index: o) }
+ public var testhashs32Fnv1a: Int32 { let o = _accessor.offset(44); return o == 0 ? 0 : _accessor.readBuffer(of: Int32.self, at: o) }
+ public func mutate(testhashs32Fnv1a: Int32) -> Bool {let o = _accessor.offset(44); return _accessor.mutate(testhashs32Fnv1a, index: o) }
+ public var testhashu32Fnv1a: UInt32 { let o = _accessor.offset(46); return o == 0 ? 0 : _accessor.readBuffer(of: UInt32.self, at: o) }
+ public func mutate(testhashu32Fnv1a: UInt32) -> Bool {let o = _accessor.offset(46); return _accessor.mutate(testhashu32Fnv1a, index: o) }
+ public var testhashs64Fnv1a: Int64 { let o = _accessor.offset(48); return o == 0 ? 0 : _accessor.readBuffer(of: Int64.self, at: o) }
+ public func mutate(testhashs64Fnv1a: Int64) -> Bool {let o = _accessor.offset(48); return _accessor.mutate(testhashs64Fnv1a, index: o) }
+ public var testhashu64Fnv1a: UInt64 { let o = _accessor.offset(50); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) }
+ public func mutate(testhashu64Fnv1a: UInt64) -> Bool {let o = _accessor.offset(50); return _accessor.mutate(testhashu64Fnv1a, index: o) }
+ public var testarrayofboolsCount: Int32 { let o = _accessor.offset(52); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func testarrayofbools(at index: Int32) -> Bool { let o = _accessor.offset(52); return o == 0 ? true : 0 != _accessor.directRead(of: Byte.self, offset: _accessor.vector(at: o) + index * 1) }
+ public var testarrayofbools: [Byte] { return _accessor.getVector(at: 52) ?? [] }
+ public func mutate(testarrayofbools: Byte, at index: Int32) -> Bool { let o = _accessor.offset(52); return _accessor.directMutate(testarrayofbools, index: _accessor.vector(at: o) + index * 1) }
+ public var testf: Float32 { let o = _accessor.offset(54); return o == 0 ? 3.14159 : _accessor.readBuffer(of: Float32.self, at: o) }
+ public func mutate(testf: Float32) -> Bool {let o = _accessor.offset(54); return _accessor.mutate(testf, index: o) }
+ public var testf2: Float32 { let o = _accessor.offset(56); return o == 0 ? 3.0 : _accessor.readBuffer(of: Float32.self, at: o) }
+ public func mutate(testf2: Float32) -> Bool {let o = _accessor.offset(56); return _accessor.mutate(testf2, index: o) }
+ public var testf3: Float32 { let o = _accessor.offset(58); return o == 0 ? 0.0 : _accessor.readBuffer(of: Float32.self, at: o) }
+ public func mutate(testf3: Float32) -> Bool {let o = _accessor.offset(58); return _accessor.mutate(testf3, index: o) }
+ public var testarrayofstring2Count: Int32 { let o = _accessor.offset(60); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func testarrayofstring2(at index: Int32) -> String? { let o = _accessor.offset(60); return o == 0 ? nil : _accessor.directString(at: _accessor.vector(at: o) + index * 4) }
+ public var testarrayofsortedstructCount: Int32 { let o = _accessor.offset(62); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func testarrayofsortedstruct(at index: Int32) -> MyGame.Example.Ability? { let o = _accessor.offset(62); return o == 0 ? nil : MyGame.Example.Ability(_accessor.bb, o: _accessor.vector(at: o) + index * 8) }
+ public var flexCount: Int32 { let o = _accessor.offset(64); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func flex(at index: Int32) -> UInt8 { let o = _accessor.offset(64); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) }
+ public var flex: [UInt8] { return _accessor.getVector(at: 64) ?? [] }
+ public func mutate(flex: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(64); return _accessor.directMutate(flex, index: _accessor.vector(at: o) + index * 1) }
+ public var test5Count: Int32 { let o = _accessor.offset(66); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func test5(at index: Int32) -> MyGame.Example.Test? { let o = _accessor.offset(66); return o == 0 ? nil : MyGame.Example.Test(_accessor.bb, o: _accessor.vector(at: o) + index * 4) }
+ public var vectorOfLongsCount: Int32 { let o = _accessor.offset(68); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfLongs(at index: Int32) -> Int64 { let o = _accessor.offset(68); return o == 0 ? 0 : _accessor.directRead(of: Int64.self, offset: _accessor.vector(at: o) + index * 8) }
+ public var vectorOfLongs: [Int64] { return _accessor.getVector(at: 68) ?? [] }
+ public func mutate(vectorOfLongs: Int64, at index: Int32) -> Bool { let o = _accessor.offset(68); return _accessor.directMutate(vectorOfLongs, index: _accessor.vector(at: o) + index * 8) }
+ public var vectorOfDoublesCount: Int32 { let o = _accessor.offset(70); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfDoubles(at index: Int32) -> Double { let o = _accessor.offset(70); return o == 0 ? 0 : _accessor.directRead(of: Double.self, offset: _accessor.vector(at: o) + index * 8) }
+ public var vectorOfDoubles: [Double] { return _accessor.getVector(at: 70) ?? [] }
+ public func mutate(vectorOfDoubles: Double, at index: Int32) -> Bool { let o = _accessor.offset(70); return _accessor.directMutate(vectorOfDoubles, index: _accessor.vector(at: o) + index * 8) }
+ public var parentNamespaceTest: MyGame.InParentNamespace? { let o = _accessor.offset(72); return o == 0 ? nil : MyGame.InParentNamespace(_accessor.bb, o: _accessor.indirect(o + _accessor.postion)) }
+ public var vectorOfReferrablesCount: Int32 { let o = _accessor.offset(74); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfReferrables(at index: Int32) -> MyGame.Example.Referrable? { let o = _accessor.offset(74); return o == 0 ? nil : MyGame.Example.Referrable(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) }
+ public func vectorOfReferrablesBy(key: UInt64) -> MyGame.Example.Referrable? { let o = _accessor.offset(74); return o == 0 ? nil : MyGame.Example.Referrable.lookupByKey(vector: _accessor.vector(at: o), key: key, fbb: _accessor.bb) }
+ public var singleWeakReference: UInt64 { let o = _accessor.offset(76); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) }
+ public func mutate(singleWeakReference: UInt64) -> Bool {let o = _accessor.offset(76); return _accessor.mutate(singleWeakReference, index: o) }
+ public var vectorOfWeakReferencesCount: Int32 { let o = _accessor.offset(78); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfWeakReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(78); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) }
+ public var vectorOfWeakReferences: [UInt64] { return _accessor.getVector(at: 78) ?? [] }
+ public func mutate(vectorOfWeakReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(78); return _accessor.directMutate(vectorOfWeakReferences, index: _accessor.vector(at: o) + index * 8) }
+ public var vectorOfStrongReferrablesCount: Int32 { let o = _accessor.offset(80); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfStrongReferrables(at index: Int32) -> MyGame.Example.Referrable? { let o = _accessor.offset(80); return o == 0 ? nil : MyGame.Example.Referrable(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) }
+ public func vectorOfStrongReferrablesBy(key: UInt64) -> MyGame.Example.Referrable? { let o = _accessor.offset(80); return o == 0 ? nil : MyGame.Example.Referrable.lookupByKey(vector: _accessor.vector(at: o), key: key, fbb: _accessor.bb) }
+ public var coOwningReference: UInt64 { let o = _accessor.offset(82); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) }
+ public func mutate(coOwningReference: UInt64) -> Bool {let o = _accessor.offset(82); return _accessor.mutate(coOwningReference, index: o) }
+ public var vectorOfCoOwningReferencesCount: Int32 { let o = _accessor.offset(84); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfCoOwningReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(84); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) }
+ public var vectorOfCoOwningReferences: [UInt64] { return _accessor.getVector(at: 84) ?? [] }
+ public func mutate(vectorOfCoOwningReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(84); return _accessor.directMutate(vectorOfCoOwningReferences, index: _accessor.vector(at: o) + index * 8) }
+ public var nonOwningReference: UInt64 { let o = _accessor.offset(86); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) }
+ public func mutate(nonOwningReference: UInt64) -> Bool {let o = _accessor.offset(86); return _accessor.mutate(nonOwningReference, index: o) }
+ public var vectorOfNonOwningReferencesCount: Int32 { let o = _accessor.offset(88); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfNonOwningReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(88); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) }
+ public var vectorOfNonOwningReferences: [UInt64] { return _accessor.getVector(at: 88) ?? [] }
+ public func mutate(vectorOfNonOwningReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(88); return _accessor.directMutate(vectorOfNonOwningReferences, index: _accessor.vector(at: o) + index * 8) }
+ public var anyUniqueType: MyGame.Example.AnyUniqueAliases { let o = _accessor.offset(90); return o == 0 ? MyGame.Example.AnyUniqueAliases.none : MyGame.Example.AnyUniqueAliases(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? MyGame.Example.AnyUniqueAliases.none }
+ public func anyUnique(type: T.Type) -> T? { let o = _accessor.offset(92); return o == 0 ? nil : _accessor.union(o) }
+ public var anyAmbiguousType: MyGame.Example.AnyAmbiguousAliases { let o = _accessor.offset(94); return o == 0 ? MyGame.Example.AnyAmbiguousAliases.none : MyGame.Example.AnyAmbiguousAliases(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? MyGame.Example.AnyAmbiguousAliases.none }
+ public func anyAmbiguous(type: T.Type) -> T? { let o = _accessor.offset(96); return o == 0 ? nil : _accessor.union(o) }
+ public var vectorOfEnumsCount: Int32 { let o = _accessor.offset(98); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vectorOfEnums(at index: Int32) -> MyGame.Example.Color? { let o = _accessor.offset(98); return o == 0 ? MyGame.Example.Color.red : MyGame.Example.Color(rawValue: _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1)) }
+ public var signedEnum: MyGame.Example.Race { let o = _accessor.offset(100); return o == 0 ? MyGame.Example.Race.none : MyGame.Example.Race(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? MyGame.Example.Race.none }
+ public func mutate(signedEnum: MyGame.Example.Race) -> Bool {let o = _accessor.offset(100); return _accessor.mutate(signedEnum.rawValue, index: o) }
+ public static func startMonster(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 49) }
+ public static func add(pos: Offset, _ fbb: FlatBufferBuilder) { fbb.add(structOffset: 0) }
+ public static func add(mana: Int16, _ fbb: FlatBufferBuilder) { fbb.add(element: mana, def: 150, at: 1) }
+ public static func add(hp: Int16, _ fbb: FlatBufferBuilder) { fbb.add(element: hp, def: 100, at: 2) }
+ public static func add(name: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: name, at: 3) }
+ public static func addVectorOf(inventory: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: inventory, at: 5) }
+ public static func add(color: MyGame.Example.Color, _ fbb: FlatBufferBuilder) { fbb.add(element: color.rawValue, def: 8, at: 6) }
+ public static func add(testType: MyGame.Example.Any_, _ fbb: FlatBufferBuilder) { fbb.add(element: testType.rawValue, def: 0, at: 7) }
+ public static func add(test: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: test, at: 8) }
+ public static func addVectorOf(test4: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: test4, at: 9) }
+ public static func addVectorOf(testarrayofstring: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayofstring, at: 10) }
+ public static func addVectorOf(testarrayoftables: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayoftables, at: 11) }
+ public static func add(enemy: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: enemy, at: 12) }
+ public static func addVectorOf(testnestedflatbuffer: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: testnestedflatbuffer, at: 13) }
+ public static func add(testempty: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: testempty, at: 14) }
+ public static func add(testbool: Bool, _ fbb: FlatBufferBuilder) { fbb.add(condition: testbool, def: false, at: 15) }
+ public static func add(testhashs32Fnv1: Int32, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashs32Fnv1, def: 0, at: 16) }
+ public static func add(testhashu32Fnv1: UInt32, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashu32Fnv1, def: 0, at: 17) }
+ public static func add(testhashs64Fnv1: Int64, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashs64Fnv1, def: 0, at: 18) }
+ public static func add(testhashu64Fnv1: UInt64, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashu64Fnv1, def: 0, at: 19) }
+ public static func add(testhashs32Fnv1a: Int32, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashs32Fnv1a, def: 0, at: 20) }
+ public static func add(testhashu32Fnv1a: UInt32, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashu32Fnv1a, def: 0, at: 21) }
+ public static func add(testhashs64Fnv1a: Int64, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashs64Fnv1a, def: 0, at: 22) }
+ public static func add(testhashu64Fnv1a: UInt64, _ fbb: FlatBufferBuilder) { fbb.add(element: testhashu64Fnv1a, def: 0, at: 23) }
+ public static func addVectorOf(testarrayofbools: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayofbools, at: 24) }
+ public static func add(testf: Float32, _ fbb: FlatBufferBuilder) { fbb.add(element: testf, def: 3.14159, at: 25) }
+ public static func add(testf2: Float32, _ fbb: FlatBufferBuilder) { fbb.add(element: testf2, def: 3.0, at: 26) }
+ public static func add(testf3: Float32, _ fbb: FlatBufferBuilder) { fbb.add(element: testf3, def: 0.0, at: 27) }
+ public static func addVectorOf(testarrayofstring2: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayofstring2, at: 28) }
+ public static func addVectorOf(testarrayofsortedstruct: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayofsortedstruct, at: 29) }
+ public static func addVectorOf(flex: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: flex, at: 30) }
+ public static func addVectorOf(test5: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: test5, at: 31) }
+ public static func addVectorOf(vectorOfLongs: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfLongs, at: 32) }
+ public static func addVectorOf(vectorOfDoubles: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfDoubles, at: 33) }
+ public static func add(parentNamespaceTest: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: parentNamespaceTest, at: 34) }
+ public static func addVectorOf(vectorOfReferrables: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfReferrables, at: 35) }
+ public static func add(singleWeakReference: UInt64, _ fbb: FlatBufferBuilder) { fbb.add(element: singleWeakReference, def: 0, at: 36) }
+ public static func addVectorOf(vectorOfWeakReferences: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfWeakReferences, at: 37) }
+ public static func addVectorOf(vectorOfStrongReferrables: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfStrongReferrables, at: 38) }
+ public static func add(coOwningReference: UInt64, _ fbb: FlatBufferBuilder) { fbb.add(element: coOwningReference, def: 0, at: 39) }
+ public static func addVectorOf(vectorOfCoOwningReferences: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfCoOwningReferences, at: 40) }
+ public static func add(nonOwningReference: UInt64, _ fbb: FlatBufferBuilder) { fbb.add(element: nonOwningReference, def: 0, at: 41) }
+ public static func addVectorOf(vectorOfNonOwningReferences: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfNonOwningReferences, at: 42) }
+ public static func add(anyUniqueType: MyGame.Example.AnyUniqueAliases, _ fbb: FlatBufferBuilder) { fbb.add(element: anyUniqueType.rawValue, def: 0, at: 43) }
+ public static func add(anyUnique: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: anyUnique, at: 44) }
+ public static func add(anyAmbiguousType: MyGame.Example.AnyAmbiguousAliases, _ fbb: FlatBufferBuilder) { fbb.add(element: anyAmbiguousType.rawValue, def: 0, at: 45) }
+ public static func add(anyAmbiguous: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: anyAmbiguous, at: 46) }
+ public static func addVectorOf(vectorOfEnums: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfEnums, at: 47) }
+ public static func add(signedEnum: MyGame.Example.Race, _ fbb: FlatBufferBuilder) { fbb.add(element: signedEnum.rawValue, def: -1, at: 48) }
+ public static func endMonster(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [10]); return end }
+ public static func sortVectorOfMonster(offsets:[Offset], _ fbb: FlatBufferBuilder) -> Offset {
+ var off = offsets
+ off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 10, fbb: fbb.buffer), fbb: fbb.buffer) < 0 }
+ return fbb.createVector(ofOffsets: off)
+ }
+ fileprivate static func lookupByKey(vector: Int32, key: String, fbb: ByteBuffer) -> Monster? {
+ let key = key.utf8.map { $0 }
+ var span = fbb.read(def: Int32.self, position: Int(vector - 4))
+ var start: Int32 = 0
+ while span != 0 {
+ var middle = span / 2
+ let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)
+ let comp = Table.compare(Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: 10, fbb: fbb), key, fbb: fbb)
+ if comp > 0 {
+ span = middle
+ } else if comp < 0 {
+ middle += 1
+ start += middle
+ span -= middle
+ } else {
+ return Monster(fbb, o: tableOffset)
+ }
+ }
+ return nil
+ }
+}
+
+public struct TypeAliases: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MONS", addPrefix: prefix) }
+ public static func getRootAsTypeAliases(bb: ByteBuffer) -> TypeAliases { return TypeAliases(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var i8: Int8 { let o = _accessor.offset(4); return o == 0 ? 0 : _accessor.readBuffer(of: Int8.self, at: o) }
+ public func mutate(i8: Int8) -> Bool {let o = _accessor.offset(4); return _accessor.mutate(i8, index: o) }
+ public var u8: UInt8 { let o = _accessor.offset(6); return o == 0 ? 0 : _accessor.readBuffer(of: UInt8.self, at: o) }
+ public func mutate(u8: UInt8) -> Bool {let o = _accessor.offset(6); return _accessor.mutate(u8, index: o) }
+ public var i16: Int16 { let o = _accessor.offset(8); return o == 0 ? 0 : _accessor.readBuffer(of: Int16.self, at: o) }
+ public func mutate(i16: Int16) -> Bool {let o = _accessor.offset(8); return _accessor.mutate(i16, index: o) }
+ public var u16: UInt16 { let o = _accessor.offset(10); return o == 0 ? 0 : _accessor.readBuffer(of: UInt16.self, at: o) }
+ public func mutate(u16: UInt16) -> Bool {let o = _accessor.offset(10); return _accessor.mutate(u16, index: o) }
+ public var i32: Int32 { let o = _accessor.offset(12); return o == 0 ? 0 : _accessor.readBuffer(of: Int32.self, at: o) }
+ public func mutate(i32: Int32) -> Bool {let o = _accessor.offset(12); return _accessor.mutate(i32, index: o) }
+ public var u32: UInt32 { let o = _accessor.offset(14); return o == 0 ? 0 : _accessor.readBuffer(of: UInt32.self, at: o) }
+ public func mutate(u32: UInt32) -> Bool {let o = _accessor.offset(14); return _accessor.mutate(u32, index: o) }
+ public var i64: Int64 { let o = _accessor.offset(16); return o == 0 ? 0 : _accessor.readBuffer(of: Int64.self, at: o) }
+ public func mutate(i64: Int64) -> Bool {let o = _accessor.offset(16); return _accessor.mutate(i64, index: o) }
+ public var u64: UInt64 { let o = _accessor.offset(18); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) }
+ public func mutate(u64: UInt64) -> Bool {let o = _accessor.offset(18); return _accessor.mutate(u64, index: o) }
+ public var f32: Float32 { let o = _accessor.offset(20); return o == 0 ? 0.0 : _accessor.readBuffer(of: Float32.self, at: o) }
+ public func mutate(f32: Float32) -> Bool {let o = _accessor.offset(20); return _accessor.mutate(f32, index: o) }
+ public var f64: Double { let o = _accessor.offset(22); return o == 0 ? 0.0 : _accessor.readBuffer(of: Double.self, at: o) }
+ public func mutate(f64: Double) -> Bool {let o = _accessor.offset(22); return _accessor.mutate(f64, index: o) }
+ public var v8Count: Int32 { let o = _accessor.offset(24); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func v8(at index: Int32) -> Int8 { let o = _accessor.offset(24); return o == 0 ? 0 : _accessor.directRead(of: Int8.self, offset: _accessor.vector(at: o) + index * 1) }
+ public var v8: [Int8] { return _accessor.getVector(at: 24) ?? [] }
+ public func mutate(v8: Int8, at index: Int32) -> Bool { let o = _accessor.offset(24); return _accessor.directMutate(v8, index: _accessor.vector(at: o) + index * 1) }
+ public var vf64Count: Int32 { let o = _accessor.offset(26); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func vf64(at index: Int32) -> Double { let o = _accessor.offset(26); return o == 0 ? 0 : _accessor.directRead(of: Double.self, offset: _accessor.vector(at: o) + index * 8) }
+ public var vf64: [Double] { return _accessor.getVector(at: 26) ?? [] }
+ public func mutate(vf64: Double, at index: Int32) -> Bool { let o = _accessor.offset(26); return _accessor.directMutate(vf64, index: _accessor.vector(at: o) + index * 8) }
+ public static func startTypeAliases(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 12) }
+ public static func add(i8: Int8, _ fbb: FlatBufferBuilder) { fbb.add(element: i8, def: 0, at: 0) }
+ public static func add(u8: UInt8, _ fbb: FlatBufferBuilder) { fbb.add(element: u8, def: 0, at: 1) }
+ public static func add(i16: Int16, _ fbb: FlatBufferBuilder) { fbb.add(element: i16, def: 0, at: 2) }
+ public static func add(u16: UInt16, _ fbb: FlatBufferBuilder) { fbb.add(element: u16, def: 0, at: 3) }
+ public static func add(i32: Int32, _ fbb: FlatBufferBuilder) { fbb.add(element: i32, def: 0, at: 4) }
+ public static func add(u32: UInt32, _ fbb: FlatBufferBuilder) { fbb.add(element: u32, def: 0, at: 5) }
+ public static func add(i64: Int64, _ fbb: FlatBufferBuilder) { fbb.add(element: i64, def: 0, at: 6) }
+ public static func add(u64: UInt64, _ fbb: FlatBufferBuilder) { fbb.add(element: u64, def: 0, at: 7) }
+ public static func add(f32: Float32, _ fbb: FlatBufferBuilder) { fbb.add(element: f32, def: 0.0, at: 8) }
+ public static func add(f64: Double, _ fbb: FlatBufferBuilder) { fbb.add(element: f64, def: 0.0, at: 9) }
+ public static func addVectorOf(v8: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: v8, at: 10) }
+ public static func addVectorOf(vf64: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: vf64, at: 11) }
+ public static func endTypeAliases(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+
+}
+
+// MARK: - Example
+
+
+// MARK: - MyGame
+
+
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
new file mode 100644
index 000000000..c1c6aca98
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift
@@ -0,0 +1,82 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import FlatBuffers
+
+public enum Character: UInt8, Enum {
+ public typealias T = UInt8
+ public static var byteSize: Int { return MemoryLayout.size }
+ public var value: UInt8 { return self.rawValue }
+ case none = 0, mulan = 1, rapunzel = 2, belle = 3, bookfan = 4, other = 5, unused = 6
+}
+
+public struct Rapunzel: Readable {
+ private var _accessor: Struct
+ public static var size = 4
+ public static var alignment = 4
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }
+
+ public var hairLength: Int32 { return _accessor.readBuffer(of: Int32.self, at: 0) }
+ public func mutate(hairLength: Int32) -> Bool { return _accessor.mutate(hairLength, index: 0) }
+}
+
+public struct BookReader: Readable {
+ private var _accessor: Struct
+ public static var size = 4
+ public static var alignment = 4
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }
+
+ public var booksRead: Int32 { return _accessor.readBuffer(of: Int32.self, at: 0) }
+ public func mutate(booksRead: Int32) -> Bool { return _accessor.mutate(booksRead, index: 0) }
+}
+
+public func createRapunzel(hairLength: Int32) -> UnsafeMutableRawPointer {
+ let memory = UnsafeMutableRawPointer.allocate(byteCount: Rapunzel.size, alignment: Rapunzel.alignment)
+ memory.initializeMemory(as: UInt8.self, repeating: 0, count: Rapunzel.size)
+ memory.storeBytes(of: hairLength, toByteOffset: 0, as: Int32.self)
+ return memory
+}
+
+public func createBookReader(booksRead: Int32) -> UnsafeMutableRawPointer {
+ let memory = UnsafeMutableRawPointer.allocate(byteCount: BookReader.size, alignment: BookReader.alignment)
+ memory.initializeMemory(as: UInt8.self, repeating: 0, count: BookReader.size)
+ memory.storeBytes(of: booksRead, toByteOffset: 0, as: Int32.self)
+ return memory
+}
+
+public struct Attacker: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MOVI", addPrefix: prefix) }
+ public static func getRootAsAttacker(bb: ByteBuffer) -> Attacker { return Attacker(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var swordAttackDamage: Int32 { let o = _accessor.offset(4); return o == 0 ? 0 : _accessor.readBuffer(of: Int32.self, at: o) }
+ public func mutate(swordAttackDamage: Int32) -> Bool {let o = _accessor.offset(4); return _accessor.mutate(swordAttackDamage, index: o) }
+ public static func startAttacker(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
+ public static func add(swordAttackDamage: Int32, _ fbb: FlatBufferBuilder) { fbb.add(element: swordAttackDamage, def: 0, at: 0) }
+ public static func endAttacker(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+
+public struct Movie: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset, prefix: Bool = false) { fbb.finish(offset: end, fileId: "MOVI", addPrefix: prefix) }
+ public static func getRootAsMovie(bb: ByteBuffer) -> Movie { return Movie(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
+
+ private init(_ t: Table) { _accessor = t }
+ public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
+
+ public var mainCharacterType: Character { let o = _accessor.offset(4); return o == 0 ? Character.none : Character(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? Character.none }
+ public func mainCharacter(type: T.Type) -> T? { let o = _accessor.offset(6); return o == 0 ? nil : _accessor.union(o) }
+ public var charactersTypeCount: Int32 { let o = _accessor.offset(8); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func charactersType(at index: Int32) -> Character? { let o = _accessor.offset(8); return o == 0 ? Character.none : Character(rawValue: _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1)) }
+ public var charactersCount: Int32 { let o = _accessor.offset(10); return o == 0 ? 0 : _accessor.vector(count: o) }
+ public func characters(at index: Int32, type: T.Type) -> T? { let o = _accessor.offset(10); return o == 0 ? nil : _accessor.directUnion(_accessor.vector(at: o) + index * 4) }
+ public static func startMovie(_ fbb: FlatBufferBuilder) -> UOffset { fbb.startTable(with: 4) }
+ public static func add(mainCharacterType: Character, _ fbb: FlatBufferBuilder) { fbb.add(element: mainCharacterType.rawValue, def: 0, at: 0) }
+ public static func add(mainCharacter: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: mainCharacter, at: 1) }
+ public static func addVectorOf(charactersType: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: charactersType, at: 2) }
+ public static func addVectorOf(characters: Offset, _ fbb: FlatBufferBuilder) { fbb.add(offset: characters, at: 3) }
+ public static func endMovie(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
+}
+
diff --git a/tests/FlatBuffers.Test.Swift/Tests/LinuxMain.swift b/tests/FlatBuffers.Test.Swift/Tests/LinuxMain.swift
new file mode 100644
index 000000000..1b16a78e7
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/LinuxMain.swift
@@ -0,0 +1,8 @@
+import XCTest
+
+import FlatBuffers_Test_SwiftTests
+
+var tests = [XCTestCaseEntry]()
+tests += FlatBuffers_Test_SwiftTests.__allTests()
+
+XCTMain(tests)
diff --git a/tests/FlatBuffers.Test.Swift/monsterdata_test.mon b/tests/FlatBuffers.Test.Swift/monsterdata_test.mon
new file mode 100644
index 000000000..ba6cf2786
Binary files /dev/null and b/tests/FlatBuffers.Test.Swift/monsterdata_test.mon differ
diff --git a/tests/TestAll.sh b/tests/TestAll.sh
index 0fc0acdbc..e20431c3b 100644
--- a/tests/TestAll.sh
+++ b/tests/TestAll.sh
@@ -60,4 +60,6 @@ echo "(in a different repo)"
echo "************************ Swift:"
-echo "(in a different repo)"
+cd FlatBuffers.Test.Swift
+sh SwiftTest.sh
+cd ..
\ No newline at end of file
diff --git a/tests/docker/languages/Dockerfile.testing.swift_5_1 b/tests/docker/languages/Dockerfile.testing.swift_5_1
new file mode 100644
index 000000000..e98e4be1f
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.swift_5_1
@@ -0,0 +1,8 @@
+FROM swift:5.1
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN swift --version
+WORKDIR /code/tests/FlatBuffers.Test.Swift
+RUN sh SwiftTest.sh