[swift] Implements union strings (#6589)

This commit is contained in:
mustiikhalil
2021-04-24 14:47:24 +03:00
committed by GitHub
parent b82fe07384
commit 4ccc52c7a0
19 changed files with 398 additions and 282 deletions

View File

@@ -28,7 +28,7 @@ public struct FlatBufferBuilder {
/// A check if the buffer is being written into by a different table
private var isNested = false
/// Dictonary that stores a map of all the strings that were written to the buffer
private var stringOffsetMap: [String: Offset<String>] = [:]
private var stringOffsetMap: [String: Offset] = [:]
/// A check to see if finish(::) was ever called to retreive data object
private var finished = false
/// A check to see if the buffer should serialize Default values
@@ -107,7 +107,7 @@ public struct FlatBufferBuilder {
/// - Parameters:
/// - table: offset for the table
/// - fields: Array of all the important fields to be serialized
mutating public func require(table: Offset<UOffset>, fields: [Int32]) {
mutating public func require(table: Offset, fields: [Int32]) {
for field in fields {
let start = _bb.capacity &- Int(table.o)
let startTable = start &- Int(_bb.read(def: Int32.self, position: start))
@@ -121,7 +121,7 @@ public struct FlatBufferBuilder {
/// - offset: Offset of the table
/// - fileId: Takes the fileId
/// - prefix: if false it wont add the size of the buffer
mutating public func finish<T>(offset: Offset<T>, fileId: String, addPrefix prefix: Bool = false) {
mutating public func finish(offset: Offset, fileId: String, addPrefix prefix: Bool = false) {
let size = MemoryLayout<UOffset>.size
preAlign(len: size &+ (prefix ? size : 0) &+ FileIdLength, alignment: _minAlignment)
assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4")
@@ -133,7 +133,7 @@ public struct FlatBufferBuilder {
/// - Parameters:
/// - offset: Offset of the table
/// - prefix: if false it wont add the size of the buffer
mutating public func finish<T>(offset: Offset<T>, addPrefix prefix: Bool = false) {
mutating public func finish(offset: Offset, addPrefix prefix: Bool = false) {
notNested()
let size = MemoryLayout<UOffset>.size
preAlign(len: size &+ (prefix ? size : 0), alignment: _minAlignment)
@@ -296,7 +296,7 @@ public struct FlatBufferBuilder {
///
/// The current function will fatalError if startVector is called before serializing the vector
/// - Parameter len: Length of the buffer
mutating public func endVector(len: Int) -> Offset<UOffset> {
mutating public func endVector(len: Int) -> Offset {
assert(isNested, "Calling endVector without calling startVector")
isNested = false
return Offset(offset: push(element: Int32(len)))
@@ -305,7 +305,7 @@ public struct FlatBufferBuilder {
/// Creates a vector of type Scalar in the buffer
/// - Parameter elements: elements to be written into the buffer
/// - returns: Offset of the vector
mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset<UOffset> {
mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset {
createVector(elements, size: elements.count)
}
@@ -313,7 +313,7 @@ public struct FlatBufferBuilder {
/// - 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<UOffset> {
mutating public func createVector<T: Scalar>(_ elements: [T], size: Int) -> Offset {
let size = size
startVector(size, elementSize: MemoryLayout<T>.size)
_bb.push(elements: elements)
@@ -323,7 +323,7 @@ public struct FlatBufferBuilder {
/// Creates a vector of type Enums in the buffer
/// - Parameter elements: elements to be written into the buffer
/// - returns: Offset of the vector
mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset<UOffset> {
mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset {
createVector(elements, size: elements.count)
}
@@ -331,7 +331,7 @@ public struct FlatBufferBuilder {
/// - 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<UOffset> {
mutating public func createVector<T: Enum>(_ elements: [T], size: Int) -> Offset {
let size = size
startVector(size, elementSize: T.byteSize)
for e in elements.reversed() {
@@ -343,7 +343,7 @@ public struct FlatBufferBuilder {
/// Creates a vector of type Offsets in the buffer
/// - Parameter offsets:Array of offsets of type T
/// - returns: Offset of the vector
mutating public func createVector<T>(ofOffsets offsets: [Offset<T>]) -> Offset<UOffset> {
mutating public func createVector(ofOffsets offsets: [Offset]) -> Offset {
createVector(ofOffsets: offsets, len: offsets.count)
}
@@ -351,8 +351,8 @@ public struct FlatBufferBuilder {
/// - Parameter elements: Array of offsets of type T
/// - Parameter size: Count of elements
/// - returns: Offset of the vector
mutating public func createVector<T>(ofOffsets offsets: [Offset<T>], len: Int) -> Offset<UOffset> {
startVector(len, elementSize: MemoryLayout<Offset<T>>.size)
mutating public func createVector(ofOffsets offsets: [Offset], len: Int) -> Offset {
startVector(len, elementSize: MemoryLayout<Offset>.size)
for o in offsets.reversed() {
push(element: o)
}
@@ -362,8 +362,8 @@ public struct FlatBufferBuilder {
/// Creates a vector of Strings
/// - Parameter str: a vector of strings that will be written into the buffer
/// - returns: Offset of the vector
mutating public func createVector(ofStrings str: [String]) -> Offset<UOffset> {
var offsets: [Offset<String>] = []
mutating public func createVector(ofStrings str: [String]) -> Offset {
var offsets: [Offset] = []
for s in str {
offsets.append(create(string: s))
}
@@ -373,7 +373,7 @@ public struct FlatBufferBuilder {
/// 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<UOffset> {
mutating public func createVector<T: NativeStruct>(ofStructs structs: [T]) -> Offset {
startVector(structs.count * MemoryLayout<T>.size, elementSize: MemoryLayout<T>.alignment)
for i in structs.reversed() {
_ = create(struct: i)
@@ -390,7 +390,7 @@ public struct FlatBufferBuilder {
/// - Returns: offset of written struct
@discardableResult
mutating public func create<T: NativeStruct>(
struct s: T, position: VOffset) -> Offset<UOffset>
struct s: T, position: VOffset) -> Offset
{
let offset = create(struct: s)
_vtableStorage.add(loc: FieldLoc(offset: _bb.size, position: VOffset(position)))
@@ -403,7 +403,7 @@ public struct FlatBufferBuilder {
/// - Returns: offset of written struct
@discardableResult
mutating public func create<T: NativeStruct>(
struct s: T) -> Offset<UOffset>
struct s: T) -> Offset
{
let size = MemoryLayout<T>.size
preAlign(len: size, alignment: MemoryLayout<T>.alignment)
@@ -416,7 +416,7 @@ public struct FlatBufferBuilder {
/// Insets a string into the buffer using UTF8
/// - Parameter str: String to be serialized
/// - returns: The strings offset in the buffer
mutating public func create(string str: String?) -> Offset<String> {
mutating public func create(string str: String?) -> Offset {
guard let str = str else { return Offset() }
let len = str.utf8.count
notNested()
@@ -432,7 +432,7 @@ public struct FlatBufferBuilder {
/// 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
mutating public func createShared(string str: String?) -> Offset<String> {
mutating public func createShared(string str: String?) -> Offset {
guard let str = str else { return Offset() }
if let offset = stringOffsetMap[str] {
return offset
@@ -448,7 +448,7 @@ public struct FlatBufferBuilder {
/// - Parameters:
/// - offset: Offset of another object to be written
/// - position: The predefined position of the object
mutating public func add<T>(offset: Offset<T>, at position: VOffset) {
mutating public func add(offset: Offset, at position: VOffset) {
if offset.isEmpty { return }
add(element: refer(to: offset.o), def: 0, at: position)
}
@@ -457,7 +457,7 @@ public struct FlatBufferBuilder {
/// - Parameter o: Offset
/// - returns: Position of the offset
@discardableResult
mutating public func push<T>(element o: Offset<T>) -> UOffset {
mutating public func push(element o: Offset) -> UOffset {
push(element: refer(to: o.o))
}

View File

@@ -20,15 +20,21 @@ import Foundation
/// since now we will be serializing native structs into the buffer.
public protocol NativeStruct {}
/// FlatbufferObject structures all the Flatbuffers objects
public protocol FlatBufferObject {
var __buffer: ByteBuffer! { get }
/// FlatbuffersInitializable is a protocol that allows any object to be
/// Initialized from a ByteBuffer
public protocol FlatbuffersInitializable {
init(_ bb: ByteBuffer, o: Int32)
}
/// FlatbufferObject structures all the Flatbuffers objects
public protocol FlatBufferObject: FlatbuffersInitializable {
var __buffer: ByteBuffer! { get }
}
public protocol ObjectAPIPacker {
associatedtype T
static func pack(_ builder: inout FlatBufferBuilder, obj: inout T) -> Offset<UOffset>
static func pack(_ builder: inout FlatBufferBuilder, obj: inout T?) -> Offset
static func pack(_ builder: inout FlatBufferBuilder, obj: inout T) -> Offset
mutating func unpack() -> T
}

View File

@@ -17,7 +17,7 @@
import Foundation
/// Offset object for all the Objects that are written into the buffer
public struct Offset<T> {
public struct Offset {
/// Offset of the object in the buffer
public var o: UOffset
/// Returns false if the offset is equal to zero

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2021 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 Foundation
extension String: FlatbuffersInitializable {
/// Initailizes a string from a Flatbuffers ByteBuffer
/// - Parameters:
/// - bb: ByteBuffer containing the readable string
/// - o: Current position
public init(_ bb: ByteBuffer, o: Int32) {
let count = bb.read(def: Int32.self, position: Int(o))
self = bb.readString(
at: Int32(MemoryLayout<Int32>.size) + o,
count: count) ?? ""
}
}
extension String: ObjectAPIPacker {
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 {
builder.create(string: obj)
}
public mutating func unpack() -> String {
self
}
}
extension String: NativeObject {
public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer where T.T == Self {
fatalError("serialize should never be called from string directly")
}
public func serialize<T: ObjectAPIPacker>(builder: inout FlatBufferBuilder, type: T.Type) -> ByteBuffer where T.T == Self {
fatalError("serialize should never be called from string directly")
}
}

View File

@@ -80,12 +80,12 @@ public struct Table {
return r
}
public func union<T: FlatBufferObject>(_ o: Int32) -> T {
public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T {
let o = o + postion
return directUnion(o)
}
public func directUnion<T: FlatBufferObject>(_ o: Int32) -> T {
public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T {
T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o)))
}