1*890232f2SAndroid Build Coastguard Worker /* 2*890232f2SAndroid Build Coastguard Worker * Copyright 2021 Google Inc. All rights reserved. 3*890232f2SAndroid Build Coastguard Worker * 4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*890232f2SAndroid Build Coastguard Worker * 8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*890232f2SAndroid Build Coastguard Worker * 10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*890232f2SAndroid Build Coastguard Worker * limitations under the License. 15*890232f2SAndroid Build Coastguard Worker */ 16*890232f2SAndroid Build Coastguard Worker 17*890232f2SAndroid Build Coastguard Worker #if !os(WASI) 18*890232f2SAndroid Build Coastguard Worker import Foundation 19*890232f2SAndroid Build Coastguard Worker #else 20*890232f2SAndroid Build Coastguard Worker import SwiftOverlayShims 21*890232f2SAndroid Build Coastguard Worker #endif 22*890232f2SAndroid Build Coastguard Worker 23*890232f2SAndroid Build Coastguard Worker /// ``FlatBufferBuilder`` builds a `FlatBuffer` through manipulating its internal state. 24*890232f2SAndroid Build Coastguard Worker /// 25*890232f2SAndroid Build Coastguard Worker /// This is done by creating a ``ByteBuffer`` that hosts the incoming data and 26*890232f2SAndroid Build Coastguard Worker /// has a hardcoded growth limit of `2GiB` which is set by the Flatbuffers standards. 27*890232f2SAndroid Build Coastguard Worker /// 28*890232f2SAndroid Build Coastguard Worker /// ```swift 29*890232f2SAndroid Build Coastguard Worker /// var builder = FlatBufferBuilder() 30*890232f2SAndroid Build Coastguard Worker /// ``` 31*890232f2SAndroid Build Coastguard Worker /// The builder should be always created as a variable, since it would be passed into the writers 32*890232f2SAndroid Build Coastguard Worker /// 33*890232f2SAndroid Build Coastguard Worker @frozen 34*890232f2SAndroid Build Coastguard Worker public struct FlatBufferBuilder { 35*890232f2SAndroid Build Coastguard Worker 36*890232f2SAndroid Build Coastguard Worker /// Storage for the Vtables used in the buffer are stored in here, so they would be written later in EndTable 37*890232f2SAndroid Build Coastguard Worker @usableFromInline internal var _vtableStorage = VTableStorage() 38*890232f2SAndroid Build Coastguard Worker /// Flatbuffer data will be written into 39*890232f2SAndroid Build Coastguard Worker @usableFromInline internal var _bb: ByteBuffer 40*890232f2SAndroid Build Coastguard Worker 41*890232f2SAndroid Build Coastguard Worker /// Reference Vtables that were already written to the buffer 42*890232f2SAndroid Build Coastguard Worker private var _vtables: [UOffset] = [] 43*890232f2SAndroid Build Coastguard Worker /// A check if the buffer is being written into by a different table 44*890232f2SAndroid Build Coastguard Worker private var isNested = false 45*890232f2SAndroid Build Coastguard Worker /// Dictonary that stores a map of all the strings that were written to the buffer 46*890232f2SAndroid Build Coastguard Worker private var stringOffsetMap: [String: Offset] = [:] 47*890232f2SAndroid Build Coastguard Worker /// A check to see if finish(::) was ever called to retreive data object 48*890232f2SAndroid Build Coastguard Worker private var finished = false 49*890232f2SAndroid Build Coastguard Worker /// A check to see if the buffer should serialize Default values 50*890232f2SAndroid Build Coastguard Worker private var serializeDefaults: Bool 51*890232f2SAndroid Build Coastguard Worker 52*890232f2SAndroid Build Coastguard Worker /// Current alignment for the buffer 53*890232f2SAndroid Build Coastguard Worker var _minAlignment: Int = 0 { 54*890232f2SAndroid Build Coastguard Worker didSet { 55*890232f2SAndroid Build Coastguard Worker _bb.alignment = _minAlignment 56*890232f2SAndroid Build Coastguard Worker } 57*890232f2SAndroid Build Coastguard Worker } 58*890232f2SAndroid Build Coastguard Worker 59*890232f2SAndroid Build Coastguard Worker /// Gives a read access to the buffer's size 60*890232f2SAndroid Build Coastguard Worker public var size: UOffset { _bb.size } 61*890232f2SAndroid Build Coastguard Worker 62*890232f2SAndroid Build Coastguard Worker #if !os(WASI) 63*890232f2SAndroid Build Coastguard Worker /// Data representation of the buffer 64*890232f2SAndroid Build Coastguard Worker /// 65*890232f2SAndroid Build Coastguard Worker /// Should only be used after ``finish(offset:addPrefix:)`` is called 66*890232f2SAndroid Build Coastguard Worker public var data: Data { 67*890232f2SAndroid Build Coastguard Worker assert(finished, "Data shouldn't be called before finish()") 68*890232f2SAndroid Build Coastguard Worker return Data( 69*890232f2SAndroid Build Coastguard Worker bytes: _bb.memory.advanced(by: _bb.writerIndex), 70*890232f2SAndroid Build Coastguard Worker count: _bb.capacity &- _bb.writerIndex) 71*890232f2SAndroid Build Coastguard Worker } 72*890232f2SAndroid Build Coastguard Worker #endif 73*890232f2SAndroid Build Coastguard Worker 74*890232f2SAndroid Build Coastguard Worker /// Returns the underlying bytes in the ``ByteBuffer`` 75*890232f2SAndroid Build Coastguard Worker /// 76*890232f2SAndroid Build Coastguard Worker /// Note: This should be used with caution. 77*890232f2SAndroid Build Coastguard Worker public var fullSizedByteArray: [UInt8] { 78*890232f2SAndroid Build Coastguard Worker let ptr = UnsafeBufferPointer( 79*890232f2SAndroid Build Coastguard Worker start: _bb.memory.assumingMemoryBound(to: UInt8.self), 80*890232f2SAndroid Build Coastguard Worker count: _bb.capacity) 81*890232f2SAndroid Build Coastguard Worker return Array(ptr) 82*890232f2SAndroid Build Coastguard Worker } 83*890232f2SAndroid Build Coastguard Worker 84*890232f2SAndroid Build Coastguard Worker /// Returns the written bytes into the ``ByteBuffer`` 85*890232f2SAndroid Build Coastguard Worker /// 86*890232f2SAndroid Build Coastguard Worker /// Should only be used after ``finish(offset:addPrefix:)`` is called 87*890232f2SAndroid Build Coastguard Worker public var sizedByteArray: [UInt8] { 88*890232f2SAndroid Build Coastguard Worker assert(finished, "Data shouldn't be called before finish()") 89*890232f2SAndroid Build Coastguard Worker return _bb.underlyingBytes 90*890232f2SAndroid Build Coastguard Worker } 91*890232f2SAndroid Build Coastguard Worker 92*890232f2SAndroid Build Coastguard Worker /// Returns the original ``ByteBuffer`` 93*890232f2SAndroid Build Coastguard Worker /// 94*890232f2SAndroid Build Coastguard Worker /// Returns the current buffer that was just created 95*890232f2SAndroid Build Coastguard Worker /// with the offsets, and data written to it. 96*890232f2SAndroid Build Coastguard Worker public var buffer: ByteBuffer { _bb } 97*890232f2SAndroid Build Coastguard Worker 98*890232f2SAndroid Build Coastguard Worker /// Returns a newly created sized ``ByteBuffer`` 99*890232f2SAndroid Build Coastguard Worker /// 100*890232f2SAndroid Build Coastguard Worker /// returns a new buffer that is sized to the data written 101*890232f2SAndroid Build Coastguard Worker /// to the main buffer 102*890232f2SAndroid Build Coastguard Worker public var sizedBuffer: ByteBuffer { 103*890232f2SAndroid Build Coastguard Worker assert(finished, "Data shouldn't be called before finish()") 104*890232f2SAndroid Build Coastguard Worker return ByteBuffer( 105*890232f2SAndroid Build Coastguard Worker memory: _bb.memory.advanced(by: _bb.reader), 106*890232f2SAndroid Build Coastguard Worker count: Int(_bb.size)) 107*890232f2SAndroid Build Coastguard Worker } 108*890232f2SAndroid Build Coastguard Worker 109*890232f2SAndroid Build Coastguard Worker // MARK: - Init 110*890232f2SAndroid Build Coastguard Worker 111*890232f2SAndroid Build Coastguard Worker /// Initialize the buffer with a size 112*890232f2SAndroid Build Coastguard Worker /// - Parameters: 113*890232f2SAndroid Build Coastguard Worker /// - initialSize: Initial size for the buffer 114*890232f2SAndroid Build Coastguard Worker /// - force: Allows default to be serialized into the buffer 115*890232f2SAndroid Build Coastguard Worker /// 116*890232f2SAndroid Build Coastguard Worker /// This initializes a new builder with an initialSize that would initialize 117*890232f2SAndroid Build Coastguard Worker /// a new ``ByteBuffer``. ``FlatBufferBuilder`` by default doesnt serialize defaults 118*890232f2SAndroid Build Coastguard Worker /// however the builder can be force by passing true for `serializeDefaults` 119*890232f2SAndroid Build Coastguard Worker public init( 120*890232f2SAndroid Build Coastguard Worker initialSize: Int32 = 1024, 121*890232f2SAndroid Build Coastguard Worker serializeDefaults force: Bool = false) 122*890232f2SAndroid Build Coastguard Worker { 123*890232f2SAndroid Build Coastguard Worker assert(initialSize > 0, "Size should be greater than zero!") 124*890232f2SAndroid Build Coastguard Worker guard isLitteEndian else { 125*890232f2SAndroid Build Coastguard Worker fatalError( 126*890232f2SAndroid Build Coastguard Worker "Reading/Writing a buffer in big endian machine is not supported on swift") 127*890232f2SAndroid Build Coastguard Worker } 128*890232f2SAndroid Build Coastguard Worker serializeDefaults = force 129*890232f2SAndroid Build Coastguard Worker _bb = ByteBuffer(initialSize: Int(initialSize)) 130*890232f2SAndroid Build Coastguard Worker } 131*890232f2SAndroid Build Coastguard Worker 132*890232f2SAndroid Build Coastguard Worker /// Clears the builder and the buffer from the written data. clearnull133*890232f2SAndroid Build Coastguard Worker mutating public func clear() { 134*890232f2SAndroid Build Coastguard Worker _minAlignment = 0 135*890232f2SAndroid Build Coastguard Worker isNested = false 136*890232f2SAndroid Build Coastguard Worker stringOffsetMap.removeAll(keepingCapacity: true) 137*890232f2SAndroid Build Coastguard Worker _vtables.removeAll(keepingCapacity: true) 138*890232f2SAndroid Build Coastguard Worker _vtableStorage.clear() 139*890232f2SAndroid Build Coastguard Worker _bb.clear() 140*890232f2SAndroid Build Coastguard Worker } 141*890232f2SAndroid Build Coastguard Worker 142*890232f2SAndroid Build Coastguard Worker // MARK: - Create Tables 143*890232f2SAndroid Build Coastguard Worker 144*890232f2SAndroid Build Coastguard Worker /// Checks if the required fields were serialized into the buffer 145*890232f2SAndroid Build Coastguard Worker /// - Parameters: 146*890232f2SAndroid Build Coastguard Worker /// - table: offset for the table 147*890232f2SAndroid Build Coastguard Worker /// - fields: Array of all the important fields to be serialized 148*890232f2SAndroid Build Coastguard Worker /// 149*890232f2SAndroid Build Coastguard Worker /// *NOTE: Never call this function, this is only supposed to be called 150*890232f2SAndroid Build Coastguard Worker /// by the generated code* 151*890232f2SAndroid Build Coastguard Worker @inline(__always) requirenull152*890232f2SAndroid Build Coastguard Worker mutating public func require(table: Offset, fields: [Int32]) { 153*890232f2SAndroid Build Coastguard Worker for field in fields { 154*890232f2SAndroid Build Coastguard Worker let start = _bb.capacity &- Int(table.o) 155*890232f2SAndroid Build Coastguard Worker let startTable = start &- Int(_bb.read(def: Int32.self, position: start)) 156*890232f2SAndroid Build Coastguard Worker let isOkay = _bb.read( 157*890232f2SAndroid Build Coastguard Worker def: VOffset.self, 158*890232f2SAndroid Build Coastguard Worker position: startTable &+ Int(field)) != 0 159*890232f2SAndroid Build Coastguard Worker assert(isOkay, "Flatbuffers requires the following field") 160*890232f2SAndroid Build Coastguard Worker } 161*890232f2SAndroid Build Coastguard Worker } 162*890232f2SAndroid Build Coastguard Worker 163*890232f2SAndroid Build Coastguard Worker /// Finished the buffer by adding the file id and then calling finish 164*890232f2SAndroid Build Coastguard Worker /// - Parameters: 165*890232f2SAndroid Build Coastguard Worker /// - offset: Offset of the table 166*890232f2SAndroid Build Coastguard Worker /// - fileId: Takes the fileId 167*890232f2SAndroid Build Coastguard Worker /// - prefix: if false it wont add the size of the buffer 168*890232f2SAndroid Build Coastguard Worker /// 169*890232f2SAndroid Build Coastguard Worker /// ``finish(offset:fileId:addPrefix:)`` should be called at the end of creating 170*890232f2SAndroid Build Coastguard Worker /// a table 171*890232f2SAndroid Build Coastguard Worker /// ```swift 172*890232f2SAndroid Build Coastguard Worker /// var root = SomeObject 173*890232f2SAndroid Build Coastguard Worker /// .createObject(&builder, 174*890232f2SAndroid Build Coastguard Worker /// name: nameOffset) 175*890232f2SAndroid Build Coastguard Worker /// builder.finish( 176*890232f2SAndroid Build Coastguard Worker /// offset: root, 177*890232f2SAndroid Build Coastguard Worker /// fileId: "ax1a", 178*890232f2SAndroid Build Coastguard Worker /// addPrefix: true) 179*890232f2SAndroid Build Coastguard Worker /// ``` 180*890232f2SAndroid Build Coastguard Worker /// File id would append a file id name at the end of the written bytes before, 181*890232f2SAndroid Build Coastguard Worker /// finishing the buffer. 182*890232f2SAndroid Build Coastguard Worker /// 183*890232f2SAndroid Build Coastguard Worker /// Whereas, if `addPrefix` is true, the written bytes would 184*890232f2SAndroid Build Coastguard Worker /// include the size of the current buffer. 185*890232f2SAndroid Build Coastguard Worker mutating public func finish( 186*890232f2SAndroid Build Coastguard Worker offset: Offset, 187*890232f2SAndroid Build Coastguard Worker fileId: String, 188*890232f2SAndroid Build Coastguard Worker addPrefix prefix: Bool = false) 189*890232f2SAndroid Build Coastguard Worker { 190*890232f2SAndroid Build Coastguard Worker let size = MemoryLayout<UOffset>.size 191*890232f2SAndroid Build Coastguard Worker preAlign( 192*890232f2SAndroid Build Coastguard Worker len: size &+ (prefix ? size : 0) &+ FileIdLength, 193*890232f2SAndroid Build Coastguard Worker alignment: _minAlignment) 194*890232f2SAndroid Build Coastguard Worker assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4") 195*890232f2SAndroid Build Coastguard Worker _bb.push(string: fileId, len: 4) 196*890232f2SAndroid Build Coastguard Worker finish(offset: offset, addPrefix: prefix) 197*890232f2SAndroid Build Coastguard Worker } 198*890232f2SAndroid Build Coastguard Worker 199*890232f2SAndroid Build Coastguard Worker /// Finished the buffer by adding the file id, offset, and prefix to it. 200*890232f2SAndroid Build Coastguard Worker /// - Parameters: 201*890232f2SAndroid Build Coastguard Worker /// - offset: Offset of the table 202*890232f2SAndroid Build Coastguard Worker /// - prefix: if false it wont add the size of the buffer 203*890232f2SAndroid Build Coastguard Worker /// 204*890232f2SAndroid Build Coastguard Worker /// ``finish(offset:addPrefix:)`` should be called at the end of creating 205*890232f2SAndroid Build Coastguard Worker /// a table 206*890232f2SAndroid Build Coastguard Worker /// ```swift 207*890232f2SAndroid Build Coastguard Worker /// var root = SomeObject 208*890232f2SAndroid Build Coastguard Worker /// .createObject(&builder, 209*890232f2SAndroid Build Coastguard Worker /// name: nameOffset) 210*890232f2SAndroid Build Coastguard Worker /// builder.finish( 211*890232f2SAndroid Build Coastguard Worker /// offset: root, 212*890232f2SAndroid Build Coastguard Worker /// addPrefix: true) 213*890232f2SAndroid Build Coastguard Worker /// ``` 214*890232f2SAndroid Build Coastguard Worker /// If `addPrefix` is true, the written bytes would 215*890232f2SAndroid Build Coastguard Worker /// include the size of the current buffer. 216*890232f2SAndroid Build Coastguard Worker mutating public func finish( 217*890232f2SAndroid Build Coastguard Worker offset: Offset, 218*890232f2SAndroid Build Coastguard Worker addPrefix prefix: Bool = false) 219*890232f2SAndroid Build Coastguard Worker { 220*890232f2SAndroid Build Coastguard Worker notNested() 221*890232f2SAndroid Build Coastguard Worker let size = MemoryLayout<UOffset>.size 222*890232f2SAndroid Build Coastguard Worker preAlign(len: size &+ (prefix ? size : 0), alignment: _minAlignment) 223*890232f2SAndroid Build Coastguard Worker push(element: refer(to: offset.o)) 224*890232f2SAndroid Build Coastguard Worker if prefix { push(element: _bb.size) } 225*890232f2SAndroid Build Coastguard Worker _vtableStorage.clear() 226*890232f2SAndroid Build Coastguard Worker finished = true 227*890232f2SAndroid Build Coastguard Worker } 228*890232f2SAndroid Build Coastguard Worker 229*890232f2SAndroid Build Coastguard Worker /// ``startTable(with:)`` will let the builder know, that a new object is being serialized. 230*890232f2SAndroid Build Coastguard Worker /// 231*890232f2SAndroid Build Coastguard Worker /// The function will fatalerror if called while there is another object being serialized. 232*890232f2SAndroid Build Coastguard Worker /// ```swift 233*890232f2SAndroid Build Coastguard Worker /// let start = Monster 234*890232f2SAndroid Build Coastguard Worker /// .startMonster(&fbb) 235*890232f2SAndroid Build Coastguard Worker /// ``` 236*890232f2SAndroid Build Coastguard Worker /// - Parameter numOfFields: Number of elements to be written to the buffer 237*890232f2SAndroid Build Coastguard Worker /// - Returns: Offset of the newly started table 238*890232f2SAndroid Build Coastguard Worker @inline(__always) startTablenull239*890232f2SAndroid Build Coastguard Worker mutating public func startTable(with numOfFields: Int) -> UOffset { 240*890232f2SAndroid Build Coastguard Worker notNested() 241*890232f2SAndroid Build Coastguard Worker isNested = true 242*890232f2SAndroid Build Coastguard Worker _vtableStorage.start(count: numOfFields) 243*890232f2SAndroid Build Coastguard Worker return _bb.size 244*890232f2SAndroid Build Coastguard Worker } 245*890232f2SAndroid Build Coastguard Worker 246*890232f2SAndroid Build Coastguard Worker /// ``endTable(at:)`` will let the ``FlatBufferBuilder`` know that the 247*890232f2SAndroid Build Coastguard Worker /// object that's written to it is completed 248*890232f2SAndroid Build Coastguard Worker /// 249*890232f2SAndroid Build Coastguard Worker /// This would be called after all the elements are serialized, 250*890232f2SAndroid Build Coastguard Worker /// it will add the current vtable into the ``ByteBuffer``. 251*890232f2SAndroid Build Coastguard Worker /// The functions will `fatalError` in case the object is called 252*890232f2SAndroid Build Coastguard Worker /// without ``startTable(with:)``, or the object has exceeded the limit of 2GB. 253*890232f2SAndroid Build Coastguard Worker /// 254*890232f2SAndroid Build Coastguard Worker /// - Parameter startOffset:Start point of the object written 255*890232f2SAndroid Build Coastguard Worker /// - returns: The root of the table endTablenull256*890232f2SAndroid Build Coastguard Worker mutating public func endTable(at startOffset: UOffset) -> UOffset { 257*890232f2SAndroid Build Coastguard Worker assert(isNested, "Calling endtable without calling starttable") 258*890232f2SAndroid Build Coastguard Worker let sizeofVoffset = MemoryLayout<VOffset>.size 259*890232f2SAndroid Build Coastguard Worker let vTableOffset = push(element: SOffset(0)) 260*890232f2SAndroid Build Coastguard Worker 261*890232f2SAndroid Build Coastguard Worker let tableObjectSize = vTableOffset &- startOffset 262*890232f2SAndroid Build Coastguard Worker assert(tableObjectSize < 0x10000, "Buffer can't grow beyond 2 Gigabytes") 263*890232f2SAndroid Build Coastguard Worker let _max = Int(_vtableStorage.maxOffset) &+ sizeofVoffset 264*890232f2SAndroid Build Coastguard Worker 265*890232f2SAndroid Build Coastguard Worker _bb.fill(padding: _max) 266*890232f2SAndroid Build Coastguard Worker _bb.write( 267*890232f2SAndroid Build Coastguard Worker value: VOffset(tableObjectSize), 268*890232f2SAndroid Build Coastguard Worker index: _bb.writerIndex &+ sizeofVoffset, 269*890232f2SAndroid Build Coastguard Worker direct: true) 270*890232f2SAndroid Build Coastguard Worker _bb.write(value: VOffset(_max), index: _bb.writerIndex, direct: true) 271*890232f2SAndroid Build Coastguard Worker 272*890232f2SAndroid Build Coastguard Worker var itr = 0 273*890232f2SAndroid Build Coastguard Worker while itr < _vtableStorage.writtenIndex { 274*890232f2SAndroid Build Coastguard Worker let loaded = _vtableStorage.load(at: itr) 275*890232f2SAndroid Build Coastguard Worker itr = itr &+ _vtableStorage.size 276*890232f2SAndroid Build Coastguard Worker guard loaded.offset != 0 else { continue } 277*890232f2SAndroid Build Coastguard Worker let _index = (_bb.writerIndex &+ Int(loaded.position)) 278*890232f2SAndroid Build Coastguard Worker _bb.write( 279*890232f2SAndroid Build Coastguard Worker value: VOffset(vTableOffset &- loaded.offset), 280*890232f2SAndroid Build Coastguard Worker index: _index, 281*890232f2SAndroid Build Coastguard Worker direct: true) 282*890232f2SAndroid Build Coastguard Worker } 283*890232f2SAndroid Build Coastguard Worker 284*890232f2SAndroid Build Coastguard Worker _vtableStorage.clear() 285*890232f2SAndroid Build Coastguard Worker let vt_use = _bb.size 286*890232f2SAndroid Build Coastguard Worker 287*890232f2SAndroid Build Coastguard Worker var isAlreadyAdded: Int? 288*890232f2SAndroid Build Coastguard Worker 289*890232f2SAndroid Build Coastguard Worker let vt2 = _bb.memory.advanced(by: _bb.writerIndex) 290*890232f2SAndroid Build Coastguard Worker let len2 = vt2.load(fromByteOffset: 0, as: Int16.self) 291*890232f2SAndroid Build Coastguard Worker 292*890232f2SAndroid Build Coastguard Worker for table in _vtables { 293*890232f2SAndroid Build Coastguard Worker let position = _bb.capacity &- Int(table) 294*890232f2SAndroid Build Coastguard Worker let vt1 = _bb.memory.advanced(by: position) 295*890232f2SAndroid Build Coastguard Worker let len1 = _bb.read(def: Int16.self, position: position) 296*890232f2SAndroid Build Coastguard Worker if len2 != len1 || 0 != memcmp(vt1, vt2, Int(len2)) { continue } 297*890232f2SAndroid Build Coastguard Worker 298*890232f2SAndroid Build Coastguard Worker isAlreadyAdded = Int(table) 299*890232f2SAndroid Build Coastguard Worker break 300*890232f2SAndroid Build Coastguard Worker } 301*890232f2SAndroid Build Coastguard Worker 302*890232f2SAndroid Build Coastguard Worker if let offset = isAlreadyAdded { 303*890232f2SAndroid Build Coastguard Worker let vTableOff = Int(vTableOffset) 304*890232f2SAndroid Build Coastguard Worker let space = _bb.capacity &- vTableOff 305*890232f2SAndroid Build Coastguard Worker _bb.write(value: Int32(offset &- vTableOff), index: space, direct: true) 306*890232f2SAndroid Build Coastguard Worker _bb.pop(_bb.capacity &- space) 307*890232f2SAndroid Build Coastguard Worker } else { 308*890232f2SAndroid Build Coastguard Worker _bb.write(value: Int32(vt_use &- vTableOffset), index: Int(vTableOffset)) 309*890232f2SAndroid Build Coastguard Worker _vtables.append(_bb.size) 310*890232f2SAndroid Build Coastguard Worker } 311*890232f2SAndroid Build Coastguard Worker isNested = false 312*890232f2SAndroid Build Coastguard Worker return vTableOffset 313*890232f2SAndroid Build Coastguard Worker } 314*890232f2SAndroid Build Coastguard Worker 315*890232f2SAndroid Build Coastguard Worker // MARK: - Builds Buffer 316*890232f2SAndroid Build Coastguard Worker 317*890232f2SAndroid Build Coastguard Worker /// Asserts to see if the object is not nested 318*890232f2SAndroid Build Coastguard Worker @inline(__always) 319*890232f2SAndroid Build Coastguard Worker @usableFromInline notNestednull320*890232f2SAndroid Build Coastguard Worker mutating internal func notNested() { 321*890232f2SAndroid Build Coastguard Worker assert(!isNested, "Object serialization must not be nested") 322*890232f2SAndroid Build Coastguard Worker } 323*890232f2SAndroid Build Coastguard Worker 324*890232f2SAndroid Build Coastguard Worker /// Changes the minimuim alignment of the buffer 325*890232f2SAndroid Build Coastguard Worker /// - Parameter size: size of the current alignment 326*890232f2SAndroid Build Coastguard Worker @inline(__always) 327*890232f2SAndroid Build Coastguard Worker @usableFromInline minAlignmentnull328*890232f2SAndroid Build Coastguard Worker mutating internal func minAlignment(size: Int) { 329*890232f2SAndroid Build Coastguard Worker if size > _minAlignment { 330*890232f2SAndroid Build Coastguard Worker _minAlignment = size 331*890232f2SAndroid Build Coastguard Worker } 332*890232f2SAndroid Build Coastguard Worker } 333*890232f2SAndroid Build Coastguard Worker 334*890232f2SAndroid Build Coastguard Worker /// Gets the padding for the current element 335*890232f2SAndroid Build Coastguard Worker /// - Parameters: 336*890232f2SAndroid Build Coastguard Worker /// - bufSize: Current size of the buffer + the offset of the object to be written 337*890232f2SAndroid Build Coastguard Worker /// - elementSize: Element size 338*890232f2SAndroid Build Coastguard Worker @inline(__always) 339*890232f2SAndroid Build Coastguard Worker @usableFromInline 340*890232f2SAndroid Build Coastguard Worker mutating internal func padding( 341*890232f2SAndroid Build Coastguard Worker bufSize: UInt32, 342*890232f2SAndroid Build Coastguard Worker elementSize: UInt32) -> UInt32 343*890232f2SAndroid Build Coastguard Worker { 344*890232f2SAndroid Build Coastguard Worker ((~bufSize) &+ 1) & (elementSize - 1) 345*890232f2SAndroid Build Coastguard Worker } 346*890232f2SAndroid Build Coastguard Worker 347*890232f2SAndroid Build Coastguard Worker /// Prealigns the buffer before writting a new object into the buffer 348*890232f2SAndroid Build Coastguard Worker /// - Parameters: 349*890232f2SAndroid Build Coastguard Worker /// - len:Length of the object 350*890232f2SAndroid Build Coastguard Worker /// - alignment: Alignment type 351*890232f2SAndroid Build Coastguard Worker @inline(__always) 352*890232f2SAndroid Build Coastguard Worker @usableFromInline preAlignnull353*890232f2SAndroid Build Coastguard Worker mutating internal func preAlign(len: Int, alignment: Int) { 354*890232f2SAndroid Build Coastguard Worker minAlignment(size: alignment) 355*890232f2SAndroid Build Coastguard Worker _bb.fill(padding: Int(padding( 356*890232f2SAndroid Build Coastguard Worker bufSize: _bb.size &+ UOffset(len), 357*890232f2SAndroid Build Coastguard Worker elementSize: UOffset(alignment)))) 358*890232f2SAndroid Build Coastguard Worker } 359*890232f2SAndroid Build Coastguard Worker 360*890232f2SAndroid Build Coastguard Worker /// Prealigns the buffer before writting a new object into the buffer 361*890232f2SAndroid Build Coastguard Worker /// - Parameters: 362*890232f2SAndroid Build Coastguard Worker /// - len: Length of the object 363*890232f2SAndroid Build Coastguard Worker /// - type: Type of the object to be written 364*890232f2SAndroid Build Coastguard Worker @inline(__always) 365*890232f2SAndroid Build Coastguard Worker @usableFromInline preAlign<T: Scalar>null366*890232f2SAndroid Build Coastguard Worker mutating internal func preAlign<T: Scalar>(len: Int, type: T.Type) { 367*890232f2SAndroid Build Coastguard Worker preAlign(len: len, alignment: MemoryLayout<T>.size) 368*890232f2SAndroid Build Coastguard Worker } 369*890232f2SAndroid Build Coastguard Worker 370*890232f2SAndroid Build Coastguard Worker /// Refers to an object that's written in the buffer 371*890232f2SAndroid Build Coastguard Worker /// - Parameter off: the objects index value 372*890232f2SAndroid Build Coastguard Worker @inline(__always) 373*890232f2SAndroid Build Coastguard Worker @usableFromInline refernull374*890232f2SAndroid Build Coastguard Worker mutating internal func refer(to off: UOffset) -> UOffset { 375*890232f2SAndroid Build Coastguard Worker let size = MemoryLayout<UOffset>.size 376*890232f2SAndroid Build Coastguard Worker preAlign(len: size, alignment: size) 377*890232f2SAndroid Build Coastguard Worker return _bb.size &- off &+ UInt32(size) 378*890232f2SAndroid Build Coastguard Worker } 379*890232f2SAndroid Build Coastguard Worker 380*890232f2SAndroid Build Coastguard Worker /// Tracks the elements written into the buffer 381*890232f2SAndroid Build Coastguard Worker /// - Parameters: 382*890232f2SAndroid Build Coastguard Worker /// - offset: The offset of the element witten 383*890232f2SAndroid Build Coastguard Worker /// - position: The position of the element 384*890232f2SAndroid Build Coastguard Worker @inline(__always) 385*890232f2SAndroid Build Coastguard Worker @usableFromInline tracknull386*890232f2SAndroid Build Coastguard Worker mutating internal func track(offset: UOffset, at position: VOffset) { 387*890232f2SAndroid Build Coastguard Worker _vtableStorage.add(loc: FieldLoc(offset: offset, position: position)) 388*890232f2SAndroid Build Coastguard Worker } 389*890232f2SAndroid Build Coastguard Worker 390*890232f2SAndroid Build Coastguard Worker // MARK: - Inserting Vectors 391*890232f2SAndroid Build Coastguard Worker 392*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` creates a new vector within buffer 393*890232f2SAndroid Build Coastguard Worker /// 394*890232f2SAndroid Build Coastguard Worker /// The function checks if there is a current object being written, if 395*890232f2SAndroid Build Coastguard Worker /// the check passes it creates a buffer alignment of `length * elementSize` 396*890232f2SAndroid Build Coastguard Worker /// ```swift 397*890232f2SAndroid Build Coastguard Worker /// builder.startVector( 398*890232f2SAndroid Build Coastguard Worker /// int32Values.count, elementSize: 4) 399*890232f2SAndroid Build Coastguard Worker /// ``` 400*890232f2SAndroid Build Coastguard Worker /// 401*890232f2SAndroid Build Coastguard Worker /// - Parameters: 402*890232f2SAndroid Build Coastguard Worker /// - len: Length of vector to be created 403*890232f2SAndroid Build Coastguard Worker /// - elementSize: Size of object type to be written 404*890232f2SAndroid Build Coastguard Worker @inline(__always) startVectornull405*890232f2SAndroid Build Coastguard Worker mutating public func startVector(_ len: Int, elementSize: Int) { 406*890232f2SAndroid Build Coastguard Worker notNested() 407*890232f2SAndroid Build Coastguard Worker isNested = true 408*890232f2SAndroid Build Coastguard Worker preAlign(len: len &* elementSize, type: UOffset.self) 409*890232f2SAndroid Build Coastguard Worker preAlign(len: len &* elementSize, alignment: elementSize) 410*890232f2SAndroid Build Coastguard Worker } 411*890232f2SAndroid Build Coastguard Worker 412*890232f2SAndroid Build Coastguard Worker /// ``endVector(len:)`` ends the currently created vector 413*890232f2SAndroid Build Coastguard Worker /// 414*890232f2SAndroid Build Coastguard Worker /// Calling ``endVector(len:)`` requires the length, of the current 415*890232f2SAndroid Build Coastguard Worker /// vector. The length would be pushed to indicate the count of numbers 416*890232f2SAndroid Build Coastguard Worker /// within the vector. If ``endVector(len:)`` is called without 417*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` it asserts. 418*890232f2SAndroid Build Coastguard Worker /// 419*890232f2SAndroid Build Coastguard Worker /// ```swift 420*890232f2SAndroid Build Coastguard Worker /// let vectorOffset = builder. 421*890232f2SAndroid Build Coastguard Worker /// endVector(len: int32Values.count) 422*890232f2SAndroid Build Coastguard Worker /// ``` 423*890232f2SAndroid Build Coastguard Worker /// 424*890232f2SAndroid Build Coastguard Worker /// - Parameter len: Length of the buffer 425*890232f2SAndroid Build Coastguard Worker /// - Returns: Returns the current ``Offset`` in the ``ByteBuffer`` 426*890232f2SAndroid Build Coastguard Worker @inline(__always) endVectornull427*890232f2SAndroid Build Coastguard Worker mutating public func endVector(len: Int) -> Offset { 428*890232f2SAndroid Build Coastguard Worker assert(isNested, "Calling endVector without calling startVector") 429*890232f2SAndroid Build Coastguard Worker isNested = false 430*890232f2SAndroid Build Coastguard Worker return Offset(offset: push(element: Int32(len))) 431*890232f2SAndroid Build Coastguard Worker } 432*890232f2SAndroid Build Coastguard Worker 433*890232f2SAndroid Build Coastguard Worker /// Creates a vector of type ``Scalar`` into the ``ByteBuffer`` 434*890232f2SAndroid Build Coastguard Worker /// 435*890232f2SAndroid Build Coastguard Worker /// ``createVector(_:)-4swl0`` writes a vector of type Scalars into 436*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer``. This is a convenient method instead of calling, 437*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` and then ``endVector(len:)`` 438*890232f2SAndroid Build Coastguard Worker /// ```swift 439*890232f2SAndroid Build Coastguard Worker /// let vectorOffset = builder. 440*890232f2SAndroid Build Coastguard Worker /// createVector([1, 2, 3, 4]) 441*890232f2SAndroid Build Coastguard Worker /// ``` 442*890232f2SAndroid Build Coastguard Worker /// 443*890232f2SAndroid Build Coastguard Worker /// The underlying implementation simply calls ``createVector(_:size:)-4lhrv`` 444*890232f2SAndroid Build Coastguard Worker /// 445*890232f2SAndroid Build Coastguard Worker /// - Parameter elements: elements to be written into the buffer 446*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of the vector 447*890232f2SAndroid Build Coastguard Worker @inline(__always) createVector<T: Scalar>null448*890232f2SAndroid Build Coastguard Worker mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset { 449*890232f2SAndroid Build Coastguard Worker createVector(elements, size: elements.count) 450*890232f2SAndroid Build Coastguard Worker } 451*890232f2SAndroid Build Coastguard Worker 452*890232f2SAndroid Build Coastguard Worker /// Creates a vector of type Scalar in the buffer 453*890232f2SAndroid Build Coastguard Worker /// 454*890232f2SAndroid Build Coastguard Worker /// ``createVector(_:)-4swl0`` writes a vector of type Scalars into 455*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer``. This is a convenient method instead of calling, 456*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` and then ``endVector(len:)`` 457*890232f2SAndroid Build Coastguard Worker /// ```swift 458*890232f2SAndroid Build Coastguard Worker /// let vectorOffset = builder. 459*890232f2SAndroid Build Coastguard Worker /// createVector([1, 2, 3, 4], size: 4) 460*890232f2SAndroid Build Coastguard Worker /// ``` 461*890232f2SAndroid Build Coastguard Worker /// 462*890232f2SAndroid Build Coastguard Worker /// - Parameter elements: Elements to be written into the buffer 463*890232f2SAndroid Build Coastguard Worker /// - Parameter size: Count of elements 464*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of the vector 465*890232f2SAndroid Build Coastguard Worker @inline(__always) 466*890232f2SAndroid Build Coastguard Worker mutating public func createVector<T: Scalar>( 467*890232f2SAndroid Build Coastguard Worker _ elements: [T], 468*890232f2SAndroid Build Coastguard Worker size: Int) -> Offset 469*890232f2SAndroid Build Coastguard Worker { 470*890232f2SAndroid Build Coastguard Worker let size = size 471*890232f2SAndroid Build Coastguard Worker startVector(size, elementSize: MemoryLayout<T>.size) 472*890232f2SAndroid Build Coastguard Worker _bb.push(elements: elements) 473*890232f2SAndroid Build Coastguard Worker return endVector(len: size) 474*890232f2SAndroid Build Coastguard Worker } 475*890232f2SAndroid Build Coastguard Worker 476*890232f2SAndroid Build Coastguard Worker /// Creates a vector of type ``Enum`` into the ``ByteBuffer`` 477*890232f2SAndroid Build Coastguard Worker /// 478*890232f2SAndroid Build Coastguard Worker /// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into 479*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer``. This is a convenient method instead of calling, 480*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` and then ``endVector(len:)`` 481*890232f2SAndroid Build Coastguard Worker /// ```swift 482*890232f2SAndroid Build Coastguard Worker /// let vectorOffset = builder. 483*890232f2SAndroid Build Coastguard Worker /// createVector([.swift, .cpp]) 484*890232f2SAndroid Build Coastguard Worker /// ``` 485*890232f2SAndroid Build Coastguard Worker /// 486*890232f2SAndroid Build Coastguard Worker /// The underlying implementation simply calls ``createVector(_:size:)-7cx6z`` 487*890232f2SAndroid Build Coastguard Worker /// 488*890232f2SAndroid Build Coastguard Worker /// - Parameter elements: elements to be written into the buffer 489*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of the vector 490*890232f2SAndroid Build Coastguard Worker @inline(__always) createVector<T: Enum>null491*890232f2SAndroid Build Coastguard Worker mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset { 492*890232f2SAndroid Build Coastguard Worker createVector(elements, size: elements.count) 493*890232f2SAndroid Build Coastguard Worker } 494*890232f2SAndroid Build Coastguard Worker 495*890232f2SAndroid Build Coastguard Worker /// Creates a vector of type ``Enum`` into the ``ByteBuffer`` 496*890232f2SAndroid Build Coastguard Worker /// 497*890232f2SAndroid Build Coastguard Worker /// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into 498*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer``. This is a convenient method instead of calling, 499*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` and then ``endVector(len:)`` 500*890232f2SAndroid Build Coastguard Worker /// ```swift 501*890232f2SAndroid Build Coastguard Worker /// let vectorOffset = builder. 502*890232f2SAndroid Build Coastguard Worker /// createVector([.swift, .cpp]) 503*890232f2SAndroid Build Coastguard Worker /// ``` 504*890232f2SAndroid Build Coastguard Worker /// 505*890232f2SAndroid Build Coastguard Worker /// - Parameter elements: Elements to be written into the buffer 506*890232f2SAndroid Build Coastguard Worker /// - Parameter size: Count of elements 507*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of the vector 508*890232f2SAndroid Build Coastguard Worker @inline(__always) 509*890232f2SAndroid Build Coastguard Worker mutating public func createVector<T: Enum>( 510*890232f2SAndroid Build Coastguard Worker _ elements: [T], 511*890232f2SAndroid Build Coastguard Worker size: Int) -> Offset 512*890232f2SAndroid Build Coastguard Worker { 513*890232f2SAndroid Build Coastguard Worker let size = size 514*890232f2SAndroid Build Coastguard Worker startVector(size, elementSize: T.byteSize) 515*890232f2SAndroid Build Coastguard Worker for e in elements.reversed() { 516*890232f2SAndroid Build Coastguard Worker _bb.push(value: e.value, len: T.byteSize) 517*890232f2SAndroid Build Coastguard Worker } 518*890232f2SAndroid Build Coastguard Worker return endVector(len: size) 519*890232f2SAndroid Build Coastguard Worker } 520*890232f2SAndroid Build Coastguard Worker 521*890232f2SAndroid Build Coastguard Worker /// Creates a vector of already written offsets 522*890232f2SAndroid Build Coastguard Worker /// 523*890232f2SAndroid Build Coastguard Worker /// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into 524*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer``. This is a convenient method instead of calling, 525*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``. 526*890232f2SAndroid Build Coastguard Worker /// 527*890232f2SAndroid Build Coastguard Worker /// The underlying implementation simply calls ``createVector(ofOffsets:len:)`` 528*890232f2SAndroid Build Coastguard Worker /// 529*890232f2SAndroid Build Coastguard Worker /// ```swift 530*890232f2SAndroid Build Coastguard Worker /// let namesOffsets = builder. 531*890232f2SAndroid Build Coastguard Worker /// createVector(ofOffsets: [name1, name2]) 532*890232f2SAndroid Build Coastguard Worker /// ``` 533*890232f2SAndroid Build Coastguard Worker /// - Parameter offsets: Array of offsets of type ``Offset`` 534*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of the vector 535*890232f2SAndroid Build Coastguard Worker @inline(__always) createVectornull536*890232f2SAndroid Build Coastguard Worker mutating public func createVector(ofOffsets offsets: [Offset]) -> Offset { 537*890232f2SAndroid Build Coastguard Worker createVector(ofOffsets: offsets, len: offsets.count) 538*890232f2SAndroid Build Coastguard Worker } 539*890232f2SAndroid Build Coastguard Worker 540*890232f2SAndroid Build Coastguard Worker /// Creates a vector of already written offsets 541*890232f2SAndroid Build Coastguard Worker /// 542*890232f2SAndroid Build Coastguard Worker /// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into 543*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer``. This is a convenient method instead of calling, 544*890232f2SAndroid Build Coastguard Worker /// ``startVector(_:elementSize:)`` and then ``endVector(len:)`` 545*890232f2SAndroid Build Coastguard Worker /// 546*890232f2SAndroid Build Coastguard Worker /// ```swift 547*890232f2SAndroid Build Coastguard Worker /// let namesOffsets = builder. 548*890232f2SAndroid Build Coastguard Worker /// createVector(ofOffsets: [name1, name2]) 549*890232f2SAndroid Build Coastguard Worker /// ``` 550*890232f2SAndroid Build Coastguard Worker /// 551*890232f2SAndroid Build Coastguard Worker /// - Parameter offsets: Array of offsets of type ``Offset`` 552*890232f2SAndroid Build Coastguard Worker /// - Parameter size: Count of elements 553*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of the vector 554*890232f2SAndroid Build Coastguard Worker @inline(__always) 555*890232f2SAndroid Build Coastguard Worker mutating public func createVector( 556*890232f2SAndroid Build Coastguard Worker ofOffsets offsets: [Offset], 557*890232f2SAndroid Build Coastguard Worker len: Int) -> Offset 558*890232f2SAndroid Build Coastguard Worker { 559*890232f2SAndroid Build Coastguard Worker startVector(len, elementSize: MemoryLayout<Offset>.size) 560*890232f2SAndroid Build Coastguard Worker for o in offsets.reversed() { 561*890232f2SAndroid Build Coastguard Worker push(element: o) 562*890232f2SAndroid Build Coastguard Worker } 563*890232f2SAndroid Build Coastguard Worker return endVector(len: len) 564*890232f2SAndroid Build Coastguard Worker } 565*890232f2SAndroid Build Coastguard Worker 566*890232f2SAndroid Build Coastguard Worker /// Creates a vector of strings 567*890232f2SAndroid Build Coastguard Worker /// 568*890232f2SAndroid Build Coastguard Worker /// ``createVector(ofStrings:)`` creates a vector of `String` into 569*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer``. This is a convenient method instead of manually 570*890232f2SAndroid Build Coastguard Worker /// creating the string offsets, you simply pass it to this function 571*890232f2SAndroid Build Coastguard Worker /// and it would write the strings into the ``ByteBuffer``. 572*890232f2SAndroid Build Coastguard Worker /// After that it calls ``createVector(ofOffsets:)`` 573*890232f2SAndroid Build Coastguard Worker /// 574*890232f2SAndroid Build Coastguard Worker /// ```swift 575*890232f2SAndroid Build Coastguard Worker /// let namesOffsets = builder. 576*890232f2SAndroid Build Coastguard Worker /// createVector(ofStrings: ["Name", "surname"]) 577*890232f2SAndroid Build Coastguard Worker /// ``` 578*890232f2SAndroid Build Coastguard Worker /// 579*890232f2SAndroid Build Coastguard Worker /// - Parameter str: Array of string 580*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of the vector 581*890232f2SAndroid Build Coastguard Worker @inline(__always) createVectornull582*890232f2SAndroid Build Coastguard Worker mutating public func createVector(ofStrings str: [String]) -> Offset { 583*890232f2SAndroid Build Coastguard Worker var offsets: [Offset] = [] 584*890232f2SAndroid Build Coastguard Worker for s in str { 585*890232f2SAndroid Build Coastguard Worker offsets.append(create(string: s)) 586*890232f2SAndroid Build Coastguard Worker } 587*890232f2SAndroid Build Coastguard Worker return createVector(ofOffsets: offsets) 588*890232f2SAndroid Build Coastguard Worker } 589*890232f2SAndroid Build Coastguard Worker 590*890232f2SAndroid Build Coastguard Worker /// Creates a vector of type ``NativeStruct``. 591*890232f2SAndroid Build Coastguard Worker /// 592*890232f2SAndroid Build Coastguard Worker /// Any swift struct in the generated code, should confirm to 593*890232f2SAndroid Build Coastguard Worker /// ``NativeStruct``. Since the generated swift structs are padded 594*890232f2SAndroid Build Coastguard Worker /// to the `FlatBuffers` standards. 595*890232f2SAndroid Build Coastguard Worker /// 596*890232f2SAndroid Build Coastguard Worker /// ```swift 597*890232f2SAndroid Build Coastguard Worker /// let offsets = builder. 598*890232f2SAndroid Build Coastguard Worker /// createVector(ofStructs: [NativeStr(num: 1), NativeStr(num: 2)]) 599*890232f2SAndroid Build Coastguard Worker /// ``` 600*890232f2SAndroid Build Coastguard Worker /// 601*890232f2SAndroid Build Coastguard Worker /// - Parameter structs: A vector of ``NativeStruct`` 602*890232f2SAndroid Build Coastguard Worker /// - Returns: ``Offset`` of the vector 603*890232f2SAndroid Build Coastguard Worker @inline(__always) createVector<T: NativeStruct>null604*890232f2SAndroid Build Coastguard Worker mutating public func createVector<T: NativeStruct>(ofStructs structs: [T]) 605*890232f2SAndroid Build Coastguard Worker -> Offset 606*890232f2SAndroid Build Coastguard Worker { 607*890232f2SAndroid Build Coastguard Worker startVector( 608*890232f2SAndroid Build Coastguard Worker structs.count * MemoryLayout<T>.size, 609*890232f2SAndroid Build Coastguard Worker elementSize: MemoryLayout<T>.alignment) 610*890232f2SAndroid Build Coastguard Worker for i in structs.reversed() { 611*890232f2SAndroid Build Coastguard Worker _ = create(struct: i) 612*890232f2SAndroid Build Coastguard Worker } 613*890232f2SAndroid Build Coastguard Worker return endVector(len: structs.count) 614*890232f2SAndroid Build Coastguard Worker } 615*890232f2SAndroid Build Coastguard Worker 616*890232f2SAndroid Build Coastguard Worker // MARK: - Inserting Structs 617*890232f2SAndroid Build Coastguard Worker 618*890232f2SAndroid Build Coastguard Worker /// Writes a ``NativeStruct`` into the ``ByteBuffer`` 619*890232f2SAndroid Build Coastguard Worker /// 620*890232f2SAndroid Build Coastguard Worker /// Adds a native struct that's build and padded according 621*890232f2SAndroid Build Coastguard Worker /// to `FlatBuffers` standards. with a predefined position. 622*890232f2SAndroid Build Coastguard Worker /// 623*890232f2SAndroid Build Coastguard Worker /// ```swift 624*890232f2SAndroid Build Coastguard Worker /// let offset = builder.create( 625*890232f2SAndroid Build Coastguard Worker /// struct: NativeStr(num: 1), 626*890232f2SAndroid Build Coastguard Worker /// position: 10) 627*890232f2SAndroid Build Coastguard Worker /// ``` 628*890232f2SAndroid Build Coastguard Worker /// 629*890232f2SAndroid Build Coastguard Worker /// - Parameters: 630*890232f2SAndroid Build Coastguard Worker /// - s: ``NativeStruct`` to be inserted into the ``ByteBuffer`` 631*890232f2SAndroid Build Coastguard Worker /// - position: The predefined position of the object 632*890232f2SAndroid Build Coastguard Worker /// - Returns: ``Offset`` of written struct 633*890232f2SAndroid Build Coastguard Worker @inline(__always) 634*890232f2SAndroid Build Coastguard Worker @discardableResult 635*890232f2SAndroid Build Coastguard Worker mutating public func create<T: NativeStruct>( 636*890232f2SAndroid Build Coastguard Worker struct s: T, position: VOffset) -> Offset 637*890232f2SAndroid Build Coastguard Worker { 638*890232f2SAndroid Build Coastguard Worker let offset = create(struct: s) 639*890232f2SAndroid Build Coastguard Worker _vtableStorage.add(loc: FieldLoc( 640*890232f2SAndroid Build Coastguard Worker offset: _bb.size, 641*890232f2SAndroid Build Coastguard Worker position: VOffset(position))) 642*890232f2SAndroid Build Coastguard Worker return offset 643*890232f2SAndroid Build Coastguard Worker } 644*890232f2SAndroid Build Coastguard Worker 645*890232f2SAndroid Build Coastguard Worker /// Writes a ``NativeStruct`` into the ``ByteBuffer`` 646*890232f2SAndroid Build Coastguard Worker /// 647*890232f2SAndroid Build Coastguard Worker /// Adds a native struct that's build and padded according 648*890232f2SAndroid Build Coastguard Worker /// to `FlatBuffers` standards, directly into the buffer without 649*890232f2SAndroid Build Coastguard Worker /// a predefined position. 650*890232f2SAndroid Build Coastguard Worker /// 651*890232f2SAndroid Build Coastguard Worker /// ```swift 652*890232f2SAndroid Build Coastguard Worker /// let offset = builder.create( 653*890232f2SAndroid Build Coastguard Worker /// struct: NativeStr(num: 1)) 654*890232f2SAndroid Build Coastguard Worker /// ``` 655*890232f2SAndroid Build Coastguard Worker /// 656*890232f2SAndroid Build Coastguard Worker /// - Parameters: 657*890232f2SAndroid Build Coastguard Worker /// - s: ``NativeStruct`` to be inserted into the ``ByteBuffer`` 658*890232f2SAndroid Build Coastguard Worker /// - Returns: ``Offset`` of written struct 659*890232f2SAndroid Build Coastguard Worker @inline(__always) 660*890232f2SAndroid Build Coastguard Worker @discardableResult 661*890232f2SAndroid Build Coastguard Worker mutating public func create<T: NativeStruct>( 662*890232f2SAndroid Build Coastguard Worker struct s: T) -> Offset 663*890232f2SAndroid Build Coastguard Worker { 664*890232f2SAndroid Build Coastguard Worker let size = MemoryLayout<T>.size 665*890232f2SAndroid Build Coastguard Worker preAlign(len: size, alignment: MemoryLayout<T>.alignment) 666*890232f2SAndroid Build Coastguard Worker _bb.push(struct: s, size: size) 667*890232f2SAndroid Build Coastguard Worker return Offset(offset: _bb.size) 668*890232f2SAndroid Build Coastguard Worker } 669*890232f2SAndroid Build Coastguard Worker 670*890232f2SAndroid Build Coastguard Worker // MARK: - Inserting Strings 671*890232f2SAndroid Build Coastguard Worker 672*890232f2SAndroid Build Coastguard Worker /// Insets a string into the buffer of type `UTF8` 673*890232f2SAndroid Build Coastguard Worker /// 674*890232f2SAndroid Build Coastguard Worker /// Adds a swift string into ``ByteBuffer`` by encoding it 675*890232f2SAndroid Build Coastguard Worker /// using `UTF8` 676*890232f2SAndroid Build Coastguard Worker /// 677*890232f2SAndroid Build Coastguard Worker /// ```swift 678*890232f2SAndroid Build Coastguard Worker /// let nameOffset = builder 679*890232f2SAndroid Build Coastguard Worker /// .create(string: "welcome") 680*890232f2SAndroid Build Coastguard Worker /// ``` 681*890232f2SAndroid Build Coastguard Worker /// 682*890232f2SAndroid Build Coastguard Worker /// - Parameter str: String to be serialized 683*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of inserted string 684*890232f2SAndroid Build Coastguard Worker @inline(__always) createnull685*890232f2SAndroid Build Coastguard Worker mutating public func create(string str: String?) -> Offset { 686*890232f2SAndroid Build Coastguard Worker guard let str = str else { return Offset() } 687*890232f2SAndroid Build Coastguard Worker let len = str.utf8.count 688*890232f2SAndroid Build Coastguard Worker notNested() 689*890232f2SAndroid Build Coastguard Worker preAlign(len: len &+ 1, type: UOffset.self) 690*890232f2SAndroid Build Coastguard Worker _bb.fill(padding: 1) 691*890232f2SAndroid Build Coastguard Worker _bb.push(string: str, len: len) 692*890232f2SAndroid Build Coastguard Worker push(element: UOffset(len)) 693*890232f2SAndroid Build Coastguard Worker return Offset(offset: _bb.size) 694*890232f2SAndroid Build Coastguard Worker } 695*890232f2SAndroid Build Coastguard Worker 696*890232f2SAndroid Build Coastguard Worker /// Insets a shared string into the buffer of type `UTF8` 697*890232f2SAndroid Build Coastguard Worker /// 698*890232f2SAndroid Build Coastguard Worker /// Adds a swift string into ``ByteBuffer`` by encoding it 699*890232f2SAndroid Build Coastguard Worker /// using `UTF8`. The function will check if the string, 700*890232f2SAndroid Build Coastguard Worker /// is already written to the ``ByteBuffer`` 701*890232f2SAndroid Build Coastguard Worker /// 702*890232f2SAndroid Build Coastguard Worker /// ```swift 703*890232f2SAndroid Build Coastguard Worker /// let nameOffset = builder 704*890232f2SAndroid Build Coastguard Worker /// .createShared(string: "welcome") 705*890232f2SAndroid Build Coastguard Worker /// 706*890232f2SAndroid Build Coastguard Worker /// 707*890232f2SAndroid Build Coastguard Worker /// let secondOffset = builder 708*890232f2SAndroid Build Coastguard Worker /// .createShared(string: "welcome") 709*890232f2SAndroid Build Coastguard Worker /// 710*890232f2SAndroid Build Coastguard Worker /// assert(nameOffset.o == secondOffset.o) 711*890232f2SAndroid Build Coastguard Worker /// ``` 712*890232f2SAndroid Build Coastguard Worker /// 713*890232f2SAndroid Build Coastguard Worker /// - Parameter str: String to be serialized 714*890232f2SAndroid Build Coastguard Worker /// - returns: ``Offset`` of inserted string 715*890232f2SAndroid Build Coastguard Worker @inline(__always) createSharednull716*890232f2SAndroid Build Coastguard Worker mutating public func createShared(string str: String?) -> Offset { 717*890232f2SAndroid Build Coastguard Worker guard let str = str else { return Offset() } 718*890232f2SAndroid Build Coastguard Worker if let offset = stringOffsetMap[str] { 719*890232f2SAndroid Build Coastguard Worker return offset 720*890232f2SAndroid Build Coastguard Worker } 721*890232f2SAndroid Build Coastguard Worker let offset = create(string: str) 722*890232f2SAndroid Build Coastguard Worker stringOffsetMap[str] = offset 723*890232f2SAndroid Build Coastguard Worker return offset 724*890232f2SAndroid Build Coastguard Worker } 725*890232f2SAndroid Build Coastguard Worker 726*890232f2SAndroid Build Coastguard Worker // MARK: - Inseting offsets 727*890232f2SAndroid Build Coastguard Worker 728*890232f2SAndroid Build Coastguard Worker /// Writes the ``Offset`` of an already written table 729*890232f2SAndroid Build Coastguard Worker /// 730*890232f2SAndroid Build Coastguard Worker /// Writes the ``Offset`` of a table if not empty into the 731*890232f2SAndroid Build Coastguard Worker /// ``ByteBuffer`` 732*890232f2SAndroid Build Coastguard Worker /// 733*890232f2SAndroid Build Coastguard Worker /// - Parameters: 734*890232f2SAndroid Build Coastguard Worker /// - offset: ``Offset`` of another object to be written 735*890232f2SAndroid Build Coastguard Worker /// - position: The predefined position of the object 736*890232f2SAndroid Build Coastguard Worker @inline(__always) addnull737*890232f2SAndroid Build Coastguard Worker mutating public func add(offset: Offset, at position: VOffset) { 738*890232f2SAndroid Build Coastguard Worker if offset.isEmpty { return } 739*890232f2SAndroid Build Coastguard Worker add(element: refer(to: offset.o), def: 0, at: position) 740*890232f2SAndroid Build Coastguard Worker } 741*890232f2SAndroid Build Coastguard Worker 742*890232f2SAndroid Build Coastguard Worker /// Pushes a value of type ``Offset`` into the ``ByteBuffer`` 743*890232f2SAndroid Build Coastguard Worker /// - Parameter o: ``Offset`` 744*890232f2SAndroid Build Coastguard Worker /// - returns: Current position of the ``Offset`` 745*890232f2SAndroid Build Coastguard Worker @inline(__always) 746*890232f2SAndroid Build Coastguard Worker @discardableResult pushnull747*890232f2SAndroid Build Coastguard Worker mutating public func push(element o: Offset) -> UOffset { 748*890232f2SAndroid Build Coastguard Worker push(element: refer(to: o.o)) 749*890232f2SAndroid Build Coastguard Worker } 750*890232f2SAndroid Build Coastguard Worker 751*890232f2SAndroid Build Coastguard Worker // MARK: - Inserting Scalars to Buffer 752*890232f2SAndroid Build Coastguard Worker 753*890232f2SAndroid Build Coastguard Worker /// Writes a ``Scalar`` value into ``ByteBuffer`` 754*890232f2SAndroid Build Coastguard Worker /// 755*890232f2SAndroid Build Coastguard Worker /// ``add(element:def:at:)`` takes in a default value, and current value 756*890232f2SAndroid Build Coastguard Worker /// and the position within the `VTable`. The default value would not 757*890232f2SAndroid Build Coastguard Worker /// be serialized if the value is the same as the current value or 758*890232f2SAndroid Build Coastguard Worker /// `serializeDefaults` is equal to false. 759*890232f2SAndroid Build Coastguard Worker /// 760*890232f2SAndroid Build Coastguard Worker /// If serializing defaults is important ``init(initialSize:serializeDefaults:)``, 761*890232f2SAndroid Build Coastguard Worker /// passing true for `serializeDefaults` would do the job. 762*890232f2SAndroid Build Coastguard Worker /// 763*890232f2SAndroid Build Coastguard Worker /// ```swift 764*890232f2SAndroid Build Coastguard Worker /// // Adds 10 to the buffer 765*890232f2SAndroid Build Coastguard Worker /// builder.add(element: Int(10), def: 1, position 12) 766*890232f2SAndroid Build Coastguard Worker /// ``` 767*890232f2SAndroid Build Coastguard Worker /// 768*890232f2SAndroid Build Coastguard Worker /// *NOTE: Never call this manually* 769*890232f2SAndroid Build Coastguard Worker /// 770*890232f2SAndroid Build Coastguard Worker /// - Parameters: 771*890232f2SAndroid Build Coastguard Worker /// - element: Element to insert 772*890232f2SAndroid Build Coastguard Worker /// - def: Default value for that element 773*890232f2SAndroid Build Coastguard Worker /// - position: The predefined position of the element 774*890232f2SAndroid Build Coastguard Worker @inline(__always) 775*890232f2SAndroid Build Coastguard Worker mutating public func add<T: Scalar>( 776*890232f2SAndroid Build Coastguard Worker element: T, 777*890232f2SAndroid Build Coastguard Worker def: T, 778*890232f2SAndroid Build Coastguard Worker at position: VOffset) 779*890232f2SAndroid Build Coastguard Worker { 780*890232f2SAndroid Build Coastguard Worker if element == def && !serializeDefaults { return } 781*890232f2SAndroid Build Coastguard Worker track(offset: push(element: element), at: position) 782*890232f2SAndroid Build Coastguard Worker } 783*890232f2SAndroid Build Coastguard Worker 784*890232f2SAndroid Build Coastguard Worker /// Writes a optional ``Scalar`` value into ``ByteBuffer`` 785*890232f2SAndroid Build Coastguard Worker /// 786*890232f2SAndroid Build Coastguard Worker /// Takes an optional value to be written into the ``ByteBuffer`` 787*890232f2SAndroid Build Coastguard Worker /// 788*890232f2SAndroid Build Coastguard Worker /// *NOTE: Never call this manually* 789*890232f2SAndroid Build Coastguard Worker /// 790*890232f2SAndroid Build Coastguard Worker /// - Parameters: 791*890232f2SAndroid Build Coastguard Worker /// - element: Optional element of type scalar 792*890232f2SAndroid Build Coastguard Worker /// - position: The predefined position of the element 793*890232f2SAndroid Build Coastguard Worker @inline(__always) add<T: Scalar>null794*890232f2SAndroid Build Coastguard Worker mutating public func add<T: Scalar>(element: T?, at position: VOffset) { 795*890232f2SAndroid Build Coastguard Worker guard let element = element else { return } 796*890232f2SAndroid Build Coastguard Worker track(offset: push(element: element), at: position) 797*890232f2SAndroid Build Coastguard Worker } 798*890232f2SAndroid Build Coastguard Worker 799*890232f2SAndroid Build Coastguard Worker /// Pushes a values of type ``Scalar`` into the ``ByteBuffer`` 800*890232f2SAndroid Build Coastguard Worker /// 801*890232f2SAndroid Build Coastguard Worker /// *NOTE: Never call this manually* 802*890232f2SAndroid Build Coastguard Worker /// 803*890232f2SAndroid Build Coastguard Worker /// - Parameter element: Element to insert 804*890232f2SAndroid Build Coastguard Worker /// - returns: Postion of the Element 805*890232f2SAndroid Build Coastguard Worker @inline(__always) 806*890232f2SAndroid Build Coastguard Worker @discardableResult push<T: Scalar>null807*890232f2SAndroid Build Coastguard Worker mutating public func push<T: Scalar>(element: T) -> UOffset { 808*890232f2SAndroid Build Coastguard Worker let size = MemoryLayout<T>.size 809*890232f2SAndroid Build Coastguard Worker preAlign( 810*890232f2SAndroid Build Coastguard Worker len: size, 811*890232f2SAndroid Build Coastguard Worker alignment: size) 812*890232f2SAndroid Build Coastguard Worker _bb.push(value: element, len: size) 813*890232f2SAndroid Build Coastguard Worker return _bb.size 814*890232f2SAndroid Build Coastguard Worker } 815*890232f2SAndroid Build Coastguard Worker 816*890232f2SAndroid Build Coastguard Worker } 817*890232f2SAndroid Build Coastguard Worker 818*890232f2SAndroid Build Coastguard Worker extension FlatBufferBuilder: CustomDebugStringConvertible { 819*890232f2SAndroid Build Coastguard Worker 820*890232f2SAndroid Build Coastguard Worker public var debugDescription: String { 821*890232f2SAndroid Build Coastguard Worker """ 822*890232f2SAndroid Build Coastguard Worker buffer debug: 823*890232f2SAndroid Build Coastguard Worker \(_bb) 824*890232f2SAndroid Build Coastguard Worker builder debug: 825*890232f2SAndroid Build Coastguard Worker { finished: \(finished), serializeDefaults: \(serializeDefaults), isNested: \(isNested) } 826*890232f2SAndroid Build Coastguard Worker """ 827*890232f2SAndroid Build Coastguard Worker } 828*890232f2SAndroid Build Coastguard Worker 829*890232f2SAndroid Build Coastguard Worker /// VTableStorage is a class to contain the VTable buffer that would be serialized into buffer 830*890232f2SAndroid Build Coastguard Worker @usableFromInline 831*890232f2SAndroid Build Coastguard Worker internal class VTableStorage { 832*890232f2SAndroid Build Coastguard Worker /// Memory check since deallocating each time we want to clear would be expensive 833*890232f2SAndroid Build Coastguard Worker /// and memory leaks would happen if we dont deallocate the first allocated memory. 834*890232f2SAndroid Build Coastguard Worker /// memory is promised to be available before adding `FieldLoc` 835*890232f2SAndroid Build Coastguard Worker private var memoryInUse = false 836*890232f2SAndroid Build Coastguard Worker /// Size of FieldLoc in memory 837*890232f2SAndroid Build Coastguard Worker let size = MemoryLayout<FieldLoc>.stride 838*890232f2SAndroid Build Coastguard Worker /// Memeory buffer 839*890232f2SAndroid Build Coastguard Worker var memory: UnsafeMutableRawBufferPointer! 840*890232f2SAndroid Build Coastguard Worker /// Capacity of the current buffer 841*890232f2SAndroid Build Coastguard Worker var capacity: Int = 0 842*890232f2SAndroid Build Coastguard Worker /// Maximuim offset written to the class 843*890232f2SAndroid Build Coastguard Worker var maxOffset: VOffset = 0 844*890232f2SAndroid Build Coastguard Worker /// number of fields written into the buffer 845*890232f2SAndroid Build Coastguard Worker var numOfFields: Int = 0 846*890232f2SAndroid Build Coastguard Worker /// Last written Index 847*890232f2SAndroid Build Coastguard Worker var writtenIndex: Int = 0 848*890232f2SAndroid Build Coastguard Worker 849*890232f2SAndroid Build Coastguard Worker /// Creates the memory to store the buffer in 850*890232f2SAndroid Build Coastguard Worker @usableFromInline 851*890232f2SAndroid Build Coastguard Worker @inline(__always) 852*890232f2SAndroid Build Coastguard Worker init() { 853*890232f2SAndroid Build Coastguard Worker memory = UnsafeMutableRawBufferPointer.allocate( 854*890232f2SAndroid Build Coastguard Worker byteCount: 0, 855*890232f2SAndroid Build Coastguard Worker alignment: 0) 856*890232f2SAndroid Build Coastguard Worker } 857*890232f2SAndroid Build Coastguard Worker 858*890232f2SAndroid Build Coastguard Worker @inline(__always) 859*890232f2SAndroid Build Coastguard Worker deinit { 860*890232f2SAndroid Build Coastguard Worker memory.deallocate() 861*890232f2SAndroid Build Coastguard Worker } 862*890232f2SAndroid Build Coastguard Worker 863*890232f2SAndroid Build Coastguard Worker /// Builds a buffer with byte count of fieldloc.size * count of field numbers 864*890232f2SAndroid Build Coastguard Worker /// - Parameter count: number of fields to be written 865*890232f2SAndroid Build Coastguard Worker @inline(__always) startnull866*890232f2SAndroid Build Coastguard Worker func start(count: Int) { 867*890232f2SAndroid Build Coastguard Worker assert(count >= 0, "number of fields should NOT be negative") 868*890232f2SAndroid Build Coastguard Worker let capacity = count &* size 869*890232f2SAndroid Build Coastguard Worker ensure(space: capacity) 870*890232f2SAndroid Build Coastguard Worker } 871*890232f2SAndroid Build Coastguard Worker 872*890232f2SAndroid Build Coastguard Worker /// Adds a FieldLoc into the buffer, which would track how many have been written, 873*890232f2SAndroid Build Coastguard Worker /// and max offset 874*890232f2SAndroid Build Coastguard Worker /// - Parameter loc: Location of encoded element 875*890232f2SAndroid Build Coastguard Worker @inline(__always) addnull876*890232f2SAndroid Build Coastguard Worker func add(loc: FieldLoc) { 877*890232f2SAndroid Build Coastguard Worker memory.baseAddress?.advanced(by: writtenIndex).storeBytes( 878*890232f2SAndroid Build Coastguard Worker of: loc, 879*890232f2SAndroid Build Coastguard Worker as: FieldLoc.self) 880*890232f2SAndroid Build Coastguard Worker writtenIndex = writtenIndex &+ size 881*890232f2SAndroid Build Coastguard Worker numOfFields = numOfFields &+ 1 882*890232f2SAndroid Build Coastguard Worker maxOffset = max(loc.position, maxOffset) 883*890232f2SAndroid Build Coastguard Worker } 884*890232f2SAndroid Build Coastguard Worker 885*890232f2SAndroid Build Coastguard Worker /// Clears the data stored related to the encoded buffer 886*890232f2SAndroid Build Coastguard Worker @inline(__always) clearnull887*890232f2SAndroid Build Coastguard Worker func clear() { 888*890232f2SAndroid Build Coastguard Worker maxOffset = 0 889*890232f2SAndroid Build Coastguard Worker numOfFields = 0 890*890232f2SAndroid Build Coastguard Worker writtenIndex = 0 891*890232f2SAndroid Build Coastguard Worker } 892*890232f2SAndroid Build Coastguard Worker 893*890232f2SAndroid Build Coastguard Worker /// Ensure that the buffer has enough space instead of recreating the buffer each time. 894*890232f2SAndroid Build Coastguard Worker /// - Parameter space: space required for the new vtable 895*890232f2SAndroid Build Coastguard Worker @inline(__always) ensurenull896*890232f2SAndroid Build Coastguard Worker func ensure(space: Int) { 897*890232f2SAndroid Build Coastguard Worker guard space &+ writtenIndex > capacity else { return } 898*890232f2SAndroid Build Coastguard Worker memory.deallocate() 899*890232f2SAndroid Build Coastguard Worker memory = UnsafeMutableRawBufferPointer.allocate( 900*890232f2SAndroid Build Coastguard Worker byteCount: space, 901*890232f2SAndroid Build Coastguard Worker alignment: size) 902*890232f2SAndroid Build Coastguard Worker capacity = space 903*890232f2SAndroid Build Coastguard Worker } 904*890232f2SAndroid Build Coastguard Worker 905*890232f2SAndroid Build Coastguard Worker /// Loads an object of type `FieldLoc` from buffer memory 906*890232f2SAndroid Build Coastguard Worker /// - Parameter index: index of element 907*890232f2SAndroid Build Coastguard Worker /// - Returns: a FieldLoc at index 908*890232f2SAndroid Build Coastguard Worker @inline(__always) loadnull909*890232f2SAndroid Build Coastguard Worker func load(at index: Int) -> FieldLoc { 910*890232f2SAndroid Build Coastguard Worker memory.load(fromByteOffset: index, as: FieldLoc.self) 911*890232f2SAndroid Build Coastguard Worker } 912*890232f2SAndroid Build Coastguard Worker 913*890232f2SAndroid Build Coastguard Worker } 914*890232f2SAndroid Build Coastguard Worker 915*890232f2SAndroid Build Coastguard Worker internal struct FieldLoc { 916*890232f2SAndroid Build Coastguard Worker var offset: UOffset 917*890232f2SAndroid Build Coastguard Worker var position: VOffset 918*890232f2SAndroid Build Coastguard Worker } 919*890232f2SAndroid Build Coastguard Worker 920*890232f2SAndroid Build Coastguard Worker } 921