aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormustiikhalil <mustii@mmk.one>2020-01-09 23:12:10 +0300
committerWouter van Oortmerssen <aardappel@gmail.com>2020-01-09 12:12:10 -0800
commit04d80f255d1c2fa7a466e8465a119c0eaef26d59 (patch)
tree3bbb6d92e6d006a733ba04c638d6eecce228ad9a
parent55686100aa6f8b4867e8de62768d8fc0ecc5a541 (diff)
downloadflatbuffers-04d80f255d1c2fa7a466e8465a119c0eaef26d59.tar.gz
[Swift] Swift implementation 🎉🎉 (#5603)
* Implemented the swift version of Flatbuffers Implemented serailzing, reading, and mutating data from object monster Fixes mis-aligned pointer issue Fixes issue when shared strings are removed from table Adds swift enum, structs code gen Fixed namespace issues + started implementing the table gen Added Mutate function to the code generator Generated linux test cases Fixed an issue with bools, and structs readers in table writer Swift docker image added Updated the test cases, and removed a method parameters in swift Fixed createVector api when called with scalars Fixed issues with scalar arrays, and fixed the code gen namespaces, added sample_binary.swift Cleaned up project Added enum vectors, and their readers Refactored code Added swift into the support document Added documentation in docs, and fixed a small issue with Data() not being returned correctly Fixes Lowercase issue, and prevents generating lookups for deprecated keys * Made all the required funcs to have const + removed unneeded code + fix lowercase func * Removed transform from lowercased and moved it to function * Fixes an issue with iOS allocation from read * Refactored cpp code to be more readable * casts position into int for position * Fix enums issue, moves scalar writer code to use memcpy * Removed c_str from struct function * Fixed script to generate new objects when ran on travis ci: fix * Handles deallocating space allocated for structs * Updated the test cases to adhere to the fileprivate lookup, no mutation for unions, and updated the names of the vector functions
-rw-r--r--.gitignore6
-rw-r--r--CMakeLists.txt1
-rw-r--r--docs/source/Compiler.md2
-rw-r--r--docs/source/FlatBuffers.md4
-rw-r--r--docs/source/Support.md36
-rw-r--r--docs/source/SwiftUsage.md93
-rw-r--r--docs/source/Tutorial.md187
-rw-r--r--include/flatbuffers/idl.h42
-rw-r--r--samples/sample_binary.swift68
-rw-r--r--src/BUILD1
-rw-r--r--src/flatc_main.cpp3
-rw-r--r--src/idl_gen_kotlin.cpp2
-rw-r--r--src/idl_gen_swift.cpp758
-rw-r--r--src/idl_parser.cpp3
-rw-r--r--swift/Package.swift22
-rw-r--r--swift/Sources/FlatBuffers/ByteBuffer.swift243
-rw-r--r--swift/Sources/FlatBuffers/Constants.swift89
-rw-r--r--swift/Sources/FlatBuffers/FlatBufferBuilder.swift486
-rw-r--r--swift/Sources/FlatBuffers/FlatBufferObject.swift87
-rw-r--r--swift/Sources/FlatBuffers/FlatBuffersUtils.swift16
-rw-r--r--swift/Sources/FlatBuffers/Int+extension.swift31
-rw-r--r--swift/Sources/FlatBuffers/Offset.swift12
-rw-r--r--swift/Sources/FlatBuffers/Struct.swift16
-rw-r--r--swift/Sources/FlatBuffers/Table.swift144
-rw-r--r--tests/FlatBuffers.Benchmarks.swift/Package.swift19
-rw-r--r--tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift75
-rw-r--r--tests/FlatBuffers.Test.Swift/Package.swift20
-rw-r--r--tests/FlatBuffers.Test.Swift/SwiftTest.sh10
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift190
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersStructsTests.swift183
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift118
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift229
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift108
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift76
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift94
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift479
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift82
-rw-r--r--tests/FlatBuffers.Test.Swift/Tests/LinuxMain.swift8
-rw-r--r--tests/FlatBuffers.Test.Swift/monsterdata_test.monbin0 -> 440 bytes
-rw-r--r--tests/TestAll.sh4
-rw-r--r--tests/docker/languages/Dockerfile.testing.swift_5_18
41 files changed, 4015 insertions, 40 deletions
diff --git a/.gitignore b/.gitignore
index d6ec9fd8..bfe065bc 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 815dadfb..a1c7c00e 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 c5768bd2..9061051b 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 a9d637ac..45ffbf22 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 c8ac7f7e..1e435a66 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
<br>
diff --git a/docs/source/SwiftUsage.md b/docs/source/SwiftUsage.md
new file mode 100644
index 00000000..fb8b1fd9
--- /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.
+
+<br>
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index e8d8519b..00408b52 100644
--- a/docs/source/Tutorial.md
+++ b/docs/source/Tutorial.md
@@ -35,6 +35,7 @@ Please select your desired language for our quest:
<input type="radio" name="language" value="lua">Lua</input>
<input type="radio" name="language" value="lobster">Lobster</input>
<input type="radio" name="language" value="rust">Rust</input>
+ <input type="radio" name="language" value="swift">Swift</input>
</form>
\endhtmlonly
@@ -152,6 +153,9 @@ For your chosen language, please cross-reference with:
<div class="language-rust">
[sample_binary.rs](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.rs)
</div>
+<div class="language-swift">
+[sample_binary.swift](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.swift)
+</div>
## Writing the Monsters' FlatBuffer Schema
@@ -363,6 +367,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools.
./../flatc --rust monster.fbs
~~~
</div>
+<div class="language-swift">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --swift monster.fbs
+~~~
+</div>
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.
~~~
</div>
+<div class="language-swift">
+~~~{.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
+~~~
+</div>
+
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);
~~~
</div>
+<div class="language-swift">
+~~~{.swift}
+ // create a `FlatBufferBuilder`, which will be used to serialize objects
+ let builder = FlatBufferBuilder(initialSize: 1024)
+~~~
+</div>
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`.
~~~
</div>
+<div class="language-swift">
+~~~{.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)
+~~~
+</div>
+
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]);
~~~
</div>
+<div class="language-swift">
+~~~{.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)
+~~~
+</div>
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]);
~~~
</div>
+<div class="language-swift">
+~~~{.swift}
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
+~~~
+</div>
<br>
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]);
~~~
</div>
+<div class="language-swift">
+~~~{.swift}
+ //
+ let points = builder.createVector(structs: [MyGame.Sample.createVec3(x: 1, y: 2, z: 3),
+ MyGame.Sample.createVec3(x: 4, y: 5, z: 6)],
+ type: Vec3.self)
+~~~
+</div>
+
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:
});
~~~
</div>
+<div class="language-swift">
+~~~{.swift}
+ 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)
+~~~
+</div>
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
~~~
</div>
+<div class="language-swift">
+ ~~~{.swift}
+ Monster.add(equippedType: .weapon, builder) // Type of union
+ Monster.add(equipped: axe, builder) // Union data
+ ~~~
+</div>
+
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);
~~~
</div>
+<div class="language-swift">
+~~~{.swift}
+ // Call `finish(offset:)` to instruct the builder that this monster is complete.
+ builder.finish(offset: orc)
+~~~
+</div>
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:
~~~
</div>
+<div class="language-swift">
+~~~{.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)
+~~~
+</div>
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);
~~~
</div>
+<div class="language-swift">
+~~~{.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))
+~~~
+</div>
+
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:
~~~
</div>
+<div class="language-swift">
+~~~{.swift}
+ let hp = monster.hp
+ let mana = monster.mana
+ let name = monster.name // returns an optional string
+~~~
+</div>
+
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`:
~~~
</div>
+<div class="language-swift">
+~~~{.swift}
+ let pos = monster.pos
+ let x = pos.x
+ let y = pos.y
+ let z = pos.z
+~~~
+</div>
+
`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`.
~~~
</div>
+<div class="language-swift">
+~~~{.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
+~~~
+</div>
+
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();
~~~
</div>
+<div class="language-swift">
+~~~{.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
+~~~
+</div>
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
~~~
</div>
+<div class="language-swift">
+~~~{.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
+ }
+~~~
+</div>
+
## Mutating FlatBuffers
As you saw above, typically once you have created a FlatBuffer, it is read-only
@@ -3046,6 +3220,15 @@ mutators like so:
~~~
</div>
+<div class="language-swift">
+~~~{.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
+~~~
+</div>
+
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:
<div class="language-rust">
[Use in Rust](@ref flatbuffers_guide_use_rust)
</div>
-
+<div class="language-swift">
+[Use in Swift](@ref flatbuffers_guide_use_swift)
+</div>
<br>
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index 1f013a8b..eac70d9e 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<void>, int, int, StringOffset, int, unused, Int) \
- TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused, Int) \
- TD(STRUCT, "", Offset<void>, int, int, int, int, unused, Int) \
- TD(UNION, "", Offset<void>, int, int, int, int, unused, Int)
+ TD(STRING, "string", Offset<void>, int, int, StringOffset, int, unused, Int, Offset<String>) \
+ TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused, Int, Offset<UOffset>) \
+ TD(STRUCT, "", Offset<void>, int, int, int, int, unused, Int, Offset<UOffset>) \
+ TD(UNION, "", Offset<void>, int, int, int, int, unused, Int, Offset<UOffset>)
#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<UOffset>)
// 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 00000000..e334fab7
--- /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..<monster.inventoryCount {
+ assert(i == monster.inventory(at: i))
+ }
+
+ for i in 0..<monster.weaponsCount {
+ let weap = monster.weapons(at: i)
+ let index = Int(i)
+ assert(weap?.damage == expectedDMG[index])
+ assert(weap?.name == expectedNames[index])
+ }
+ assert(monster.equippedType == .weapon)
+ let equipped = monster.equipped(type: Weapon.self)
+ assert(equipped?.name == "Axe")
+ assert(equipped?.damage == 5)
+ print("Monster Object is Verified")
+} \ No newline at end of file
diff --git a/src/BUILD b/src/BUILD
index 3532a7ac..f50727a0 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -56,6 +56,7 @@ cc_library(
"idl_gen_python.cpp",
"idl_gen_rust.cpp",
"idl_gen_text.cpp",
+ "idl_gen_swift.cpp",
"util.cpp",
],
hdrs = [
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
index 34739ced..b8a771ff 100644
--- a/src/flatc_main.cpp
+++ b/src/flatc_main.cpp
@@ -105,6 +105,9 @@ int main(int argc, const char *argv[]) {
{ flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema",
true, nullptr, flatbuffers::IDLOptions::kJsonSchema,
"Generate Json schema", nullptr },
+ { flatbuffers::GenerateSwift, nullptr, "--swift", "swift",
+ true, nullptr, flatbuffers::IDLOptions::kSwift,
+ "Generate Swift files for tables/structs", nullptr },
};
flatbuffers::FlatCompiler::InitParams params;
diff --git a/src/idl_gen_kotlin.cpp b/src/idl_gen_kotlin.cpp
index bde552f7..ece4b658 100644
--- a/src/idl_gen_kotlin.cpp
+++ b/src/idl_gen_kotlin.cpp
@@ -141,7 +141,7 @@ class KotlinGenerator : public BaseGenerator {
// clang-format off
static const char * const kotlin_typename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
- CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, ...) \
#KTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp
new file mode 100644
index 00000000..04c099f7
--- /dev/null
+++ b/src/idl_gen_swift.cpp
@@ -0,0 +1,758 @@
+#include <unordered_set>
+
+#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<char>(::tolower(static_cast<unsigned char>(c)));
+}
+
+class SwiftGenerator : public BaseGenerator {
+ private:
+ const Namespace *cur_name_space_;
+ CodeWriter code_;
+ std::unordered_set<std::string> keywords_;
+ std::set<std::string> 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<int>(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<UOffset>, 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<std::string> 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<int>(it - struct_def.fields.vec.begin()));
+ }
+ code_ +=
+ "\tpublic static func end{{STRUCTNAME}}(_ fbb: FlatBufferBuilder, "
+ "start: "
+ "UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(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<UOffset>], "
+ "_ fbb: FlatBufferBuilder) -> Offset<UOffset> {";
+ 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<String>"
+ : "Offset<UOffset>";
+ 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}}<T: FlatBufferObject>(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}}<T: FlatBufferObject>(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<int>(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 7c3c46dc..13c8c3ad 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 00000000..18bb90a4
--- /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 00000000..654b265c
--- /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<UInt8>.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<UInt8>.size * Int(padding))
+ }
+
+ ///Adds an array of type Scalar to the buffer memory
+ /// - Parameter elements: An array of Scalars
+ func push<T: Scalar>(elements: [T]) {
+ let size = elements.count * MemoryLayout<T>.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<T: Scalar>(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<String.UTF8View.Element>, 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<T>(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<T>(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<T>(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 00000000..889b0cc3
--- /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<SOffset>.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 00000000..84fba1be
--- /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<String>] = [:]
+ /// 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<UOffset>, 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<T>(offset: Offset<T>, fileId: String, addPrefix prefix: Bool = false) {
+ let size = MemoryLayout<UOffset>.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<T>(offset: Offset<T>, addPrefix prefix: Bool = false) {
+ notNested()
+ let size = MemoryLayout<UOffset>.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<VOffset>.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<T: Scalar>(len: Int, type: T.Type) {
+ preAlign(len: len, alignment: MemoryLayout<T>.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<UOffset>.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<T: Scalar>(_ elements: [T]) -> Offset<UOffset> {
+ 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<T: Scalar>(_ elements: [T], size: Int) -> Offset<UOffset> {
+ let size = size
+ startVector(size, elementSize: MemoryLayout<T>.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<T: Enum>(_ elements: [T]) -> Offset<UOffset> {
+ 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<T: Enum>(_ elements: [T], size: Int) -> Offset<UOffset> {
+ 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<T>(ofOffsets offsets: [Offset<T>]) -> Offset<UOffset> {
+ 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<T>(ofOffsets offsets: [Offset<T>], len: Int) -> Offset<UOffset> {
+ startVector(len, elementSize: MemoryLayout<Offset<T>>.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<UOffset> {
+ var offsets: [Offset<String>] = []
+ 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<T: Readable>(structs: [UnsafeMutableRawPointer],
+ type: T.Type) -> Offset<UOffset> {
+ 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<T: Readable>(struct s: UnsafeMutableRawPointer,
+ type: T.Type) -> Offset<UOffset> {
+ 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<String> {
+ 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<String> {
+ 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<T>(offset: Offset<T>, 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<T>(element o: Offset<T>) -> 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<T: Scalar>(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<T: Scalar>(element: T) -> UOffset {
+ preAlign(len: MemoryLayout<T>.size,
+ alignment: MemoryLayout<T>.size)
+ _bb.push(value: element, len: MemoryLayout<T>.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 00000000..6e405f5b
--- /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<T: Scalar>(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<T: Scalar>(_ 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<T: Scalar>(_ 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<T: Scalar>(_ 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<T: Scalar>(_ 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 00000000..6838f862
--- /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<Int32>.size)
+ }
+}
diff --git a/swift/Sources/FlatBuffers/Int+extension.swift b/swift/Sources/FlatBuffers/Int+extension.swift
new file mode 100644
index 00000000..e52bdab6
--- /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 00000000..cdb02278
--- /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<T> {
+ /// 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 00000000..88e3a41a
--- /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<T: Scalar>(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 00000000..0f783bfe
--- /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<Int32>.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<T: Scalar>(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<T: Scalar>(of type: T.Type, offset o: Int32) -> T {
+ let r = bb.read(def: T.self, position: Int(o))
+ return r
+ }
+
+ public func union<T: FlatBufferObject>(_ o: Int32) -> T {
+ let o = o + postion
+ return directUnion(o)
+ }
+
+ public func directUnion<T: FlatBufferObject>(_ o: Int32) -> T {
+ return T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o)))
+ }
+
+ public func getVector<T>(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<Int32>.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<Int32>.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..<minValue {
+ let b = fbb.read(def: Int8.self, position: Int(i + startPos1))
+ let byte = key[Int(i)]
+ if b != byte {
+ return Int32(b - Int8(byte))
+ }
+ }
+ return len1 - len2
+ }
+}
diff --git a/tests/FlatBuffers.Benchmarks.swift/Package.swift b/tests/FlatBuffers.Benchmarks.swift/Package.swift
new file mode 100644
index 00000000..9360b10f
--- /dev/null
+++ b/tests/FlatBuffers.Benchmarks.swift/Package.swift
@@ -0,0 +1,19 @@
+// 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.Benchmarks.swift",
+ platforms: [
+ .macOS(.v10_14)
+ ],
+ dependencies: [
+ .package(path: "../../swift")
+ ],
+ targets: [
+ .target(
+ name: "FlatBuffers.Benchmarks.swift",
+ dependencies: ["FlatBuffers"]),
+ ]
+)
diff --git a/tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift b/tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift
new file mode 100644
index 00000000..2fac8590
--- /dev/null
+++ b/tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift
@@ -0,0 +1,75 @@
+import CoreFoundation
+import FlatBuffers
+
+struct Benchmark {
+ var name: String
+ var value: Double
+
+ var description: String { "\(String(format: "|\t%@\t\t|\t\t%fs\t|", name, value))"}
+}
+
+func run(name: String, runs: Int, action: () -> Void) -> Benchmark {
+ action()
+ let start = CFAbsoluteTimeGetCurrent()
+ for _ in 0..<runs {
+ action()
+ }
+ let ends = CFAbsoluteTimeGetCurrent()
+ let value = Double(ends - start) / Double(runs)
+ print("done \(name): in \(value)")
+ return Benchmark(name: name, value: value)
+}
+
+
+func createDocument(Benchmarks: [Benchmark]) -> 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 00000000..bbe5a6ab
--- /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 00000000..aa8b5aca
--- /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 00000000..486cd1a4
--- /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<UOffset>] = []
+ 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..<monster.inventoryCount {
+ XCTAssertEqual(monster.inventory(at: i), Byte(i + 1))
+ }
+
+ XCTAssertEqual(monster.mutate(inventory: 0, at: 0), true)
+ XCTAssertEqual(monster.mutate(inventory: 1, at: 1), true)
+ XCTAssertEqual(monster.mutate(inventory: 2, at: 2), true)
+ XCTAssertEqual(monster.mutate(inventory: 3, at: 3), true)
+ XCTAssertEqual(monster.mutate(inventory: 4, at: 4), true)
+
+ let vec = monster.pos
+ XCTAssertEqual(vec?.x, 1)
+ XCTAssertTrue(vec?.mutate(x: 55.0) ?? false)
+ XCTAssertTrue(vec?.mutate(test1: 55) ?? false)
+ XCTAssertEqual(vec?.x, 55.0)
+ XCTAssertEqual(vec?.test1, 55.0)
+ XCTAssertTrue(vec?.mutate(x: 1) ?? false)
+ XCTAssertEqual(vec?.x, 1)
+ XCTAssertTrue(vec?.mutate(test1: 3) ?? false)
+ }
+
+ func readMonster(fb: ByteBuffer) {
+ let monster = Monster1.getRootAsMonster(bb: fb)
+ XCTAssertEqual(monster.hp, 80)
+ XCTAssertEqual(monster.mana, 150)
+ XCTAssertEqual(monster.name, "MyMonster")
+ let pos = monster.pos
+ XCTAssertEqual(pos?.x, 1)
+ XCTAssertEqual(pos?.y, 2)
+ XCTAssertEqual(pos?.z, 3)
+ XCTAssertEqual(pos?.test1, 3)
+ XCTAssertEqual(pos?.test2, .green)
+ let test = pos?.test3
+ XCTAssertEqual(test?.a, 5)
+ XCTAssertEqual(test?.b, 6)
+ XCTAssertEqual(monster.testType, .monster)
+ let monster2 = monster.test(type: Monster1.self)
+ XCTAssertEqual(monster2?.name, "Fred")
+
+ XCTAssertEqual(monster.mutate(mana: 10), false)
+
+ XCTAssertEqual(monster.mana, 150)
+ XCTAssertEqual(monster.inventoryCount, 5)
+ var sum: Byte = 0
+ for i in 0...monster.inventoryCount {
+ sum += monster.inventory(at: i)
+ }
+ XCTAssertEqual(sum, 10)
+ XCTAssertEqual(monster.test4Count, 2)
+ let test0 = monster.test4(at: 0)
+ let test1 = monster.test4(at: 1)
+ var sum0 = 0
+ var sum1 = 0
+ if let a = test0?.a, let b = test0?.b {
+ sum0 = Int(a) + Int(b)
+ }
+ if let a = test1?.a, let b = test1?.b {
+ sum1 = Int(a) + Int(b)
+ }
+ XCTAssertEqual(sum0 + sum1, 100)
+ XCTAssertEqual(monster.testarrayofstringCount, 2)
+ XCTAssertEqual(monster.testarrayofstring(at: 0), "test1")
+ XCTAssertEqual(monster.testarrayofstring(at: 1), "test2")
+ XCTAssertEqual(monster.testbool, true)
+
+ let array = monster.nameSegmentArray
+ XCTAssertEqual(String(bytes: array ?? [], encoding: .utf8), "MyMonster")
+
+ if 0 == monster.testarrayofboolsCount {
+ XCTAssertEqual(monster.testarrayofbools.isEmpty, true)
+ } else {
+ XCTAssertEqual(monster.testarrayofbools.isEmpty, false)
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersStructsTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersStructsTests.swift
new file mode 100644
index 00000000..4115706f
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersStructsTests.swift
@@ -0,0 +1,183 @@
+import XCTest
+@testable import FlatBuffers
+
+final class FlatBuffersStructsTests: XCTestCase {
+
+ func testCreatingStruct() {
+ let v = createVecWrite(x: 1.0, y: 2.0, z: 3.0)
+ let b = FlatBufferBuilder(initialSize: 20)
+ let o = b.create(struct: v, type: Vec.self)
+ let end = VPointerVec.createVPointer(b: b, o: o)
+ b.finish(offset: end)
+ XCTAssertEqual(b.sizedByteArray, [12, 0, 0, 0, 0, 0, 6, 0, 4, 0, 4, 0, 6, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64])
+ }
+
+ func testReadingStruct() {
+ let v = createVecWrite(x: 1.0, y: 2.0, z: 3.0)
+ let b = FlatBufferBuilder(initialSize: 20)
+ let o = b.create(struct: v, type: Vec.self)
+ let end = VPointerVec.createVPointer(b: b, o: o)
+ b.finish(offset: end)
+ let buffer = b.sizedByteArray
+ XCTAssertEqual(buffer, [12, 0, 0, 0, 0, 0, 6, 0, 4, 0, 4, 0, 6, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64])
+ let point = VPointerVec.getRootAsCountry(ByteBuffer(bytes: buffer))
+ XCTAssertEqual(point.vec?.z, 3.0)
+ }
+
+ func testCreatingVectorStruct() {
+ let b = FlatBufferBuilder(initialSize: 20)
+ let path = b.createVector(structs: [createVecWrite(x: 1, y: 2, z: 3), createVecWrite(x: 4.0, y: 5.0, z: 6)], type: Vec.self)
+ let end = VPointerVectorVec.createVPointer(b: b, v: path)
+ b.finish(offset: end)
+ XCTAssertEqual(b.sizedByteArray, [12, 0, 0, 0, 8, 0, 8, 0, 0, 0, 4, 0, 8, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64])
+ }
+
+ func testCreatingVectorStructWithForcedDefaults() {
+ let b = FlatBufferBuilder(initialSize: 20, serializeDefaults: true)
+ let path = b.createVector(structs: [createVecWrite(x: 1, y: 2, z: 3), createVecWrite(x: 4.0, y: 5.0, z: 6)], type: Vec.self)
+ let end = VPointerVectorVec.createVPointer(b: b, v: path)
+ b.finish(offset: end)
+ XCTAssertEqual(b.sizedByteArray, [12, 0, 0, 0, 8, 0, 12, 0, 4, 0, 8, 0, 8, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64])
+ }
+
+ func testCreatingEnums() {
+ let b = FlatBufferBuilder(initialSize: 20)
+ let path = b.createVector(structs: [createVecWrite(x: 1, y: 2, z: 3), createVecWrite(x: 4, y: 5, z: 6)], type: Vec.self)
+ let end = VPointerVectorVec.createVPointer(b: b, color: .blue, v: path)
+ b.finish(offset: end)
+ XCTAssertEqual(b.sizedByteArray, [12, 0, 0, 0, 8, 0, 12, 0, 4, 0, 8, 0, 8, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64])
+ }
+
+ func testReadingStructWithEnums() {
+ let b = FlatBufferBuilder(initialSize: 20)
+ let vec = createVec2(x: 1, y: 2, z: 3, color: .red)
+ let o = b.create(struct: vec, type: Vec2.self)
+ let end = VPointerVec2.createVPointer(b: b, o: o, type: .vec)
+ b.finish(offset: end)
+ let buffer = b.sizedByteArray
+ XCTAssertEqual(buffer, [16, 0, 0, 0, 0, 0, 10, 0, 12, 0, 12, 0, 11, 0, 4, 0, 10, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0])
+ let point = VPointerVec2.getRootAsCountry(ByteBuffer(bytes: buffer))
+ XCTAssertEqual(point.vec?.c, Color2.red)
+ XCTAssertEqual(point.vec?.x, 1.0)
+ XCTAssertEqual(point.vec?.y, 2.0)
+ XCTAssertEqual(point.vec?.z, 3.0)
+ XCTAssertEqual(point.UType, Test.vec)
+ }
+
+}
+
+func createVecWrite(x: Float32, y: Float32, z: Float32) -> 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<UOffset> { return Offset(offset: b.endTable(at: s)) }
+
+ static func createVPointer(b: FlatBufferBuilder, o: Offset<UOffset>) -> Offset<UOffset> {
+ 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<UOffset>) { 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<UOffset> { return Offset(offset: b.endTable(at: s)) }
+
+ static func createVPointer(b: FlatBufferBuilder, color: Color = .green, v: Offset<UOffset>) -> Offset<UOffset> {
+ 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<UOffset> { return Offset(offset: b.endTable(at: s)) }
+
+ static func createVPointer(b: FlatBufferBuilder, o: Offset<UOffset>, type: Test) -> Offset<UOffset> {
+ 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 00000000..e8e737e2
--- /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<Int>()
+ let b = Offset<Int>(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<Country> {
+ return createCountry(builder: &builder, offset: builder.create(string: name), log: log, lan: lan)
+ }
+
+ @inlinable static func createCountry(builder: inout FlatBufferBuilder, offset: Offset<String>, log: Int32, lan: Int32) -> Offset<Country> {
+ 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<Country> {
+ 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<String>) {
+ 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 00000000..d6524293
--- /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..<movie.charactersTypeCount {
+ XCTAssertEqual(movie.charactersType(at: i), characterType[Int(i)])
+ }
+
+ XCTAssertEqual(movie.characters(at: 0, type: BookReader.self)?.booksRead, 7)
+ XCTAssertEqual(movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage, swordDmg)
+ XCTAssertEqual(movie.characters(at: 2, type: BookReader.self)?.booksRead, 2)
+ }
+}
+
+public enum ColorsNameSpace {
+
+enum RGB: Int32, Enum {
+ typealias T = Int32
+ static var byteSize: Int { return MemoryLayout<Int32>.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<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: colors, at: 0) }
+ static func endMonster(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(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<UOffset>,
+ hp: Int16,
+ name: Offset<String>,
+ inventory: Offset<UOffset>,
+ color: Color3,
+ weapons: Offset<UOffset>,
+ equipment: Equipment = .none,
+ equippedOffset: Offset<Weapon>,
+ path: Offset<UOffset>) -> Offset<Monster> {
+ 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: FlatBufferObject>() -> 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<UOffset>,
+ equipment: Equipment = .none,
+ equippedOffset: UOffset) -> Offset<Monster> {
+ 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<String>, dmg: Int16) -> Offset<Weapon> {
+ 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<Weapon> {
+ return Offset(offset: builder.endTable(at: startOffset))
+ }
+
+ @inlinable static func add(builder: inout FlatBufferBuilder, name: Offset<String>) {
+ 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 00000000..5e6301ff
--- /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<UOffset> {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbersVector(b: FlatBufferBuilder, array: [Int32]) -> Offset<UOffset> {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbersVector(b: FlatBufferBuilder, array: [Double]) -> Offset<UOffset> {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbersVector(b: FlatBufferBuilder, array: [Float32]) -> Offset<UOffset> {
+ return b.createVector(array, size: array.count)
+ }
+
+ static func createNumbers(b: FlatBufferBuilder, o: Offset<UOffset>) -> Offset<UOffset> {
+ 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 00000000..c044c5ca
--- /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<Country> {
+ return createCountry(builder: &builder, offset: builder.create(string: name), log: log, lan: lan)
+ }
+
+ static func createCountry(builder: inout FlatBufferBuilder, offset: Offset<String>, log: Double, lan: Double) -> Offset<Country> {
+ 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<Country> {
+ 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<String>) {
+ 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 00000000..d53a7a6c
--- /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 00000000..aa6675d7
--- /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<UInt8>.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<Int8>.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<UInt8>.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<UInt8>.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<UInt8>.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<UOffset>, 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<UOffset> { let end = Offset<UOffset>(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<UOffset>, 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<UOffset> { let end = Offset<UOffset>(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<UOffset>, 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<UOffset> { let end = Offset<UOffset>(offset: fbb.endTable(at: start)); return end }
+}
+
+public struct Stat: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset<UOffset>, 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<String>, _ 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<UOffset> { let end = Offset<UOffset>(offset: fbb.endTable(at: start)); return end }
+}
+
+public struct Referrable: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset<UOffset>, 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<UOffset> { let end = Offset<UOffset>(offset: fbb.endTable(at: start)); return end }
+ public static func sortVectorOfReferrable(offsets:[Offset<UOffset>], _ fbb: FlatBufferBuilder) -> Offset<UOffset> {
+ 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<UOffset>, 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<T: FlatBufferObject>(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<T: FlatBufferObject>(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<T: FlatBufferObject>(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<UOffset>, _ 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<String>, _ fbb: FlatBufferBuilder) { fbb.add(offset: name, at: 3) }
+ public static func addVectorOf(inventory: Offset<UOffset>, _ 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<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: test, at: 8) }
+ public static func addVectorOf(test4: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: test4, at: 9) }
+ public static func addVectorOf(testarrayofstring: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayofstring, at: 10) }
+ public static func addVectorOf(testarrayoftables: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayoftables, at: 11) }
+ public static func add(enemy: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: enemy, at: 12) }
+ public static func addVectorOf(testnestedflatbuffer: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: testnestedflatbuffer, at: 13) }
+ public static func add(testempty: Offset<UOffset>, _ 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<UOffset>, _ 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<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayofstring2, at: 28) }
+ public static func addVectorOf(testarrayofsortedstruct: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: testarrayofsortedstruct, at: 29) }
+ public static func addVectorOf(flex: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: flex, at: 30) }
+ public static func addVectorOf(test5: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: test5, at: 31) }
+ public static func addVectorOf(vectorOfLongs: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfLongs, at: 32) }
+ public static func addVectorOf(vectorOfDoubles: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfDoubles, at: 33) }
+ public static func add(parentNamespaceTest: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: parentNamespaceTest, at: 34) }
+ public static func addVectorOf(vectorOfReferrables: Offset<UOffset>, _ 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<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: vectorOfWeakReferences, at: 37) }
+ public static func addVectorOf(vectorOfStrongReferrables: Offset<UOffset>, _ 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<UOffset>, _ 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<UOffset>, _ 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<UOffset>, _ 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<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: anyAmbiguous, at: 46) }
+ public static func addVectorOf(vectorOfEnums: Offset<UOffset>, _ 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<UOffset> { let end = Offset<UOffset>(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [10]); return end }
+ public static func sortVectorOfMonster(offsets:[Offset<UOffset>], _ fbb: FlatBufferBuilder) -> Offset<UOffset> {
+ 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<UOffset>, 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<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: v8, at: 10) }
+ public static func addVectorOf(vf64: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: vf64, at: 11) }
+ public static func endTypeAliases(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(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 00000000..c1c6aca9
--- /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<UInt8>.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<UOffset>, 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<UOffset> { let end = Offset<UOffset>(offset: fbb.endTable(at: start)); return end }
+}
+
+public struct Movie: FlatBufferObject {
+ private var _accessor: Table
+ public static func finish(_ fbb: FlatBufferBuilder, end: Offset<UOffset>, 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<T: FlatBufferObject>(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<T: FlatBufferObject>(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<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: mainCharacter, at: 1) }
+ public static func addVectorOf(charactersType: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: charactersType, at: 2) }
+ public static func addVectorOf(characters: Offset<UOffset>, _ fbb: FlatBufferBuilder) { fbb.add(offset: characters, at: 3) }
+ public static func endMovie(_ fbb: FlatBufferBuilder, start: UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(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 00000000..1b16a78e
--- /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 00000000..ba6cf278
--- /dev/null
+++ b/tests/FlatBuffers.Test.Swift/monsterdata_test.mon
Binary files differ
diff --git a/tests/TestAll.sh b/tests/TestAll.sh
index 0fc0acdb..e20431c3 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 00000000..e98e4be1
--- /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