blob: 5c78224893171a9e3ddc3fda302d9fb0e519b32b [file] [log] [blame]
Austin Schuh58b9b472020-11-25 19:12:44 -08001/*
James Kuszmaul8e62b022022-03-22 09:33:25 -07002 * Copyright 2021 Google Inc. All rights reserved.
Austin Schuh58b9b472020-11-25 19:12:44 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Austin Schuh2dd86a92022-09-14 21:19:23 -070017#if !os(WASI)
Austin Schuh272c6132020-11-14 16:37:52 -080018import Foundation
Austin Schuh2dd86a92022-09-14 21:19:23 -070019#else
20import SwiftOverlayShims
21#endif
Austin Schuh272c6132020-11-14 16:37:52 -080022
James Kuszmaul8e62b022022-03-22 09:33:25 -070023/// `Table` is a Flatbuffers object that can read,
24/// mutate scalar fields within a valid flatbuffers buffer
25@frozen
Austin Schuh272c6132020-11-14 16:37:52 -080026public struct Table {
James Kuszmaul8e62b022022-03-22 09:33:25 -070027
28 /// Hosting Bytebuffer
Austin Schuh58b9b472020-11-25 19:12:44 -080029 public private(set) var bb: ByteBuffer
James Kuszmaul8e62b022022-03-22 09:33:25 -070030 /// Current position of the table within the buffer
Austin Schuh58b9b472020-11-25 19:12:44 -080031 public private(set) var postion: Int32
Austin Schuh272c6132020-11-14 16:37:52 -080032
James Kuszmaul8e62b022022-03-22 09:33:25 -070033 /// Initializer for the table interface to allow generated code to read
34 /// data from memory
35 /// - Parameters:
36 /// - bb: ByteBuffer that stores data
37 /// - position: Current table position
38 /// - Note: This will `CRASH` if read on a big endian machine
Austin Schuh58b9b472020-11-25 19:12:44 -080039 public init(bb: ByteBuffer, position: Int32 = 0) {
40 guard isLitteEndian else {
James Kuszmaul8e62b022022-03-22 09:33:25 -070041 fatalError(
42 "Reading/Writing a buffer in big endian machine is not supported on swift")
Austin Schuh272c6132020-11-14 16:37:52 -080043 }
Austin Schuh58b9b472020-11-25 19:12:44 -080044 self.bb = bb
45 postion = position
46 }
Austin Schuh272c6132020-11-14 16:37:52 -080047
James Kuszmaul8e62b022022-03-22 09:33:25 -070048 /// Gets the offset of the current field within the buffer by reading
49 /// the vtable
50 /// - Parameter o: current offset
51 /// - Returns: offset of field within buffer
Austin Schuh58b9b472020-11-25 19:12:44 -080052 public func offset(_ o: Int32) -> Int32 {
53 let vtable = postion - bb.read(def: Int32.self, position: Int(postion))
James Kuszmaul8e62b022022-03-22 09:33:25 -070054 return o < bb
55 .read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read(
56 def: Int16.self,
57 position: Int(vtable + o))) : 0
Austin Schuh58b9b472020-11-25 19:12:44 -080058 }
59
James Kuszmaul8e62b022022-03-22 09:33:25 -070060 /// Gets the indirect offset of the current stored object
61 /// (applicable only for object arrays)
62 /// - Parameter o: current offset
63 /// - Returns: offset of field within buffer
64 public func indirect(_ o: Int32) -> Int32 {
65 o + bb.read(def: Int32.self, position: Int(o))
66 }
Austin Schuh58b9b472020-11-25 19:12:44 -080067
68 /// String reads from the buffer with respect to position of the current table.
69 /// - Parameter offset: Offset of the string
70 public func string(at offset: Int32) -> String? {
71 directString(at: offset + postion)
72 }
73
74 /// Direct string reads from the buffer disregarding the position of the table.
James Kuszmaul8e62b022022-03-22 09:33:25 -070075 /// It would be preferable to use string unless the current position of the table
76 /// is not needed
Austin Schuh58b9b472020-11-25 19:12:44 -080077 /// - Parameter offset: Offset of the string
78 public func directString(at offset: Int32) -> String? {
79 var offset = offset
80 offset += bb.read(def: Int32.self, position: Int(offset))
81 let count = bb.read(def: Int32.self, position: Int(offset))
James Kuszmaul8e62b022022-03-22 09:33:25 -070082 let position = Int(offset) + MemoryLayout<Int32>.size
83 return bb.readString(at: position, count: Int(count))
Austin Schuh58b9b472020-11-25 19:12:44 -080084 }
85
86 /// Reads from the buffer with respect to the position in the table.
87 /// - Parameters:
James Kuszmaul8e62b022022-03-22 09:33:25 -070088 /// - type: Type of Element that needs to be read from the buffer
Austin Schuh58b9b472020-11-25 19:12:44 -080089 /// - o: Offset of the Element
James Kuszmaul8e62b022022-03-22 09:33:25 -070090 public func readBuffer<T>(of type: T.Type, at o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -080091 directRead(of: T.self, offset: o + postion)
92 }
93
94 /// Reads from the buffer disregarding the position of the table.
95 /// It would be used when reading from an
96 /// ```
97 /// let offset = __t.offset(10)
98 /// //Only used when the we already know what is the
99 /// // position in the table since __t.vector(at:)
100 /// // returns the index with respect to the position
101 /// __t.directRead(of: Byte.self,
102 /// offset: __t.vector(at: offset) + index * 1)
103 /// ```
104 /// - Parameters:
James Kuszmaul8e62b022022-03-22 09:33:25 -0700105 /// - type: Type of Element that needs to be read from the buffer
Austin Schuh58b9b472020-11-25 19:12:44 -0800106 /// - o: Offset of the Element
James Kuszmaul8e62b022022-03-22 09:33:25 -0700107 public func directRead<T>(of type: T.Type, offset o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -0800108 let r = bb.read(def: T.self, position: Int(o))
109 return r
110 }
111
James Kuszmaul8e62b022022-03-22 09:33:25 -0700112 /// Returns that current `Union` object at a specific offset
113 /// by adding offset to the current position of table
114 /// - Parameter o: offset
115 /// - Returns: A flatbuffers object
116 public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -0800117 let o = o + postion
118 return directUnion(o)
119 }
120
James Kuszmaul8e62b022022-03-22 09:33:25 -0700121 /// Returns a direct `Union` object at a specific offset
122 /// - Parameter o: offset
123 /// - Returns: A flatbuffers object
124 public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -0800125 T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o)))
126 }
127
James Kuszmaul8e62b022022-03-22 09:33:25 -0700128 /// Returns a vector of type T at a specific offset
129 /// This should only be used by `Scalars`
130 /// - Parameter off: Readable offset
131 /// - Returns: Returns a vector of type [T]
Austin Schuh58b9b472020-11-25 19:12:44 -0800132 public func getVector<T>(at off: Int32) -> [T]? {
133 let o = offset(off)
134 guard o != 0 else { return nil }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700135 return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o)))
Austin Schuh58b9b472020-11-25 19:12:44 -0800136 }
137
138 /// Vector count gets the count of Elements within the array
139 /// - Parameter o: start offset of the vector
140 /// - returns: Count of elements
141 public func vector(count o: Int32) -> Int32 {
142 var o = o
143 o += postion
144 o += bb.read(def: Int32.self, position: Int(o))
145 return bb.read(def: Int32.self, position: Int(o))
146 }
147
148 /// Vector start index in the buffer
149 /// - Parameter o:start offset of the vector
150 /// - returns: the start index of the vector
151 public func vector(at o: Int32) -> Int32 {
152 var o = o
153 o += postion
154 return o + bb.read(def: Int32.self, position: Int(o)) + 4
155 }
Austin Schuh272c6132020-11-14 16:37:52 -0800156
James Kuszmaul8e62b022022-03-22 09:33:25 -0700157 /// Reading an indirect offset of a table.
158 /// - Parameters:
159 /// - o: position within the buffer
160 /// - fbb: ByteBuffer
161 /// - Returns: table offset
162 static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 {
163 o + fbb.read(def: Int32.self, position: Int(o))
164 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800165
James Kuszmaul8e62b022022-03-22 09:33:25 -0700166 /// Gets a vtable value according to an table Offset and a field offset
167 /// - Parameters:
168 /// - o: offset relative to entire buffer
169 /// - vOffset: Field offset within a vtable
170 /// - fbb: ByteBuffer
171 /// - Returns: an position of a field
172 static public func offset(
173 _ o: Int32,
174 vOffset: Int32,
175 fbb: ByteBuffer) -> Int32
176 {
Austin Schuh58b9b472020-11-25 19:12:44 -0800177 let vTable = Int32(fbb.capacity) - o
178 return vTable + Int32(fbb.read(
179 def: Int16.self,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700180 position: Int(vTable + vOffset - fbb.read(
181 def: Int32.self,
182 position: Int(vTable)))))
Austin Schuh58b9b472020-11-25 19:12:44 -0800183 }
184
James Kuszmaul8e62b022022-03-22 09:33:25 -0700185 /// Compares two objects at offset A and offset B within a ByteBuffer
186 /// - Parameters:
187 /// - off1: first offset to compare
188 /// - off2: second offset to compare
189 /// - fbb: Bytebuffer
190 /// - Returns: returns the difference between
191 static public func compare(
192 _ off1: Int32,
193 _ off2: Int32,
194 fbb: ByteBuffer) -> Int32
195 {
Austin Schuh58b9b472020-11-25 19:12:44 -0800196 let memorySize = Int32(MemoryLayout<Int32>.size)
197 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
198 let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2))
199 let len1 = fbb.read(def: Int32.self, position: Int(_off1))
200 let len2 = fbb.read(def: Int32.self, position: Int(_off2))
201 let startPos1 = _off1 + memorySize
202 let startPos2 = _off2 + memorySize
203 let minValue = min(len1, len2)
204 for i in 0...minValue {
205 let b1 = fbb.read(def: Int8.self, position: Int(i + startPos1))
206 let b2 = fbb.read(def: Int8.self, position: Int(i + startPos2))
207 if b1 != b2 {
208 return Int32(b2 - b1)
209 }
Austin Schuh272c6132020-11-14 16:37:52 -0800210 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800211 return len1 - len2
212 }
213
James Kuszmaul8e62b022022-03-22 09:33:25 -0700214 /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer
215 /// - Parameters:
216 /// - off1: Offset to compare to
217 /// - key: bytes array to compare to
218 /// - fbb: Bytebuffer
219 /// - Returns: returns the difference between
220 static public func compare(
221 _ off1: Int32,
222 _ key: [Byte],
223 fbb: ByteBuffer) -> Int32
224 {
Austin Schuh58b9b472020-11-25 19:12:44 -0800225 let memorySize = Int32(MemoryLayout<Int32>.size)
226 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
227 let len1 = fbb.read(def: Int32.self, position: Int(_off1))
228 let len2 = Int32(key.count)
229 let startPos1 = _off1 + memorySize
230 let minValue = min(len1, len2)
231 for i in 0..<minValue {
232 let b = fbb.read(def: Int8.self, position: Int(i + startPos1))
233 let byte = key[Int(i)]
234 if b != byte {
235 return Int32(b - Int8(byte))
236 }
Austin Schuh272c6132020-11-14 16:37:52 -0800237 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800238 return len1 - len2
239 }
Austin Schuh272c6132020-11-14 16:37:52 -0800240}