Commit 04d80f25 authored by mustiikhalil's avatar mustiikhalil Committed by Wouter van Oortmerssen

[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
parent 55686100
*_wire.txt
*_wire.bin
.DS_Store
**/.build
**/Packages
/*.xcodeproj
**/xcuserdata/
**/xcshareddata/
**/.swiftpm/
*.o
*.o.d
*.class
......
......@@ -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
......
......@@ -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
......
......@@ -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.
......
......@@ -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>
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>
This diff is collapsed.
......@@ -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,
......
// 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
......@@ -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 = [
......
......@@ -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;
......
......@@ -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
......
This diff is collapsed.
......@@ -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 {
......
// 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: []),
]
)
This diff is collapsed.
#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
}
This diff is collapsed.
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 {}
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)
}
}
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)
}
}
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 }
}
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
}
}
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
}
}
// 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"]),
]
)
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)
// 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"]),
]
)
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
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)
}
}
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)
}
}
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))
}
}
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)
}
}
#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
// 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 }
}
import XCTest
import FlatBuffers_Test_SwiftTests
var tests = [XCTestCaseEntry]()
tests += FlatBuffers_Test_SwiftTests.__allTests()
XCTMain(tests)
......@@ -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
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment