forked from BigfootDev/flatbuffers
Improves documentation, and adding DocC (#6784)
Finished documenting flatbuffersbuilder Replaces swift 5.5 with 5.2 packages Starts building the tutorial for xcode 13 Finishes building the tutorial for xcode 13 Removes docc files from old swift versions Updates swift style guide
This commit is contained in:
@@ -37,7 +37,8 @@ func greet(name: String, client greeter: models_GreeterServiceClient) {
|
||||
builder.finish(offset: root)
|
||||
|
||||
// Make the RPC call to the server.
|
||||
let sayHello = greeter.SayHello(Message<models_HelloRequest>(builder: &builder))
|
||||
let sayHello = greeter
|
||||
.SayHello(Message<models_HelloRequest>(builder: &builder))
|
||||
|
||||
// wait() on the response to stop the program from exiting before the response is received.
|
||||
do {
|
||||
@@ -54,7 +55,8 @@ func greet(name: String, client greeter: models_GreeterServiceClient) {
|
||||
builder.finish(offset: manyRoot)
|
||||
|
||||
let call = greeter.SayManyHellos(Message(builder: &builder)) { message in
|
||||
print("Greeter SayManyHellos received: \(message.object.message ?? "Unknown")")
|
||||
print(
|
||||
"Greeter SayManyHellos received: \(message.object.message ?? "Unknown")")
|
||||
}
|
||||
|
||||
let status = try! call.status.recover { _ in .processingError }.wait()
|
||||
|
||||
@@ -32,7 +32,8 @@ class Greeter: models_GreeterProvider {
|
||||
|
||||
func SayHello(
|
||||
request: Message<models_HelloRequest>,
|
||||
context: StatusOnlyCallContext) -> EventLoopFuture<Message<models_HelloReply>>
|
||||
context: StatusOnlyCallContext)
|
||||
-> EventLoopFuture<Message<models_HelloReply>>
|
||||
{
|
||||
let recipient = request.object.name ?? "Stranger"
|
||||
|
||||
@@ -40,17 +41,22 @@ class Greeter: models_GreeterProvider {
|
||||
let off = builder.create(string: "Hello \(recipient)")
|
||||
let root = models_HelloReply.createHelloReply(&builder, messageOffset: off)
|
||||
builder.finish(offset: root)
|
||||
return context.eventLoop.makeSucceededFuture(Message<models_HelloReply>(builder: &builder))
|
||||
return context.eventLoop
|
||||
.makeSucceededFuture(Message<models_HelloReply>(builder: &builder))
|
||||
}
|
||||
|
||||
func SayManyHellos(
|
||||
request: Message<models_HelloRequest>,
|
||||
context: StreamingResponseCallContext<Message<models_HelloReply>>) -> EventLoopFuture<GRPCStatus>
|
||||
context: StreamingResponseCallContext<Message<models_HelloReply>>)
|
||||
-> EventLoopFuture<GRPCStatus>
|
||||
{
|
||||
for name in greetings {
|
||||
var builder = FlatBufferBuilder()
|
||||
let off = builder.create(string: "\(name) \(request.object.name ?? "Unknown")")
|
||||
let root = models_HelloReply.createHelloReply(&builder, messageOffset: off)
|
||||
let off = builder
|
||||
.create(string: "\(name) \(request.object.name ?? "Unknown")")
|
||||
let root = models_HelloReply.createHelloReply(
|
||||
&builder,
|
||||
messageOffset: off)
|
||||
builder.finish(offset: root)
|
||||
_ = context.sendResponse(Message<models_HelloReply>(builder: &builder))
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
--typeattributes prev-line # wrapAttributes
|
||||
|
||||
# rules
|
||||
--rules todos,anyObjectProtocol,redundantParens,redundantReturn,redundantSelf,sortedImports,strongifiedSelf,trailingCommas,trailingSpace,wrapArguments,wrapMultilineStatementBraces,indent,wrapAttributes,void,fileHeader
|
||||
--rules wrap,todos,anyObjectProtocol,redundantParens,redundantReturn,redundantSelf,sortedImports,strongifiedSelf,trailingCommas,trailingSpace,wrapArguments,wrapMultilineStatementBraces,indent,wrapAttributes,void,fileHeader
|
||||
--disable trailingclosures
|
||||
|
||||
--exclude **/*_generated.swift
|
||||
--exclude **/swift_code_*.swift
|
||||
--exclude **/*.grpc.swift
|
||||
|
||||
--header "/*\n * Copyright {year} Google Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */"
|
||||
@@ -31,5 +31,6 @@ let package = Package(
|
||||
targets: [
|
||||
.target(
|
||||
name: "FlatBuffers",
|
||||
dependencies: []),
|
||||
dependencies: [],
|
||||
exclude: ["Documentation.docc/Resources/code/swift"]),
|
||||
])
|
||||
|
||||
36
swift/Package@swift-5.5.swift
Normal file
36
swift/Package@swift-5.5.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
// swift-tools-version:5.5
|
||||
/*
|
||||
* Copyright 2020 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "FlatBuffers",
|
||||
platforms: [
|
||||
.iOS(.v11),
|
||||
.macOS(.v10_14),
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "FlatBuffers",
|
||||
targets: ["FlatBuffers"]),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "FlatBuffers",
|
||||
dependencies: []),
|
||||
])
|
||||
|
||||
@@ -164,7 +164,10 @@ public struct ByteBuffer {
|
||||
/// Constructor that creates a Flatbuffer from unsafe memory region without copying
|
||||
/// - Parameter assumingMemoryBound: The unsafe memory region
|
||||
/// - Parameter capacity: The size of the given memory region
|
||||
public init(assumingMemoryBound memory: UnsafeMutableRawPointer, capacity: Int) {
|
||||
public init(
|
||||
assumingMemoryBound memory: UnsafeMutableRawPointer,
|
||||
capacity: Int)
|
||||
{
|
||||
_storage = Storage(memory: memory, capacity: capacity, unowned: true)
|
||||
_writerSize = capacity
|
||||
}
|
||||
@@ -244,7 +247,10 @@ public struct ByteBuffer {
|
||||
@usableFromInline
|
||||
mutating func push(string str: String, len: Int) {
|
||||
ensureSpace(size: len)
|
||||
if str.utf8.withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != nil {
|
||||
if str.utf8
|
||||
.withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) !=
|
||||
nil
|
||||
{
|
||||
} else {
|
||||
let utf8View = str.utf8
|
||||
for c in utf8View.reversed() {
|
||||
@@ -304,7 +310,9 @@ public struct ByteBuffer {
|
||||
/// - Parameter size: size of the `VTable`
|
||||
@inline(__always)
|
||||
mutating func pop(_ size: Int) {
|
||||
assert((_writerSize &- size) > 0, "New size should NOT be a negative number")
|
||||
assert(
|
||||
(_writerSize &- size) > 0,
|
||||
"New size should NOT be a negative number")
|
||||
memset(_storage.memory.advanced(by: writerIndex), 0, _writerSize &- size)
|
||||
_writerSize = size
|
||||
}
|
||||
@@ -341,7 +349,8 @@ public struct ByteBuffer {
|
||||
assert(
|
||||
index + count <= _storage.capacity,
|
||||
"Reading out of bounds is illegal")
|
||||
let start = _storage.memory.advanced(by: index).assumingMemoryBound(to: T.self)
|
||||
let start = _storage.memory.advanced(by: index)
|
||||
.assumingMemoryBound(to: T.self)
|
||||
let array = UnsafeBufferPointer(start: start, count: count)
|
||||
return Array(array)
|
||||
}
|
||||
@@ -359,7 +368,8 @@ public struct ByteBuffer {
|
||||
assert(
|
||||
index + count <= _storage.capacity,
|
||||
"Reading out of bounds is illegal")
|
||||
let start = _storage.memory.advanced(by: index).assumingMemoryBound(to: UInt8.self)
|
||||
let start = _storage.memory.advanced(by: index)
|
||||
.assumingMemoryBound(to: UInt8.self)
|
||||
let bufprt = UnsafeBufferPointer(start: start, count: count)
|
||||
return String(bytes: Array(bufprt), encoding: type)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ import Foundation
|
||||
#endif
|
||||
|
||||
/// A boolean to see if the system is littleEndian
|
||||
let isLitteEndian = CFByteOrderGetCurrent() == Int(CFByteOrderLittleEndian.rawValue)
|
||||
let isLitteEndian = CFByteOrderGetCurrent() ==
|
||||
Int(CFByteOrderLittleEndian.rawValue)
|
||||
/// Constant for the file id length
|
||||
let FileIdLength = 4
|
||||
/// Type aliases
|
||||
@@ -30,7 +31,8 @@ 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)
|
||||
public let FlatBufferMaxSize = UInt32
|
||||
.max << ((MemoryLayout<SOffset>.size * 8 - 1) - 1)
|
||||
|
||||
/// Protocol that All Scalars should conform to
|
||||
///
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# ``FlatBuffers``
|
||||
|
||||
FlatBuffers: Memory Efficient Serialization Library
|
||||
|
||||
## Overview
|
||||
|
||||
- Access to serialized data without parsing/unpacking - What sets FlatBuffers apart is that it represents hierarchical data in a flat binary buffer in such a way that it can still be accessed directly without parsing/unpacking, while also still supporting data structure evolution (forwards/backwards compatibility).
|
||||
- Memory efficiency and speed - The only memory needed to access your data is that of the buffer. It requires 0 additional allocations (in C++, other languages may vary). FlatBuffers is also very suitable for use with mmap (or streaming), requiring only part of the buffer to be in memory. Access is close to the speed of raw struct access with only one extra indirection (a kind of vtable) to allow for format evolution and optional fields. It is aimed at projects where spending time and space (many memory allocations) to be able to access or construct serialized data is undesirable, such as in games or any other performance sensitive applications. See the benchmarks for details.
|
||||
- Flexible - Optional fields means not only do you get great forwards and backwards compatibility (increasingly important for long-lived games: don't have to update all data with each new version!). It also means you have a lot of choice in what data you write and what data you don't, and how you design data structures.
|
||||
- Tiny code footprint - Small amounts of generated code, and just a single small header as the minimum dependency, which is very easy to integrate. Again, see the benchmark section for details.
|
||||
- Strongly typed - Errors happen at compile time rather than manually having to write repetitive and error prone run-time checks. Useful code can be generated for you.
|
||||
|
||||
## Topics
|
||||
|
||||
### Read this first
|
||||
|
||||
- <doc:Tutorial_Table_of_Contents>
|
||||
|
||||
### Where to start
|
||||
|
||||
- ``FlatBufferBuilder``
|
||||
- ``ByteBuffer``
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
enum Color:byte { red, green, blue }
|
||||
@@ -0,0 +1,6 @@
|
||||
enum Color:byte { red, green, blue }
|
||||
|
||||
struct Vec3 {
|
||||
x:float;
|
||||
y:float;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
enum Color:byte { red, green, blue }
|
||||
|
||||
struct Vec3 {
|
||||
x:float;
|
||||
y:float;
|
||||
}
|
||||
|
||||
table Monster {
|
||||
pos:Vec3;
|
||||
color:Color = Blue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
enum Color:byte { red, green, blue }
|
||||
|
||||
struct Vec3 {
|
||||
x:float;
|
||||
y:float;
|
||||
}
|
||||
|
||||
table Monster {
|
||||
pos:Vec3;
|
||||
color:Color = Blue;
|
||||
|
||||
mana:short = 150;
|
||||
hp:short = 100;
|
||||
name:string;
|
||||
equipped:Equipment;
|
||||
weapons:[Weapon];
|
||||
path:[Vec3];
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
enum Color:byte { red, green, blue }
|
||||
|
||||
union Equipment { Weapon } // Optionally add more tables.
|
||||
|
||||
struct Vec3 {
|
||||
x:float;
|
||||
y:float;
|
||||
}
|
||||
|
||||
table Monster {
|
||||
pos:Vec3;
|
||||
color:Color = Blue;
|
||||
|
||||
mana:short = 150;
|
||||
hp:short = 100;
|
||||
name:string;
|
||||
equipped:Equipment;
|
||||
weapons:[Weapon];
|
||||
path:[Vec3];
|
||||
}
|
||||
|
||||
table Weapon {
|
||||
name:string;
|
||||
damage:short;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
enum Color:byte { red, green, blue }
|
||||
|
||||
union Equipment { Weapon } // Optionally add more tables.
|
||||
|
||||
struct Vec3 {
|
||||
x:float;
|
||||
y:float;
|
||||
}
|
||||
|
||||
table Monster {
|
||||
pos:Vec3;
|
||||
color:Color = Blue;
|
||||
|
||||
mana:short = 150;
|
||||
hp:short = 100;
|
||||
name:string;
|
||||
equipped:Equipment;
|
||||
weapons:[Weapon];
|
||||
path:[Vec3];
|
||||
}
|
||||
|
||||
table Weapon {
|
||||
name:string;
|
||||
damage:short;
|
||||
}
|
||||
|
||||
root_type Monster; // flatc --swift monster.fbs
|
||||
@@ -0,0 +1 @@
|
||||
import Foundation
|
||||
@@ -0,0 +1,71 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
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)
|
||||
|
||||
// Create a FlatBuffer `vector` that contains offsets to the sword and axe
|
||||
// we created above.
|
||||
let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
|
||||
|
||||
// Name of the Monster.
|
||||
let name = builder.create(string: "Orc")
|
||||
|
||||
let pathOffset = fbb.createVector(ofStructs: [
|
||||
Vec3(x: 0, y: 0),
|
||||
Vec3(x: 5, y: 5),
|
||||
])
|
||||
|
||||
// startVector(len, elementSize: MemoryLayout<Offset>.size)
|
||||
// for o in offsets.reversed() {
|
||||
// push(element: o)
|
||||
// }
|
||||
// endVector(len: len)
|
||||
|
||||
let orc = Monster.createMonster(
|
||||
&builder,
|
||||
pos: Vec3(x: 1, y: 2),
|
||||
hp: 300,
|
||||
nameOffset: name,
|
||||
color: .red,
|
||||
weaponsVectorOffset: weaponsOffset,
|
||||
equippedType: .weapon,
|
||||
equippedOffset: axe,
|
||||
pathOffset: pathOffset)
|
||||
|
||||
// let start = Monster.startMonster(&builder)
|
||||
// Monster.add(pos: Vec3(x: 1, y: 2), &builder)
|
||||
// Monster.add(hp: 300, &builder)
|
||||
// Monster.add(name: name, &builder)
|
||||
// Monster.add(color: .red, &builder)
|
||||
// Monster.addVectorOf(weapons: weaponsOffset, &builder)
|
||||
// Monster.add(equippedType: .weapon, &builder)
|
||||
// Monster.addVectorOf(paths: weaponsOffset, &builder)
|
||||
// Monster.add(equipped: axe, &builder)
|
||||
// var orc = Monster.endMonster(&builder, start: start)
|
||||
|
||||
// Call `finish(offset:)` to instruct the builder that this monster is complete.
|
||||
builder.finish(offset: orc)
|
||||
// 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.sizedBuffer)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// 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 = try! getCheckedRoot(byteBuffer: ByteBuffer(bytes: buf))
|
||||
// let monster: Monster = getRoot(byteBuffer: ByteBuffer(bytes: buf))
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// 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 = try! getCheckedRoot(byteBuffer: ByteBuffer(bytes: buf))
|
||||
// let monster: Monster = getRoot(byteBuffer: ByteBuffer(bytes: buf))
|
||||
|
||||
let hp = monster.hp
|
||||
let mana = monster.mana
|
||||
let name = monster.name // returns an optional string
|
||||
|
||||
let pos = monster.pos
|
||||
let x = pos.x
|
||||
let y = pos.y
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// 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 = try! getCheckedRoot(byteBuffer: ByteBuffer(bytes: buf))
|
||||
// let monster: Monster = getRoot(byteBuffer: ByteBuffer(bytes: buf))
|
||||
|
||||
let hp = monster.hp
|
||||
let mana = monster.mana
|
||||
let name = monster.name // returns an optional string
|
||||
|
||||
let pos = monster.pos
|
||||
let x = pos.x
|
||||
let y = pos.y
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
@@ -0,0 +1,7 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
let weapon1Name = builder.create(string: "Sword")
|
||||
let weapon2Name = builder.create(string: "Axe")
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
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)
|
||||
|
||||
// Create a FlatBuffer `vector` that contains offsets to the sword and axe
|
||||
// we created above.
|
||||
let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
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)
|
||||
|
||||
// Create a FlatBuffer `vector` that contains offsets to the sword and axe
|
||||
// we created above.
|
||||
let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
|
||||
|
||||
// Name of the Monster.
|
||||
let name = builder.create(string: "Orc")
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
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)
|
||||
|
||||
// Create a FlatBuffer `vector` that contains offsets to the sword and axe
|
||||
// we created above.
|
||||
let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
|
||||
|
||||
// Name of the Monster.
|
||||
let name = builder.create(string: "Orc")
|
||||
|
||||
let pathOffset = fbb.createVector(ofStructs: [
|
||||
Vec3(x: 0, y: 0),
|
||||
Vec3(x: 5, y: 5),
|
||||
])
|
||||
|
||||
// startVector(len, elementSize: MemoryLayout<Offset>.size)
|
||||
// for o in offsets.reversed() {
|
||||
// push(element: o)
|
||||
// }
|
||||
// endVector(len: len)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
|
||||
func run() {
|
||||
// create a `FlatBufferBuilder`, which will be used to serialize objects
|
||||
let builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
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)
|
||||
|
||||
// Create a FlatBuffer `vector` that contains offsets to the sword and axe
|
||||
// we created above.
|
||||
let weaponsOffset = builder.createVector(ofOffsets: [sword, axe])
|
||||
|
||||
// Name of the Monster.
|
||||
let name = builder.create(string: "Orc")
|
||||
|
||||
let pathOffset = fbb.createVector(ofStructs: [
|
||||
Vec3(x: 0, y: 0),
|
||||
Vec3(x: 5, y: 5),
|
||||
])
|
||||
|
||||
// startVector(len, elementSize: MemoryLayout<Offset>.size)
|
||||
// for o in offsets.reversed() {
|
||||
// push(element: o)
|
||||
// }
|
||||
// endVector(len: len)
|
||||
|
||||
let orc = Monster.createMonster(
|
||||
&builder,
|
||||
pos: Vec3(x: 1, y: 2),
|
||||
hp: 300,
|
||||
nameOffset: name,
|
||||
color: .red,
|
||||
weaponsVectorOffset: weaponsOffset,
|
||||
equippedType: .weapon,
|
||||
equippedOffset: axe,
|
||||
pathOffset: pathOffset)
|
||||
|
||||
// let start = Monster.startMonster(&builder)
|
||||
// Monster.add(pos: Vec3(x: 1, y: 2), &builder)
|
||||
// Monster.add(hp: 300, &builder)
|
||||
// Monster.add(name: name, &builder)
|
||||
// Monster.add(color: .red, &builder)
|
||||
// Monster.addVectorOf(weapons: weaponsOffset, &builder)
|
||||
// Monster.add(equippedType: .weapon, &builder)
|
||||
// Monster.addVectorOf(paths: weaponsOffset, &builder)
|
||||
// Monster.add(equipped: axe, &builder)
|
||||
// var orc = Monster.endMonster(&builder, start: start)
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,14 @@
|
||||
@Tutorials(name: "Starting with FlatBuffers") {
|
||||
@Intro(title: "Starting with FlatBuffers") {
|
||||
FlatBuffers is an efficient cross platform 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.
|
||||
}
|
||||
@Chapter(name: "Generating your code") {
|
||||
Start by generating your first FlatBuffers objects.
|
||||
@Image(source: tutorial_cover_image_1.png, alt: "A code structure for a base struct in flatbuffers")
|
||||
@TutorialReference(tutorial: "doc:creating_flatbuffer_schema")
|
||||
@TutorialReference(tutorial: "doc:create_your_first_buffer")
|
||||
@TutorialReference(tutorial: "doc:reading_bytebuffer")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
@Tutorial(time: 5) {
|
||||
@Intro(title: "After having our code generated") {
|
||||
After generating the code from the previous section, we will know start creating our monster object.
|
||||
We will create a monster object called orc.
|
||||
}
|
||||
|
||||
@Section(title: "Building your first buffer") {
|
||||
@ContentAndMedia {}
|
||||
@Steps {
|
||||
@Step {
|
||||
Starting with a new file, we will create our very first Flatbuffer.
|
||||
@Code(name: "ViewController.swift", file: "swift_code_1.swift")
|
||||
}
|
||||
@Step {
|
||||
First, we need to import ``FlatBuffers``
|
||||
@Code(name: "ViewController.swift", file: "swift_code_2.swift")
|
||||
}
|
||||
@Step {
|
||||
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), which will grow automatically if needed.
|
||||
@Code(name: "ViewController.swift", file: "swift_code_3.swift")
|
||||
}
|
||||
@Step {
|
||||
After creating the builder, we can start serializing our data. Before we make our orc Monster,
|
||||
let's create some Weapons: a Sword and an Axe. However we will start by naming our weapons as `Sword` and `Axe`
|
||||
@Code(name: "ViewController.swift", file: "swift_code_4.swift")
|
||||
}
|
||||
@Step {
|
||||
After naming the weapons, we will create two weapon objects with the damage that the weapon is going to deal.
|
||||
That's done by calling the `start` Method on each table you will be creating, in this case its called `startWeapon`
|
||||
and finished by calling `end`.
|
||||
@Code(name: "ViewController.swift", file: "swift_code_5.swift")
|
||||
}
|
||||
@Step {
|
||||
We will take our (Sword and Axe) serialized data and serialize their offsets as a vector of tables into our `ByteBuffer`.
|
||||
So we can reference them later on from our Monster Object
|
||||
@Code(name: "ViewController.swift", file: "swift_code_6.swift")
|
||||
}
|
||||
@Step {
|
||||
We will add our Monster name as a string value just like we did with the weapons.
|
||||
@Code(name: "ViewController.swift", file: "swift_code_7.swift")
|
||||
}
|
||||
|
||||
@Step {
|
||||
We will create a path that our monster should be using while roaming in its den. To create a vector of paths we would us
|
||||
`createVector(ofStructs: [])` which will take a Native `Swift` struct that has been padded to fit the `FlatBuffers` standards.
|
||||
|
||||
There are usually two ways of creating vectors in `FlatBuffers` which you can see in commented out code.
|
||||
And thus there are multiple convenience methods that will cover all the bases
|
||||
when trying to create a vector so that you dont have to create it with `start` and `end`
|
||||
@Code(name: "ViewController.swift", file: "swift_code_8.swift")
|
||||
}
|
||||
|
||||
@Step {
|
||||
Now to serialize our data into our `Monster` object. Which again there are two ways of doing, by calling the `create` method or
|
||||
by serializing the objects yourself. What we added to our Monster were the `Equipped Type` and the `Equipped` union itself, which
|
||||
allows the Monster to have the `Axe` as his equipped weapon.
|
||||
|
||||
Important: Unlike structs, you should not nest tables or other objects,
|
||||
which is why we created all the `strings/vectors/tables` that this monster refers to before start.
|
||||
If you try to create any of them between start and end, you will get an `assert`.
|
||||
@Code(name: "ViewController.swift", file: "swift_code_9.swift")
|
||||
}
|
||||
|
||||
@Step {
|
||||
Finally you can just finalize the buffer by calling `builder.finish` and get the Byte array from the buffer.
|
||||
@Code(name: "ViewController.swift", file: "swift_code_10.swift")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
@Tutorial(time: 2) {
|
||||
@Intro(title: "Creating a schema") {
|
||||
You will need to have the FlatBuffer compiler to be installed on your device
|
||||
}
|
||||
|
||||
@Section(title: "Creating a schema") {
|
||||
@ContentAndMedia {}
|
||||
@Steps {
|
||||
@Step {
|
||||
Start by creating a new empty folder called `monster.fbs`. We want to create a Monster table, that contains
|
||||
position, color, and basic information about the monster.
|
||||
@Code(name: "monster.fbs", file: "monster_step_1.fbs")
|
||||
}
|
||||
@Step {
|
||||
We will start by adding our Color object. We will be using an enumerate, to represent this object
|
||||
@Code(name: "monster.fbs", file: "monster_step_2.fbs")
|
||||
}
|
||||
@Step {
|
||||
We will add a position object and will use a struct to represent that type of data. Where we will need the monsters
|
||||
x and y positions.
|
||||
@Code(name: "monster.fbs", file: "monster_step_3.fbs")
|
||||
}
|
||||
@Step {
|
||||
Then we will be creating our Monster object of type table. This will contain the current position of our
|
||||
monster and its color
|
||||
@Code(name: "monster.fbs", file: "monster_step_4.fbs")
|
||||
}
|
||||
@Step {
|
||||
Our Monster is missing a name, mana, hp, name, equipped Weapon, weapons, and path. We will be adding these
|
||||
fields to our table with a proper data type for each. Example; weapons, and path would be a vector of data.
|
||||
@Code(name: "monster.fbs", file: "monster_step_5.fbs")
|
||||
}
|
||||
@Step {
|
||||
Now we are missing two data types here, `Weapon` and `Equipment`. And since Equipment can be a weapon, we will be using
|
||||
a `Union` enumerate that can contain all the equipment that you would want your monster to have. And the weapon can simply
|
||||
have a name and amount of damage
|
||||
@Code(name: "monster.fbs", file: "monster_step_6.fbs")
|
||||
}
|
||||
@Step {
|
||||
And to finalize our monster table, we can add a root type of type Monster.
|
||||
Then run the command `flatc --swift monster.fbs`
|
||||
Note: Make sure to import the file to your xcode project.
|
||||
@Code(name: "monster.fbs", file: "monster_step_7.fbs")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@Tutorial(time: 2) {
|
||||
@Intro(title: "Reading ByteBuffers") {
|
||||
After getting our ByteBuffer created, we can now read it.
|
||||
}
|
||||
|
||||
@Section(title: "Reading your first buffer") {
|
||||
@ContentAndMedia {}
|
||||
@Steps {
|
||||
@Step {
|
||||
After fetching the data from disk or network you need to access that data, and that can be done.
|
||||
By simply calling `getCheckedRoot`, which checks if the data is valid before enabling you to read from a corrupt buffer.
|
||||
however, if you are sure that the data is 100% correct you can simply call `getRoot`
|
||||
@Code(name: "ViewController.swift", file: "swift_code_11.swift")
|
||||
}
|
||||
@Step {
|
||||
Now since we have a Monster object, all the fields can be accessed by simply fetching the data. Note, Deprecated fields will not
|
||||
show up
|
||||
@Code(name: "ViewController.swift", file: "swift_code_12.swift")
|
||||
}
|
||||
@Step {
|
||||
And you can access union types as easy as this
|
||||
@Code(name: "ViewController.swift", file: "swift_code_13.swift")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
import Foundation
|
||||
|
||||
/// Enum is a protocol that all flatbuffers enums should conform to
|
||||
/// Since it allows us to get the actual `ByteSize` and `Value`
|
||||
/// Since it allows us to get the actual `ByteSize` and `Value` from
|
||||
/// a swift enum.
|
||||
public protocol Enum {
|
||||
/// associatedtype that the type of the enum should conform to
|
||||
associatedtype T: Scalar & Verifiable
|
||||
|
||||
@@ -16,9 +16,16 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// `FlatBufferBuilder` builds a `FlatBuffer` through manipulating its internal state.
|
||||
/// This is done by creating a `ByteBuffer` that hosts the incoming data and
|
||||
/// has a hardcoded growth limit of `2GiB` which is set by the Flatbuffers standards
|
||||
/// ``FlatBufferBuilder`` builds a `FlatBuffer` through manipulating its internal state.
|
||||
///
|
||||
/// This is done by creating a ``ByteBuffer`` that hosts the incoming data and
|
||||
/// has a hardcoded growth limit of `2GiB` which is set by the Flatbuffers standards.
|
||||
///
|
||||
/// ```swift
|
||||
/// var builder = FlatBufferBuilder()
|
||||
/// ```
|
||||
/// The builder should be always created as a variable, since it would be passed into the writers
|
||||
///
|
||||
@frozen
|
||||
public struct FlatBufferBuilder {
|
||||
|
||||
@@ -47,21 +54,30 @@ public struct FlatBufferBuilder {
|
||||
|
||||
/// Gives a read access to the buffer's size
|
||||
public var size: UOffset { _bb.size }
|
||||
|
||||
/// Data representation of the buffer
|
||||
///
|
||||
/// Should only be used after ``finish(offset:addPrefix:)`` is called
|
||||
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
|
||||
|
||||
/// Returns the underlying bytes in the ``ByteBuffer``
|
||||
///
|
||||
/// Note: This should be used with caution.
|
||||
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
|
||||
|
||||
/// Returns the written bytes into the ``ByteBuffer``
|
||||
///
|
||||
/// Should only be used after ``finish(offset:addPrefix:)`` is called
|
||||
public var sizedByteArray: [UInt8] {
|
||||
assert(finished, "Data shouldn't be called before finish()")
|
||||
let cp = _bb.capacity &- _bb.writerIndex
|
||||
@@ -71,10 +87,17 @@ public struct FlatBufferBuilder {
|
||||
let ptr = UnsafeBufferPointer(start: start, count: cp)
|
||||
return Array(ptr)
|
||||
}
|
||||
/// Returns the buffer
|
||||
|
||||
/// Returns the original ``ByteBuffer``
|
||||
///
|
||||
/// Returns the current buffer that was just created
|
||||
/// with the offsets, and data written to it.
|
||||
public var buffer: ByteBuffer { _bb }
|
||||
|
||||
/// Returns A sized Buffer from the readable bytes
|
||||
/// Returns a newly created sized ``ByteBuffer``
|
||||
///
|
||||
/// returns a new buffer that is sized to the data written
|
||||
/// to the main buffer
|
||||
public var sizedBuffer: ByteBuffer {
|
||||
assert(finished, "Data shouldn't be called before finish()")
|
||||
return ByteBuffer(
|
||||
@@ -84,20 +107,28 @@ public struct FlatBufferBuilder {
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
/// initialize the buffer with a size
|
||||
/// 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) {
|
||||
///
|
||||
/// This initializes a new builder with an initialSize that would initialize
|
||||
/// a new ``ByteBuffer``. ``FlatBufferBuilder`` by default doesnt serialize defaults
|
||||
/// however the builder can be force by passing true for `serializeDefaults`
|
||||
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")
|
||||
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
|
||||
/// Clears the builder and the buffer from the written data.
|
||||
mutating public func clear() {
|
||||
_minAlignment = 0
|
||||
isNested = false
|
||||
@@ -113,6 +144,9 @@ public struct FlatBufferBuilder {
|
||||
/// - Parameters:
|
||||
/// - table: offset for the table
|
||||
/// - fields: Array of all the important fields to be serialized
|
||||
///
|
||||
/// *NOTE: Never call this function, this is only supposed to be called
|
||||
/// by the generated code*
|
||||
mutating public func require(table: Offset, fields: [Int32]) {
|
||||
for field in fields {
|
||||
let start = _bb.capacity &- Int(table.o)
|
||||
@@ -129,6 +163,23 @@ public struct FlatBufferBuilder {
|
||||
/// - offset: Offset of the table
|
||||
/// - fileId: Takes the fileId
|
||||
/// - prefix: if false it wont add the size of the buffer
|
||||
///
|
||||
/// ``finish(offset:fileId:addPrefix:)`` should be called at the end of creating
|
||||
/// a table
|
||||
/// ```swift
|
||||
/// var root = SomeObject
|
||||
/// .createObject(&builder,
|
||||
/// name: nameOffset)
|
||||
/// builder.finish(
|
||||
/// offset: root,
|
||||
/// fileId: "ax1a",
|
||||
/// addPrefix: true)
|
||||
/// ```
|
||||
/// File id would append a file id name at the end of the written bytes before,
|
||||
/// finishing the buffer.
|
||||
///
|
||||
/// Whereas, if `addPrefix` is true, the written bytes would
|
||||
/// include the size of the current buffer.
|
||||
mutating public func finish(
|
||||
offset: Offset,
|
||||
fileId: String,
|
||||
@@ -147,6 +198,19 @@ public struct FlatBufferBuilder {
|
||||
/// - Parameters:
|
||||
/// - offset: Offset of the table
|
||||
/// - prefix: if false it wont add the size of the buffer
|
||||
///
|
||||
/// ``finish(offset:addPrefix:)`` should be called at the end of creating
|
||||
/// a table
|
||||
/// ```swift
|
||||
/// var root = SomeObject
|
||||
/// .createObject(&builder,
|
||||
/// name: nameOffset)
|
||||
/// builder.finish(
|
||||
/// offset: root,
|
||||
/// addPrefix: true)
|
||||
/// ```
|
||||
/// If `addPrefix` is true, the written bytes would
|
||||
/// include the size of the current buffer.
|
||||
mutating public func finish(
|
||||
offset: Offset,
|
||||
addPrefix prefix: Bool = false)
|
||||
@@ -160,10 +224,15 @@ public struct FlatBufferBuilder {
|
||||
finished = true
|
||||
}
|
||||
|
||||
/// starttable will let the builder know, that a new object is being serialized.
|
||||
/// ``startTable(with:)`` 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
|
||||
/// The function will fatalerror if called while there is another object being serialized.
|
||||
/// ```swift
|
||||
/// let start = Monster
|
||||
/// .startMonster(&fbb)
|
||||
/// ```
|
||||
/// - Parameter numOfFields: Number of elements to be written to the buffer
|
||||
/// - Returns: Offset of the newly started table
|
||||
mutating public func startTable(with numOfFields: Int) -> UOffset {
|
||||
notNested()
|
||||
isNested = true
|
||||
@@ -171,11 +240,14 @@ public struct FlatBufferBuilder {
|
||||
return _bb.size
|
||||
}
|
||||
|
||||
/// Endtable will let the builder know that the object that's written to it is completed
|
||||
/// ``endTable(at:)`` will let the ``FlatBufferBuilder`` 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 current vtable into the ``ByteBuffer``.
|
||||
/// The functions will `fatalError` in case the object is called
|
||||
/// without ``startTable(with:)``, or the object has exceeded the limit of 2GB.
|
||||
///
|
||||
/// 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
|
||||
mutating public func endTable(at startOffset: UOffset) -> UOffset {
|
||||
@@ -239,7 +311,7 @@ public struct FlatBufferBuilder {
|
||||
|
||||
// MARK: - Builds Buffer
|
||||
|
||||
/// asserts to see if the object is not nested
|
||||
/// Asserts to see if the object is not nested
|
||||
@usableFromInline
|
||||
mutating internal func notNested() {
|
||||
assert(!isNested, "Object serialization must not be nested")
|
||||
@@ -259,7 +331,10 @@ public struct FlatBufferBuilder {
|
||||
/// - bufSize: Current size of the buffer + the offset of the object to be written
|
||||
/// - elementSize: Element size
|
||||
@inline(__always)
|
||||
mutating internal func padding(bufSize: UInt32, elementSize: UInt32) -> UInt32 {
|
||||
mutating internal func padding(
|
||||
bufSize: UInt32,
|
||||
elementSize: UInt32) -> UInt32
|
||||
{
|
||||
((~bufSize) &+ 1) & (elementSize - 1)
|
||||
}
|
||||
|
||||
@@ -304,7 +379,18 @@ public struct FlatBufferBuilder {
|
||||
|
||||
// MARK: - Inserting Vectors
|
||||
|
||||
/// Starts a vector of length and Element size
|
||||
/// ``startVector(_:elementSize:)`` creates a new vector within buffer
|
||||
///
|
||||
/// The function checks if there is a current object being written, if
|
||||
/// the check passes it creates a buffer alignment of `length * elementSize`
|
||||
/// ```swift
|
||||
/// builder.startVector(
|
||||
/// int32Values.count, elementSize: 4)
|
||||
/// ```
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - len: Length of vector to be created
|
||||
/// - elementSize: Size of object type to be written
|
||||
mutating public func startVector(_ len: Int, elementSize: Int) {
|
||||
notNested()
|
||||
isNested = true
|
||||
@@ -312,46 +398,102 @@ public struct FlatBufferBuilder {
|
||||
preAlign(len: len &* elementSize, alignment: elementSize)
|
||||
}
|
||||
|
||||
/// Ends the vector of at length
|
||||
/// ``endVector(len:)`` ends the currently created vector
|
||||
///
|
||||
/// Calling ``endVector(len:)`` requires the length, of the current
|
||||
/// vector. The length would be pushed to indicate the count of numbers
|
||||
/// within the vector. If ``endVector(len:)`` is called without
|
||||
/// ``startVector(_:elementSize:)`` it asserts.
|
||||
///
|
||||
/// ```swift
|
||||
/// let vectorOffset = builder.
|
||||
/// endVector(len: int32Values.count)
|
||||
/// ```
|
||||
///
|
||||
/// The current function will fatalError if startVector is called before serializing the vector
|
||||
/// - Parameter len: Length of the buffer
|
||||
/// - Returns: Returns the current ``Offset`` in the ``ByteBuffer``
|
||||
mutating public func endVector(len: Int) -> Offset {
|
||||
assert(isNested, "Calling endVector without calling startVector")
|
||||
isNested = false
|
||||
return Offset(offset: push(element: Int32(len)))
|
||||
}
|
||||
|
||||
/// Creates a vector of type Scalar in the buffer
|
||||
/// Creates a vector of type ``Scalar`` into the ``ByteBuffer``
|
||||
///
|
||||
/// ``createVector(_:)-4swl0`` writes a vector of type Scalars into
|
||||
/// ``ByteBuffer``. This is a convenient method instead of calling,
|
||||
/// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
|
||||
/// ```swift
|
||||
/// let vectorOffset = builder.
|
||||
/// createVector([1, 2, 3, 4])
|
||||
/// ```
|
||||
///
|
||||
/// The underlying implementation simply calls ``createVector(_:size:)-4lhrv``
|
||||
///
|
||||
/// - Parameter elements: elements to be written into the buffer
|
||||
/// - returns: Offset of the vector
|
||||
/// - returns: ``Offset`` of the vector
|
||||
mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset {
|
||||
createVector(elements, size: elements.count)
|
||||
}
|
||||
|
||||
/// Creates a vector of type Scalar in the buffer
|
||||
///
|
||||
/// ``createVector(_:)-4swl0`` writes a vector of type Scalars into
|
||||
/// ``ByteBuffer``. This is a convenient method instead of calling,
|
||||
/// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
|
||||
/// ```swift
|
||||
/// let vectorOffset = builder.
|
||||
/// createVector([1, 2, 3, 4], size: 4)
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter elements: Elements to be written into the buffer
|
||||
/// - Parameter size: Count of elements
|
||||
/// - returns: Offset of the vector
|
||||
mutating public func createVector<T: Scalar>(_ elements: [T], size: Int) -> Offset {
|
||||
/// - returns: ``Offset`` of the vector
|
||||
mutating public func createVector<T: Scalar>(
|
||||
_ elements: [T],
|
||||
size: Int) -> Offset
|
||||
{
|
||||
let size = size
|
||||
startVector(size, elementSize: MemoryLayout<T>.size)
|
||||
_bb.push(elements: elements)
|
||||
return endVector(len: size)
|
||||
}
|
||||
|
||||
/// Creates a vector of type Enums in the buffer
|
||||
/// Creates a vector of type ``Enum`` into the ``ByteBuffer``
|
||||
///
|
||||
/// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into
|
||||
/// ``ByteBuffer``. This is a convenient method instead of calling,
|
||||
/// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
|
||||
/// ```swift
|
||||
/// let vectorOffset = builder.
|
||||
/// createVector([.swift, .cpp])
|
||||
/// ```
|
||||
///
|
||||
/// The underlying implementation simply calls ``createVector(_:size:)-7cx6z``
|
||||
///
|
||||
/// - Parameter elements: elements to be written into the buffer
|
||||
/// - returns: Offset of the vector
|
||||
/// - returns: ``Offset`` of the vector
|
||||
mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset {
|
||||
createVector(elements, size: elements.count)
|
||||
}
|
||||
|
||||
/// Creates a vector of type Enums in the buffer
|
||||
/// Creates a vector of type ``Enum`` into the ``ByteBuffer``
|
||||
///
|
||||
/// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into
|
||||
/// ``ByteBuffer``. This is a convenient method instead of calling,
|
||||
/// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
|
||||
/// ```swift
|
||||
/// let vectorOffset = builder.
|
||||
/// createVector([.swift, .cpp])
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter elements: Elements to be written into the buffer
|
||||
/// - Parameter size: Count of elements
|
||||
/// - returns: Offset of the vector
|
||||
mutating public func createVector<T: Enum>(_ elements: [T], size: Int) -> Offset {
|
||||
/// - returns: ``Offset`` of the vector
|
||||
mutating public func createVector<T: Enum>(
|
||||
_ elements: [T],
|
||||
size: Int) -> Offset
|
||||
{
|
||||
let size = size
|
||||
startVector(size, elementSize: T.byteSize)
|
||||
for e in elements.reversed() {
|
||||
@@ -360,18 +502,42 @@ public struct FlatBufferBuilder {
|
||||
return 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
|
||||
/// Creates a vector of already written offsets
|
||||
///
|
||||
/// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into
|
||||
/// ``ByteBuffer``. This is a convenient method instead of calling,
|
||||
/// ``startVector(_:elementSize:)`` and then ``endVector(len:)``.
|
||||
///
|
||||
/// The underlying implementation simply calls ``createVector(ofOffsets:len:)``
|
||||
///
|
||||
/// ```swift
|
||||
/// let namesOffsets = builder.
|
||||
/// createVector(ofOffsets: [name1, name2])
|
||||
/// ```
|
||||
/// - Parameter offsets: Array of offsets of type ``Offset``
|
||||
/// - returns: ``Offset`` of the vector
|
||||
mutating public func createVector(ofOffsets offsets: [Offset]) -> Offset {
|
||||
createVector(ofOffsets: offsets, len: offsets.count)
|
||||
}
|
||||
|
||||
/// Creates a vector of type Offsets in the buffer
|
||||
/// - Parameter elements: Array of offsets of type T
|
||||
/// Creates a vector of already written offsets
|
||||
///
|
||||
/// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into
|
||||
/// ``ByteBuffer``. This is a convenient method instead of calling,
|
||||
/// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
|
||||
///
|
||||
/// ```swift
|
||||
/// let namesOffsets = builder.
|
||||
/// createVector(ofOffsets: [name1, name2])
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter offsets: Array of offsets of type ``Offset``
|
||||
/// - Parameter size: Count of elements
|
||||
/// - returns: Offset of the vector
|
||||
mutating public func createVector(ofOffsets offsets: [Offset], len: Int) -> Offset {
|
||||
/// - returns: ``Offset`` of the vector
|
||||
mutating public func createVector(
|
||||
ofOffsets offsets: [Offset],
|
||||
len: Int) -> Offset
|
||||
{
|
||||
startVector(len, elementSize: MemoryLayout<Offset>.size)
|
||||
for o in offsets.reversed() {
|
||||
push(element: o)
|
||||
@@ -379,9 +545,21 @@ public struct FlatBufferBuilder {
|
||||
return 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
|
||||
/// Creates a vector of strings
|
||||
///
|
||||
/// ``createVector(ofStrings:)`` creates a vector of `String` into
|
||||
/// ``ByteBuffer``. This is a convenient method instead of manually
|
||||
/// creating the string offsets, you simply pass it to this function
|
||||
/// and it would write the strings into the ``ByteBuffer``.
|
||||
/// After that it calls ``createVector(ofOffsets:)``
|
||||
///
|
||||
/// ```swift
|
||||
/// let namesOffsets = builder.
|
||||
/// createVector(ofStrings: ["Name", "surname"])
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter str: Array of string
|
||||
/// - returns: ``Offset`` of the vector
|
||||
mutating public func createVector(ofStrings str: [String]) -> Offset {
|
||||
var offsets: [Offset] = []
|
||||
for s in str {
|
||||
@@ -390,10 +568,22 @@ public struct FlatBufferBuilder {
|
||||
return createVector(ofOffsets: offsets)
|
||||
}
|
||||
|
||||
/// Creates a vector of `Native swift structs` which were padded to flatbuffers standards
|
||||
/// - Parameter structs: A vector of structs
|
||||
/// - Returns: offset of the vector
|
||||
mutating public func createVector<T: NativeStruct>(ofStructs structs: [T]) -> Offset {
|
||||
/// Creates a vector of type ``NativeStruct``.
|
||||
///
|
||||
/// Any swift struct in the generated code, should confirm to
|
||||
/// ``NativeStruct``. Since the generated swift structs are padded
|
||||
/// to the `FlatBuffers` standards.
|
||||
///
|
||||
/// ```swift
|
||||
/// let offsets = builder.
|
||||
/// createVector(ofStructs: [NativeStr(num: 1), NativeStr(num: 2)])
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter structs: A vector of ``NativeStruct``
|
||||
/// - Returns: ``Offset`` of the vector
|
||||
mutating public func createVector<T: NativeStruct>(ofStructs structs: [T])
|
||||
-> Offset
|
||||
{
|
||||
startVector(
|
||||
structs.count * MemoryLayout<T>.size,
|
||||
elementSize: MemoryLayout<T>.alignment)
|
||||
@@ -405,11 +595,21 @@ public struct FlatBufferBuilder {
|
||||
|
||||
// MARK: - Inserting Structs
|
||||
|
||||
/// Fills the buffer with a native struct that's build and padded according to flatbuffers standards
|
||||
/// Writes a ``NativeStruct`` into the ``ByteBuffer``
|
||||
///
|
||||
/// Adds a native struct that's build and padded according
|
||||
/// to `FlatBuffers` standards. with a predefined position.
|
||||
///
|
||||
/// ```swift
|
||||
/// let offset = builder.create(
|
||||
/// struct: NativeStr(num: 1),
|
||||
/// position: 10)
|
||||
/// ```
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - s: `Native swift` struct to insert
|
||||
/// - s: ``NativeStruct`` to be inserted into the ``ByteBuffer``
|
||||
/// - position: The predefined position of the object
|
||||
/// - Returns: offset of written struct
|
||||
/// - Returns: ``Offset`` of written struct
|
||||
@discardableResult
|
||||
mutating public func create<T: NativeStruct>(
|
||||
struct s: T, position: VOffset) -> Offset
|
||||
@@ -421,10 +621,20 @@ public struct FlatBufferBuilder {
|
||||
return offset
|
||||
}
|
||||
|
||||
/// Fills the buffer with a native struct that's build and padded according to flatbuffers standards
|
||||
/// Writes a ``NativeStruct`` into the ``ByteBuffer``
|
||||
///
|
||||
/// Adds a native struct that's build and padded according
|
||||
/// to `FlatBuffers` standards, directly into the buffer without
|
||||
/// a predefined position.
|
||||
///
|
||||
/// ```swift
|
||||
/// let offset = builder.create(
|
||||
/// struct: NativeStr(num: 1))
|
||||
/// ```
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - s: `Native swift` struct to insert
|
||||
/// - Returns: offset of written struct
|
||||
/// - s: ``NativeStruct`` to be inserted into the ``ByteBuffer``
|
||||
/// - Returns: ``Offset`` of written struct
|
||||
@discardableResult
|
||||
mutating public func create<T: NativeStruct>(
|
||||
struct s: T) -> Offset
|
||||
@@ -437,9 +647,18 @@ public struct FlatBufferBuilder {
|
||||
|
||||
// MARK: - Inserting Strings
|
||||
|
||||
/// Insets a string into the buffer using UTF8
|
||||
/// Insets a string into the buffer of type `UTF8`
|
||||
///
|
||||
/// Adds a swift string into ``ByteBuffer`` by encoding it
|
||||
/// using `UTF8`
|
||||
///
|
||||
/// ```swift
|
||||
/// let nameOffset = builder
|
||||
/// .create(string: "welcome")
|
||||
/// ```
|
||||
///
|
||||
/// - Parameter str: String to be serialized
|
||||
/// - returns: The strings offset in the buffer
|
||||
/// - returns: ``Offset`` of inserted string
|
||||
mutating public func create(string str: String?) -> Offset {
|
||||
guard let str = str else { return Offset() }
|
||||
let len = str.utf8.count
|
||||
@@ -451,11 +670,25 @@ public struct FlatBufferBuilder {
|
||||
return Offset(offset: _bb.size)
|
||||
}
|
||||
|
||||
/// Inserts a shared string to the buffer
|
||||
/// Insets a shared string into the buffer of type `UTF8`
|
||||
///
|
||||
/// Adds a swift string into ``ByteBuffer`` by encoding it
|
||||
/// using `UTF8`. The function will check if the string,
|
||||
/// is already written to the ``ByteBuffer``
|
||||
///
|
||||
/// ```swift
|
||||
/// let nameOffset = builder
|
||||
/// .createShared(string: "welcome")
|
||||
///
|
||||
///
|
||||
/// let secondOffset = builder
|
||||
/// .createShared(string: "welcome")
|
||||
///
|
||||
/// assert(nameOffset.o == secondOffset.o)
|
||||
/// ```
|
||||
///
|
||||
/// 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
|
||||
/// - returns: ``Offset`` of inserted string
|
||||
mutating public func createShared(string str: String?) -> Offset {
|
||||
guard let str = str else { return Offset() }
|
||||
if let offset = stringOffsetMap[str] {
|
||||
@@ -468,18 +701,22 @@ public struct FlatBufferBuilder {
|
||||
|
||||
// MARK: - Inseting offsets
|
||||
|
||||
/// Adds the offset of an object into the buffer
|
||||
/// Writes the ``Offset`` of an already written table
|
||||
///
|
||||
/// Writes the ``Offset`` of a table if not empty into the
|
||||
/// ``ByteBuffer``
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - offset: Offset of another object to be written
|
||||
/// - position: The predefined position of the object
|
||||
/// - offset: ``Offset`` of another object to be written
|
||||
/// - position: The predefined position of the object
|
||||
mutating public func add(offset: Offset, at position: VOffset) {
|
||||
if offset.isEmpty { 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
|
||||
/// Pushes a value of type ``Offset`` into the ``ByteBuffer``
|
||||
/// - Parameter o: ``Offset``
|
||||
/// - returns: Current position of the ``Offset``
|
||||
@discardableResult
|
||||
mutating public func push(element o: Offset) -> UOffset {
|
||||
push(element: refer(to: o.o))
|
||||
@@ -487,18 +724,42 @@ public struct FlatBufferBuilder {
|
||||
|
||||
// MARK: - Inserting Scalars to Buffer
|
||||
|
||||
/// Adds a value into the buffer of type Scalar
|
||||
/// Writes a ``Scalar`` value into ``ByteBuffer``
|
||||
///
|
||||
/// ``add(element:def:at:)`` takes in a default value, and current value
|
||||
/// and the position within the `VTable`. The default value would not
|
||||
/// be serialized if the value is the same as the current value or
|
||||
/// `serializeDefaults` is equal to false.
|
||||
///
|
||||
/// If serializing defaults is important ``init(initialSize:serializeDefaults:)``,
|
||||
/// passing true for `serializeDefaults` would do the job.
|
||||
///
|
||||
/// ```swift
|
||||
/// // Adds 10 to the buffer
|
||||
/// builder.add(element: Int(10), def: 1, position 12)
|
||||
/// ```
|
||||
///
|
||||
/// *NOTE: Never call this manually*
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - element: Element to insert
|
||||
/// - def: Default value for that element
|
||||
/// - position: The predefined position of the element
|
||||
mutating public func add<T: Scalar>(element: T, def: T, at position: VOffset) {
|
||||
mutating public func add<T: Scalar>(
|
||||
element: T,
|
||||
def: T,
|
||||
at position: VOffset)
|
||||
{
|
||||
if element == def && !serializeDefaults { return }
|
||||
track(offset: push(element: element), at: position)
|
||||
}
|
||||
|
||||
/// Adds a value into the buffer of type optional Scalar
|
||||
/// Writes a optional ``Scalar`` value into ``ByteBuffer``
|
||||
///
|
||||
/// Takes an optional value to be written into the ``ByteBuffer``
|
||||
///
|
||||
/// *NOTE: Never call this manually*
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - element: Optional element of type scalar
|
||||
/// - position: The predefined position of the element
|
||||
@@ -507,7 +768,10 @@ public struct FlatBufferBuilder {
|
||||
track(offset: push(element: element), at: position)
|
||||
}
|
||||
|
||||
/// Pushes the values into the buffer
|
||||
/// Pushes a values of type ``Scalar`` into the ``ByteBuffer``
|
||||
///
|
||||
/// *NOTE: Never call this manually*
|
||||
///
|
||||
/// - Parameter element: Element to insert
|
||||
/// - returns: Postion of the Element
|
||||
@discardableResult
|
||||
@@ -556,7 +820,9 @@ extension FlatBufferBuilder: CustomDebugStringConvertible {
|
||||
/// Creates the memory to store the buffer in
|
||||
@usableFromInline
|
||||
init() {
|
||||
memory = UnsafeMutableRawBufferPointer.allocate(byteCount: 0, alignment: 0)
|
||||
memory = UnsafeMutableRawBufferPointer.allocate(
|
||||
byteCount: 0,
|
||||
alignment: 0)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
@@ -23,6 +23,8 @@ public protocol NativeStruct {}
|
||||
/// FlatbuffersInitializable is a protocol that allows any object to be
|
||||
/// Initialized from a ByteBuffer
|
||||
public protocol FlatbuffersInitializable {
|
||||
/// Any flatbuffers object that confirms to this protocol is going to be
|
||||
/// initializable through this initializer
|
||||
init(_ bb: ByteBuffer, o: Int32)
|
||||
}
|
||||
|
||||
@@ -31,26 +33,32 @@ public protocol FlatBufferObject: FlatbuffersInitializable {
|
||||
var __buffer: ByteBuffer! { get }
|
||||
}
|
||||
|
||||
/// `ObjectAPIPacker` is a protocol that allows object to pack and unpack from a
|
||||
/// `NativeObject` to a flatbuffers Object and vice versa.
|
||||
/// ``ObjectAPIPacker`` is a protocol that allows object to pack and unpack from a
|
||||
/// ``NativeObject`` to a flatbuffers Object and vice versa.
|
||||
public protocol ObjectAPIPacker {
|
||||
/// associatedtype to the object that should be unpacked.
|
||||
associatedtype T
|
||||
|
||||
/// `pack` tries packs the variables of a native Object into the `ByteBuffer` by using
|
||||
/// the FlatBufferBuilder
|
||||
/// ``pack(_:obj:)-3ptws`` tries to pacs the variables of a native Object into the `ByteBuffer` by using
|
||||
/// a FlatBufferBuilder
|
||||
/// - Parameters:
|
||||
/// - builder: FlatBufferBuilder that will host incoming data
|
||||
/// - obj: Object of associatedtype to the current implementer
|
||||
///
|
||||
/// ``pack(_:obj:)-3ptws`` can be called by passing through an already initialized ``FlatBufferBuilder``
|
||||
/// or it can be called by using the public API that will create a new ``FlatBufferBuilder``
|
||||
static func pack(_ builder: inout FlatBufferBuilder, obj: inout T?) -> Offset
|
||||
|
||||
/// `pack` packs the variables of a native Object into the `ByteBuffer` by using
|
||||
/// ``pack(_:obj:)-20ipk`` packs the variables of a native Object into the `ByteBuffer` by using
|
||||
/// the FlatBufferBuilder
|
||||
/// - Parameters:
|
||||
/// - builder: FlatBufferBuilder that will host incoming data
|
||||
/// - obj: Object of associatedtype to the current implementer
|
||||
///
|
||||
/// ``pack(_:obj:)-20ipk`` can be called by passing through an already initialized ``FlatBufferBuilder``
|
||||
/// or it can be called by using the public API that will create a new ``FlatBufferBuilder``
|
||||
static func pack(_ builder: inout FlatBufferBuilder, obj: inout T) -> Offset
|
||||
|
||||
/// `Unpack` unpacks a flatbuffers object into a `NativeObject`
|
||||
/// ``unpack()`` unpacks a ``FlatBuffers`` object into a Native swift object.
|
||||
mutating func unpack() -> T
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public enum FlatBuffersUtils {
|
||||
/// creates a new buffer use `readPrefixedSizeCheckedRoot` instead
|
||||
/// unless a completely new buffer is required
|
||||
/// - Parameter bb: Flatbuffer object
|
||||
///
|
||||
///
|
||||
public static func removeSizePrefix(bb: ByteBuffer) -> ByteBuffer {
|
||||
bb.duplicate(removing: MemoryLayout<Int32>.size)
|
||||
}
|
||||
|
||||
@@ -53,7 +53,10 @@ public enum FlatbuffersErrors: Error, Equatable {
|
||||
fieldName: String)
|
||||
case apparentSizeTooLarge
|
||||
|
||||
public static func == (lhs: FlatbuffersErrors, rhs: FlatbuffersErrors) -> Bool {
|
||||
public static func == (
|
||||
lhs: FlatbuffersErrors,
|
||||
rhs: FlatbuffersErrors) -> Bool
|
||||
{
|
||||
lhs.localizedDescription == rhs.localizedDescription
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,12 @@ public struct Message<T: FlatBufferObject>: FlatBufferGRPCMessage {
|
||||
public var object: T {
|
||||
T.init(
|
||||
buffer,
|
||||
o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) + Int32(buffer.reader))
|
||||
o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) +
|
||||
Int32(buffer.reader))
|
||||
}
|
||||
|
||||
public var rawPointer: UnsafeMutableRawPointer { buffer.memory.advanced(by: buffer.reader) }
|
||||
public var rawPointer: UnsafeMutableRawPointer {
|
||||
buffer.memory.advanced(by: buffer.reader) }
|
||||
|
||||
public var size: Int { Int(buffer.size) }
|
||||
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Mutable is a protocol that allows us to mutate Scalar values within the buffer
|
||||
/// Mutable is a protocol that allows us to mutate Scalar values within a ``ByteBuffer``
|
||||
public protocol Mutable {
|
||||
/// makes Flatbuffer accessed within the Protocol
|
||||
var bb: ByteBuffer { get }
|
||||
/// makes position of the table/struct accessed within the Protocol
|
||||
/// 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
|
||||
/// Mutates the memory in the buffer, this is only called from the access function of ``Table`` and ``struct``
|
||||
/// - Parameters:
|
||||
/// - value: New value to be inserted to the buffer
|
||||
/// - index: index of the Element
|
||||
@@ -39,7 +39,7 @@ extension Mutable {
|
||||
|
||||
extension Mutable where Self == Table {
|
||||
|
||||
/// Mutates a value by calling mutate with respect to the position in the table
|
||||
/// Mutates a value by calling mutate with respect to the position in a ``Table``
|
||||
/// - Parameters:
|
||||
/// - value: New value to be inserted to the buffer
|
||||
/// - index: index of the Element
|
||||
|
||||
@@ -26,7 +26,9 @@ extension NativeObject {
|
||||
/// Serialize is a helper function that serailizes the data from the Object API to a bytebuffer directly th
|
||||
/// - Parameter type: Type of the Flatbuffer object
|
||||
/// - Returns: returns the encoded sized ByteBuffer
|
||||
public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer where T.T == Self {
|
||||
public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer
|
||||
where T.T == Self
|
||||
{
|
||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||
return serialize(builder: &builder, type: type.self)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ import Foundation
|
||||
/// - options: Verifier options
|
||||
/// - Throws: FlatbuffersErrors
|
||||
/// - Returns: Returns a valid, checked Flatbuffers object
|
||||
///
|
||||
/// ``getPrefixedSizeCheckedRoot(byteBuffer:options:)`` would skip the first Bytes in
|
||||
/// the ``ByteBuffer`` and verifies the buffer by calling ``getCheckedRoot(byteBuffer:options:)``
|
||||
public func getPrefixedSizeCheckedRoot<T: FlatBufferObject & Verifiable>(
|
||||
byteBuffer: inout ByteBuffer,
|
||||
options: VerifierOptions = .init()) throws -> T
|
||||
@@ -35,7 +38,12 @@ public func getPrefixedSizeCheckedRoot<T: FlatBufferObject & Verifiable>(
|
||||
/// Returns a `NON-Checked` flatbuffers object
|
||||
/// - Parameter byteBuffer: Buffer that contains data
|
||||
/// - Returns: Returns a Flatbuffers object
|
||||
public func getPrefixedSizeRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) -> T {
|
||||
///
|
||||
/// ``getPrefixedSizeCheckedRoot(byteBuffer:options:)`` would skip the first Bytes in
|
||||
/// the ``ByteBuffer`` and then calls ``getRoot(byteBuffer:)``
|
||||
public func getPrefixedSizeRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer)
|
||||
-> T
|
||||
{
|
||||
byteBuffer.skipPrefix()
|
||||
return getRoot(byteBuffer: &byteBuffer)
|
||||
|
||||
@@ -47,6 +55,10 @@ public func getPrefixedSizeRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffe
|
||||
/// - options: Verifier options
|
||||
/// - Throws: FlatbuffersErrors
|
||||
/// - Returns: Returns a valid, checked Flatbuffers object
|
||||
///
|
||||
/// ``getCheckedRoot(byteBuffer:options:)`` Takes in a ``ByteBuffer`` and verifies
|
||||
/// that by creating a ``Verifier`` and checkes if all the `Bytes` and correctly aligned
|
||||
/// and within the ``ByteBuffer`` range.
|
||||
public func getCheckedRoot<T: FlatBufferObject & Verifiable>(
|
||||
byteBuffer: inout ByteBuffer,
|
||||
options: VerifierOptions = .init()) throws -> T
|
||||
@@ -55,7 +67,8 @@ public func getCheckedRoot<T: FlatBufferObject & Verifiable>(
|
||||
try ForwardOffset<T>.verify(&verifier, at: 0, of: T.self)
|
||||
return T.init(
|
||||
byteBuffer,
|
||||
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) + Int32(byteBuffer.reader))
|
||||
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) +
|
||||
Int32(byteBuffer.reader))
|
||||
}
|
||||
|
||||
/// Returns a `NON-Checked` flatbuffers object
|
||||
@@ -64,5 +77,6 @@ public func getCheckedRoot<T: FlatBufferObject & Verifiable>(
|
||||
public func getRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) -> T {
|
||||
T.init(
|
||||
byteBuffer,
|
||||
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) + Int32(byteBuffer.reader))
|
||||
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) +
|
||||
Int32(byteBuffer.reader))
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ extension String: Verifiable {
|
||||
|
||||
if !verifier._options._ignoreMissingNullTerminators && !isNullTerminated {
|
||||
let str = verifier._buffer.readString(at: range.start, count: range.count)
|
||||
throw FlatbuffersErrors.missingNullTerminator(position: position, str: str)
|
||||
throw FlatbuffersErrors.missingNullTerminator(
|
||||
position: position,
|
||||
str: str)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,12 +71,18 @@ extension String: FlatbuffersInitializable {
|
||||
|
||||
extension String: ObjectAPIPacker {
|
||||
|
||||
public static func pack(_ builder: inout FlatBufferBuilder, obj: inout String?) -> Offset {
|
||||
public static func pack(
|
||||
_ builder: inout FlatBufferBuilder,
|
||||
obj: inout String?) -> Offset
|
||||
{
|
||||
guard var obj = obj else { return Offset() }
|
||||
return pack(&builder, obj: &obj)
|
||||
}
|
||||
|
||||
public static func pack(_ builder: inout FlatBufferBuilder, obj: inout String) -> Offset {
|
||||
public static func pack(
|
||||
_ builder: inout FlatBufferBuilder,
|
||||
obj: inout String) -> Offset
|
||||
{
|
||||
builder.create(string: obj)
|
||||
}
|
||||
|
||||
@@ -86,7 +94,9 @@ extension String: ObjectAPIPacker {
|
||||
|
||||
extension String: NativeObject {
|
||||
|
||||
public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer where T.T == Self {
|
||||
public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer
|
||||
where T.T == Self
|
||||
{
|
||||
fatalError("serialize should never be called from string directly")
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@ public struct Table {
|
||||
/// - Note: This will `CRASH` if read on a big endian machine
|
||||
public init(bb: ByteBuffer, position: Int32 = 0) {
|
||||
guard isLitteEndian else {
|
||||
fatalError("Reading/Writing a buffer in big endian machine is not supported on swift")
|
||||
fatalError(
|
||||
"Reading/Writing a buffer in big endian machine is not supported on swift")
|
||||
}
|
||||
self.bb = bb
|
||||
postion = position
|
||||
@@ -46,9 +47,10 @@ public struct Table {
|
||||
/// - Returns: offset of field within buffer
|
||||
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
|
||||
return o < bb
|
||||
.read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read(
|
||||
def: Int16.self,
|
||||
position: Int(vtable + o))) : 0
|
||||
}
|
||||
|
||||
/// Gets the indirect offset of the current stored object
|
||||
@@ -163,7 +165,11 @@ public struct Table {
|
||||
/// - vOffset: Field offset within a vtable
|
||||
/// - fbb: ByteBuffer
|
||||
/// - Returns: an position of a field
|
||||
static public func offset(_ o: Int32, vOffset: Int32, fbb: ByteBuffer) -> Int32 {
|
||||
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,
|
||||
@@ -178,7 +184,11 @@ public struct Table {
|
||||
/// - off2: second offset to compare
|
||||
/// - fbb: Bytebuffer
|
||||
/// - Returns: returns the difference between
|
||||
static public func compare(_ off1: Int32, _ off2: Int32, fbb: ByteBuffer) -> Int32 {
|
||||
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))
|
||||
@@ -203,7 +213,11 @@ public struct Table {
|
||||
/// - key: bytes array to compare to
|
||||
/// - fbb: Bytebuffer
|
||||
/// - Returns: returns the difference between
|
||||
static public func compare(_ off1: Int32, _ key: [Byte], fbb: ByteBuffer) -> Int32 {
|
||||
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))
|
||||
|
||||
@@ -64,8 +64,7 @@ public struct TableVerifier {
|
||||
|
||||
/// Reading the offset for the field needs to be read.
|
||||
let offset: VOffset = try _verifier.getValue(
|
||||
at: Int(clamping: _vtable &+ Int(field))
|
||||
)
|
||||
at: Int(clamping: _vtable &+ Int(field)))
|
||||
|
||||
if offset > 0 {
|
||||
return Int(clamping: _position &+ Int(offset))
|
||||
@@ -116,7 +115,8 @@ public struct TableVerifier {
|
||||
unionKeyName: String,
|
||||
fieldName: String,
|
||||
required: Bool,
|
||||
completion: @escaping (inout Verifier, T, Int) throws -> Void) throws where T: UnionEnum
|
||||
completion: @escaping (inout Verifier, T, Int) throws -> Void) throws
|
||||
where T: UnionEnum
|
||||
{
|
||||
let keyPos = try dereference(key)
|
||||
let valPos = try dereference(field)
|
||||
@@ -170,7 +170,8 @@ public struct TableVerifier {
|
||||
unionKeyName: String,
|
||||
fieldName: String,
|
||||
required: Bool,
|
||||
completion: @escaping (inout Verifier, T, Int) throws -> Void) throws where T: UnionEnum
|
||||
completion: @escaping (inout Verifier, T, Int) throws -> Void) throws
|
||||
where T: UnionEnum
|
||||
{
|
||||
let keyVectorPosition = try dereference(key)
|
||||
let offsetVectorPosition = try dereference(field)
|
||||
|
||||
@@ -176,14 +176,18 @@ public struct Verifier {
|
||||
|
||||
let reportedOverflow: (partialValue: UInt32, overflow: Bool)
|
||||
if offset > 0 {
|
||||
reportedOverflow = _int32Position.subtractingReportingOverflow(offset.magnitude)
|
||||
reportedOverflow = _int32Position
|
||||
.subtractingReportingOverflow(offset.magnitude)
|
||||
} else {
|
||||
reportedOverflow = _int32Position.addingReportingOverflow(offset.magnitude)
|
||||
reportedOverflow = _int32Position
|
||||
.addingReportingOverflow(offset.magnitude)
|
||||
}
|
||||
|
||||
/// since `subtractingReportingOverflow` & `addingReportingOverflow` returns true,
|
||||
/// if there is overflow we return failure
|
||||
if reportedOverflow.overflow || reportedOverflow.partialValue > _buffer.capacity {
|
||||
if reportedOverflow.overflow || reportedOverflow.partialValue > _buffer
|
||||
.capacity
|
||||
{
|
||||
throw FlatbuffersErrors.signedOffsetOutOfBounds(
|
||||
offset: Int(offset),
|
||||
position: position)
|
||||
|
||||
@@ -21,7 +21,8 @@ struct Benchmark {
|
||||
var name: String
|
||||
var value: Double
|
||||
|
||||
var description: String { "\(String(format: "|\t%@\t\t|\t\t%fs\t|", name, value))"}
|
||||
var description: String {
|
||||
"\(String(format: "|\t%@\t\t|\t\t%fs\t|", name, value))"}
|
||||
}
|
||||
|
||||
func run(name: String, runs: Int, action: () -> Void) -> Benchmark {
|
||||
|
||||
@@ -25,7 +25,7 @@ let package = Package(
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "../../swift/"),
|
||||
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0"),
|
||||
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.4.1"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
||||
@@ -35,7 +35,8 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
|
||||
|
||||
func testReadFromOtherLanguages() {
|
||||
let path = FileManager.default.currentDirectoryPath
|
||||
let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon")
|
||||
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)
|
||||
readVerifiedMonster(fb: _data)
|
||||
@@ -108,15 +109,16 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
|
||||
// swiftformat:disable all
|
||||
var array: [UInt8] = [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]
|
||||
// swiftformat:enable all
|
||||
let unpacked = array.withUnsafeMutableBytes { (memory) -> MyGame_Example_MonsterT in
|
||||
let bytes = ByteBuffer(
|
||||
assumingMemoryBound: memory.baseAddress!,
|
||||
capacity: memory.count)
|
||||
var monster = Monster.getRootAsMonster(bb: bytes)
|
||||
readFlatbufferMonster(monster: &monster)
|
||||
let unpacked = monster.unpack()
|
||||
return unpacked
|
||||
}
|
||||
let unpacked = array
|
||||
.withUnsafeMutableBytes { (memory) -> MyGame_Example_MonsterT in
|
||||
let bytes = ByteBuffer(
|
||||
assumingMemoryBound: memory.baseAddress!,
|
||||
capacity: memory.count)
|
||||
var monster = Monster.getRootAsMonster(bb: bytes)
|
||||
readFlatbufferMonster(monster: &monster)
|
||||
let unpacked = monster.unpack()
|
||||
return unpacked
|
||||
}
|
||||
readObjectApi(monster: unpacked)
|
||||
}
|
||||
|
||||
@@ -143,7 +145,10 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
|
||||
|
||||
func readVerifiedMonster(fb: ByteBuffer) {
|
||||
var byteBuffer = fb
|
||||
XCTAssertNoThrow(try readMonster(monster: getCheckedRoot(byteBuffer: &byteBuffer) as MyGame_Example_Monster))
|
||||
XCTAssertNoThrow(
|
||||
try readMonster(
|
||||
monster: getCheckedRoot(
|
||||
byteBuffer: &byteBuffer) as MyGame_Example_Monster))
|
||||
}
|
||||
|
||||
func readMonster(monster: Monster) {
|
||||
@@ -151,7 +156,8 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
|
||||
readFlatbufferMonster(monster: &monster)
|
||||
let unpacked: MyGame_Example_MonsterT? = monster.unpack()
|
||||
readObjectApi(monster: unpacked!)
|
||||
guard let buffer = unpacked?.serialize() else { fatalError("Couldnt generate bytebuffer") }
|
||||
guard let buffer = unpacked?.serialize()
|
||||
else { fatalError("Couldnt generate bytebuffer") }
|
||||
var newMonster = Monster.getRootAsMonster(bb: buffer)
|
||||
readFlatbufferMonster(monster: &newMonster)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ final class FlatBuffersStructsTests: XCTestCase {
|
||||
let root = TestMutatingBool.endTestMutatingBool(&fbb, start: start)
|
||||
fbb.finish(offset: root)
|
||||
|
||||
let testMutatingBool = TestMutatingBool.getRootAsTestMutatingBool(bb: fbb.sizedBuffer)
|
||||
let testMutatingBool = TestMutatingBool
|
||||
.getRootAsTestMutatingBool(bb: fbb.sizedBuffer)
|
||||
let property = testMutatingBool.mutableB
|
||||
XCTAssertEqual(property?.property, false)
|
||||
property?.mutate(property: false)
|
||||
|
||||
@@ -108,7 +108,8 @@ final class FlatBuffersTests: XCTestCase {
|
||||
justEnum: .one,
|
||||
maybeEnum: nil)
|
||||
b.finish(offset: root)
|
||||
let scalarTable = optional_scalars_ScalarStuff.getRootAsScalarStuff(bb: b.sizedBuffer)
|
||||
let scalarTable = optional_scalars_ScalarStuff
|
||||
.getRootAsScalarStuff(bb: b.sizedBuffer)
|
||||
XCTAssertEqual(scalarTable.justI8, 80)
|
||||
XCTAssertNil(scalarTable.maybeI8)
|
||||
XCTAssertEqual(scalarTable.maybeBool, true)
|
||||
@@ -136,7 +137,8 @@ class Country {
|
||||
of: Int32.self,
|
||||
at: o) }
|
||||
var nameVector: [UInt8]? { __t.getVector(at: 4) }
|
||||
var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
|
||||
var name: String? {
|
||||
let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
|
||||
|
||||
@inlinable
|
||||
static func getRootAsCountry(_ bb: ByteBuffer) -> Country {
|
||||
@@ -174,7 +176,10 @@ class Country {
|
||||
}
|
||||
|
||||
@inlinable
|
||||
static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset {
|
||||
static func end(
|
||||
builder: inout FlatBufferBuilder,
|
||||
startOffset: UOffset) -> Offset
|
||||
{
|
||||
Offset(offset: builder.endTable(at: startOffset))
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,10 @@ final class FlatBuffersUnionTests: XCTestCase {
|
||||
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 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]
|
||||
@@ -138,7 +141,9 @@ final class FlatBuffersUnionTests: XCTestCase {
|
||||
2)
|
||||
|
||||
var objc: MovieT? = movie.unpack()
|
||||
XCTAssertEqual(movie.charactersTypeCount, Int32(objc?.characters.count ?? 0))
|
||||
XCTAssertEqual(
|
||||
movie.charactersTypeCount,
|
||||
Int32(objc?.characters.count ?? 0))
|
||||
XCTAssertEqual(
|
||||
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
|
||||
(objc?.characters[0]?.value as? BookReader)?.booksRead)
|
||||
@@ -219,20 +224,32 @@ public enum ColorsNameSpace {
|
||||
private var _accessor: Table
|
||||
static func getRootAsMonster(bb: ByteBuffer) -> Monster { Monster(Table(
|
||||
bb: bb,
|
||||
position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
|
||||
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: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
|
||||
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: inout FlatBufferBuilder) -> UOffset { fbb
|
||||
.startTable(with: 1) }
|
||||
static func add(colors: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(
|
||||
offset: colors,
|
||||
at: 4) }
|
||||
static func endMonster(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
|
||||
static func endMonster(
|
||||
_ fbb: inout FlatBufferBuilder,
|
||||
start: UOffset)
|
||||
-> Offset
|
||||
{ let end = Offset(offset: fbb.endTable(at: start)); return end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,9 +297,10 @@ struct LocalMonster {
|
||||
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 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)
|
||||
@@ -304,7 +322,10 @@ struct LocalMonster {
|
||||
let start = builder.startTable(with: 3)
|
||||
builder.add(element: equippedOffset, def: 0, at: 8)
|
||||
builder.add(offset: offset, at: 4)
|
||||
builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 6)
|
||||
builder.add(
|
||||
element: equipment.rawValue,
|
||||
def: Equipment.none.rawValue,
|
||||
at: 6)
|
||||
return Offset(offset: builder.endTable(at: start))
|
||||
}
|
||||
}
|
||||
@@ -323,7 +344,8 @@ struct Weapon: FlatBufferObject {
|
||||
of: Int16.self,
|
||||
at: o) }
|
||||
var nameVector: [UInt8]? { __t.getVector(at: 4) }
|
||||
var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
|
||||
var name: String? {
|
||||
let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
|
||||
|
||||
static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { Weapon(Table(
|
||||
bb: bb,
|
||||
@@ -342,7 +364,10 @@ struct Weapon: FlatBufferObject {
|
||||
}
|
||||
|
||||
@inlinable
|
||||
static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset {
|
||||
static func end(
|
||||
builder: inout FlatBufferBuilder,
|
||||
startOffset: UOffset) -> Offset
|
||||
{
|
||||
Offset(offset: builder.endTable(at: startOffset))
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,16 @@ final class FlatBuffersVectors: XCTestCase {
|
||||
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 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)
|
||||
@@ -119,19 +127,31 @@ struct Numbers {
|
||||
var vArrayDouble: [Double]? { __t.getVector(at: 4) }
|
||||
var vArrayFloat: [Float32]? { __t.getVector(at: 4) }
|
||||
|
||||
static func createNumbersVector(b: inout FlatBufferBuilder, array: [Int]) -> Offset {
|
||||
static func createNumbersVector(
|
||||
b: inout FlatBufferBuilder,
|
||||
array: [Int]) -> Offset
|
||||
{
|
||||
b.createVector(array, size: array.count)
|
||||
}
|
||||
|
||||
static func createNumbersVector(b: inout FlatBufferBuilder, array: [Int32]) -> Offset {
|
||||
static func createNumbersVector(
|
||||
b: inout FlatBufferBuilder,
|
||||
array: [Int32]) -> Offset
|
||||
{
|
||||
b.createVector(array, size: array.count)
|
||||
}
|
||||
|
||||
static func createNumbersVector(b: inout FlatBufferBuilder, array: [Double]) -> Offset {
|
||||
static func createNumbersVector(
|
||||
b: inout FlatBufferBuilder,
|
||||
array: [Double]) -> Offset
|
||||
{
|
||||
b.createVector(array, size: array.count)
|
||||
}
|
||||
|
||||
static func createNumbersVector(b: inout FlatBufferBuilder, array: [Float32]) -> Offset {
|
||||
static func createNumbersVector(
|
||||
b: inout FlatBufferBuilder,
|
||||
array: [Float32]) -> Offset
|
||||
{
|
||||
b.createVector(array, size: array.count)
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,10 @@ class CountryDouble {
|
||||
return CountryDouble.end(builder: &builder, startOffset: _start)
|
||||
}
|
||||
|
||||
static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset {
|
||||
static func end(
|
||||
builder: inout FlatBufferBuilder,
|
||||
startOffset: UOffset) -> Offset
|
||||
{
|
||||
Offset(offset: builder.endTable(at: startOffset))
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,8 @@ final class FlatbuffersVerifierTests: XCTestCase {
|
||||
field: 22,
|
||||
fieldName: "test4",
|
||||
required: false,
|
||||
type: ForwardOffset<Vector<MyGame_Example_Test, MyGame_Example_Test>>.self))
|
||||
type: ForwardOffset<Vector<MyGame_Example_Test, MyGame_Example_Test>>
|
||||
.self))
|
||||
|
||||
XCTAssertNoThrow(try tableVerifer.visit(
|
||||
field: 24,
|
||||
@@ -201,11 +202,15 @@ final class FlatbuffersVerifierTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testFullVerifier() {
|
||||
XCTAssertNoThrow(try getCheckedRoot(byteBuffer: &validFlatbuffersObject) as MyGame_Example_Monster)
|
||||
XCTAssertNoThrow(
|
||||
try getCheckedRoot(
|
||||
byteBuffer: &validFlatbuffersObject) as MyGame_Example_Monster)
|
||||
}
|
||||
|
||||
func testInvalidBuffer() {
|
||||
XCTAssertThrowsError(try getCheckedRoot(byteBuffer: &invalidFlatbuffersObject) as MyGame_Example_Monster)
|
||||
XCTAssertThrowsError(
|
||||
try getCheckedRoot(
|
||||
byteBuffer: &invalidFlatbuffersObject) as MyGame_Example_Monster)
|
||||
}
|
||||
|
||||
func testValidUnionBuffer() {
|
||||
|
||||
@@ -136,7 +136,9 @@ extension FlatbuffersVerifierTests {
|
||||
public func __allTests() -> [XCTestCaseEntry] {
|
||||
[
|
||||
testCase(FlatBuffersDoubleTests.__allTests__FlatBuffersDoubleTests),
|
||||
testCase(FlatBuffersMonsterWriterTests.__allTests__FlatBuffersMonsterWriterTests),
|
||||
testCase(
|
||||
FlatBuffersMonsterWriterTests
|
||||
.__allTests__FlatBuffersMonsterWriterTests),
|
||||
testCase(FlatBuffersMoreDefaults.__allTests__FlatBuffersMoreDefaults),
|
||||
testCase(FlatBuffersStructsTests.__allTests__FlatBuffersStructsTests),
|
||||
testCase(FlatBuffersTests.__allTests__FlatBuffersTests),
|
||||
|
||||
Reference in New Issue
Block a user