diff options
author | mustiikhalil <mustii@mmk.one> | 2021-05-14 20:59:28 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-14 20:59:28 +0300 |
commit | a5175c513a192ffd50fbfb1574817bb99b3e20cc (patch) | |
tree | ae8f4c3d6ac9637e809a588c85322fda6ce784ef | |
parent | 04b10f5a3a78aed27030a4e26dcf36921979114f (diff) | |
download | flatbuffers-a5175c513a192ffd50fbfb1574817bb99b3e20cc.tar.gz flatbuffers-a5175c513a192ffd50fbfb1574817bb99b3e20cc.tar.bz2 flatbuffers-a5175c513a192ffd50fbfb1574817bb99b3e20cc.zip |
Implements verifier and code gen for swift (#6373)
Updates test cases on linux
Adhere to new protocol naming
Adds fuzzing
Adds documentation
Adds support for string unions
Updated fuzzer generated code
38 files changed, 2291 insertions, 168 deletions
@@ -141,3 +141,4 @@ yarn-error.log **/vendor **/go.sum flatbuffers.pc +**/FlatBuffers.Test.Swift.xcodeproj diff --git a/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift b/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift index 8914d983..bc1eca3c 100644 --- a/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift +++ b/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift @@ -4,7 +4,7 @@ import FlatBuffers -public struct models_HelloReply: FlatBufferObject { +public struct models_HelloReply: FlatBufferObject, Verifiable { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -34,9 +34,15 @@ public struct models_HelloReply: FlatBufferObject { models_HelloReply.add(message: message, &fbb) return models_HelloReply.endHelloReply(&fbb, start: __start) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.message.p, fieldName: "message", required: false, type: ForwardOffset<String>.self) + _v.finish() + } } -public struct models_HelloRequest: FlatBufferObject { +public struct models_HelloRequest: FlatBufferObject, Verifiable { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -66,5 +72,11 @@ public struct models_HelloRequest: FlatBufferObject { models_HelloRequest.add(name: name, &fbb) return models_HelloRequest.endHelloRequest(&fbb, start: __start) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: false, type: ForwardOffset<String>.self) + _v.finish() + } } diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp index 3fffd394..762cd291 100644 --- a/src/idl_gen_swift.cpp +++ b/src/idl_gen_swift.cpp @@ -187,7 +187,8 @@ class SwiftGenerator : public BaseGenerator { code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public"); GenComment(struct_def.doc_comment); code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def)); - code_ += "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct\\"; + code_ += + "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct, Verifiable\\"; if (parser_.opts.generate_object_based_api) code_ += ", NativeObject\\"; code_ += " {"; code_ += ""; @@ -250,6 +251,15 @@ class SwiftGenerator : public BaseGenerator { GenReaderMainBody() + "{{VALUETYPE}}(rawValue: _{{VALUENAME}})! }"; } } + code_ += ""; + code_ += + "public static func verify<T>(_ verifier: inout Verifier, at position: " + "Int, of type: T.Type) throws where T: Verifiable {"; + Indent(); + code_ += + "try verifier.inBuffer(position: position, of: {{STRUCTNAME}}.self)"; + Outdent(); + code_ += "}"; Outdent(); code_ += "}\n"; } @@ -375,6 +385,8 @@ class SwiftGenerator : public BaseGenerator { GenTableWriter(struct_def); if (parser_.opts.generate_object_based_api) GenerateObjectAPITableExtension(struct_def); + code_ += ""; + GenerateVerifier(struct_def); Outdent(); code_ += "}\n"; } @@ -410,6 +422,7 @@ class SwiftGenerator : public BaseGenerator { code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : ""); code_ += "{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: FlatBufferObject\\"; + if (!struct_def.fixed) code_ += ", Verifiable\\"; if (!struct_def.fixed && parser_.opts.generate_object_based_api) code_ += ", ObjectAPIPacker\\"; code_ += " {\n"; @@ -651,8 +664,10 @@ class SwiftGenerator : public BaseGenerator { code_.SetValue("VALUETYPE", type); code_.SetValue("OFFSET", name); code_.SetValue("CONSTANT", field.value.constant); - std::string def_Val = field.IsDefault() ? "{{CONSTANT}}" : "nil"; - std::string optional = field.IsOptional() ? "?" : ""; + bool opt_scalar = + field.IsOptional() && IsScalar(field.value.type.base_type); + std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}"; + std::string optional = opt_scalar ? "?" : ""; auto const_string = "return o == 0 ? " + def_Val + " : "; GenComment(field.doc_comment); if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) && @@ -831,6 +846,112 @@ class SwiftGenerator : public BaseGenerator { } } + void GenerateVerifier(const StructDef &struct_def) { + code_ += + "public static func verify<T>(_ verifier: inout Verifier, at position: " + "Int, of type: T.Type) throws where T: Verifiable {"; + Indent(); + code_ += "var _v = try verifier.visitTable(at: position)"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto offset = NumToString(field.value.offset); + auto name = Name(field); + + code_.SetValue("VALUENAME", name); + code_.SetValue("VALUETYPE", GenerateVerifierType(field)); + code_.SetValue("OFFSET", name); + code_.SetValue("ISREQUIRED", field.IsRequired() ? "true" : "false"); + + if (IsUnion(field.value.type)) { + GenerateUnionTypeVerifier(field); + continue; + } + + code_ += + "try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}.p, fieldName: " + "\"{{VALUENAME}}\", required: {{ISREQUIRED}}, type: " + "{{VALUETYPE}}.self)"; + } + code_ += "_v.finish()"; + Outdent(); + code_ += "}"; + } + + void GenerateUnionTypeVerifier(const FieldDef &field) { + auto is_vector = IsVector(field.value.type) || IsArray(field.value.type); + if (field.value.type.base_type == BASE_TYPE_UTYPE || + (is_vector && + field.value.type.VectorType().base_type == BASE_TYPE_UTYPE)) + return; + EnumDef &union_def = *field.value.type.enum_def; + code_.SetValue("VALUETYPE", NameWrappedInNameSpace(union_def)); + code_.SetValue("FUNCTION_NAME", is_vector ? "visitUnionVector" : "visit"); + code_ += + "try _v.{{FUNCTION_NAME}}(unionKey: {{TABLEOFFSET}}.{{OFFSET}}Type.p, " + "unionField: {{TABLEOFFSET}}.{{OFFSET}}.p, unionKeyName: " + "\"{{VALUENAME}}Type\", fieldName: \"{{VALUENAME}}\", required: " + "{{ISREQUIRED}}, completion: { (verifier, key: {{VALUETYPE}}, pos) in"; + Indent(); + code_ += "switch key {"; + for (auto it = union_def.Vals().begin(); it != union_def.Vals().end(); + ++it) { + const auto &ev = **it; + + auto name = Name(ev); + auto type = GenType(ev.union_type); + code_.SetValue("KEY", name); + code_.SetValue("VALUETYPE", type); + code_ += "case .{{KEY}}:"; + Indent(); + if (ev.union_type.base_type == BASE_TYPE_NONE) { + code_ += "break // NOTE - SWIFT doesnt support none"; + } else if (ev.union_type.base_type == BASE_TYPE_STRING) { + code_ += + "try ForwardOffset<String>.verify(&verifier, at: pos, of: " + "String.self)"; + } else { + code_.SetValue("MAINTYPE", ev.union_type.struct_def->fixed + ? type + : "ForwardOffset<" + type + ">"); + code_ += + "try {{MAINTYPE}}.verify(&verifier, at: pos, of: " + "{{VALUETYPE}}.self)"; + } + Outdent(); + } + code_ += "}"; + Outdent(); + code_ += "})"; + } + + std::string GenerateVerifierType(const FieldDef &field) { + auto type = field.value.type; + auto is_vector = IsVector(type) || IsArray(type); + + if (is_vector) { + auto vector_type = field.value.type.VectorType(); + return "ForwardOffset<Vector<" + + GenerateNestedVerifierTypes(vector_type) + ", " + + GenType(vector_type) + ">>"; + } + + return GenerateNestedVerifierTypes(field.value.type); + } + + std::string GenerateNestedVerifierTypes(const Type &type) { + auto string_type = GenType(type); + + if (IsScalar(type.base_type)) { return string_type; } + + if (IsString(type)) { return "ForwardOffset<" + string_type + ">"; } + + if (type.struct_def && type.struct_def->fixed) { return string_type; } + + return "ForwardOffset<" + string_type + ">"; + } + void GenByKeyFunctions(const FieldDef &key_field) { code_.SetValue("TYPE", GenType(key_field.value.type)); code_ += @@ -844,13 +965,24 @@ class SwiftGenerator : public BaseGenerator { void GenEnum(const EnumDef &enum_def) { if (enum_def.generated) return; auto is_private_access = enum_def.attributes.Lookup("private"); + code_.SetValue("ENUM_TYPE", + enum_def.is_union ? "UnionEnum" : "Enum, Verifiable"); code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public"); code_.SetValue("ENUM_NAME", NameWrappedInNameSpace(enum_def)); code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false)); GenComment(enum_def.doc_comment); - code_ += "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, Enum {"; + code_ += + "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, {{ENUM_TYPE}} {"; Indent(); code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}"; + if (enum_def.is_union) { + code_ += ""; + code_ += "{{ACCESS_TYPE}} init?(value: T) {"; + Indent(); + code_ += "self.init(rawValue: value)"; + Outdent(); + code_ += "}\n"; + } code_ += "{{ACCESS_TYPE}} static var byteSize: Int { return " "MemoryLayout<{{BASE_TYPE}}>.size " @@ -865,7 +997,7 @@ class SwiftGenerator : public BaseGenerator { GenComment(ev.doc_comment); code_ += "case {{KEY}} = {{VALUE}}"; } - code_ += "\n"; + code_ += ""; AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max"); AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min"); Outdent(); diff --git a/swift.swiftformat b/swift.swiftformat index 8ef724df..3f4c45d1 100644 --- a/swift.swiftformat +++ b/swift.swiftformat @@ -2,6 +2,7 @@ # format --indent 2 +--maxwidth 80 # options --self remove # redundantSelf diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index b301e02e..c658d467 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -16,6 +16,9 @@ import Foundation +/// `ByteBuffer` is the interface that stores the data for a `Flatbuffers` object +/// it allows users to write and read data directly from memory thus the use of its +/// functions should be used @frozen public struct ByteBuffer { @@ -32,7 +35,9 @@ public struct ByteBuffer { @usableFromInline init(count: Int, alignment: Int) { - memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment) + memory = UnsafeMutableRawPointer.allocate( + byteCount: count, + alignment: alignment) capacity = count unowned = false } @@ -69,7 +74,7 @@ public struct ByteBuffer { /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer /// - Parameter size: Size of the current object @usableFromInline - internal func reallocate(_ size: Int, writerSize: Int, alignment: Int) { + func reallocate(_ size: Int, writerSize: Int, alignment: Int) { let currentWritingIndex = capacity &- writerSize while capacity <= writerSize &+ size { capacity = capacity << 1 @@ -78,7 +83,9 @@ public struct ByteBuffer { /// solution take from Apple-NIO capacity = capacity.convertToPowerofTwo - let newData = UnsafeMutableRawPointer.allocate(byteCount: capacity, alignment: alignment) + let newData = UnsafeMutableRawPointer.allocate( + byteCount: capacity, + alignment: alignment) memset(newData, 0, capacity &- writerSize) memcpy( newData.advanced(by: capacity &- writerSize), @@ -94,9 +101,9 @@ public struct ByteBuffer { /// The size of the elements written to the buffer + their paddings private var _writerSize: Int = 0 /// Aliginment of the current memory being written to the buffer - internal var alignment = 1 + var alignment = 1 /// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer - internal var writerIndex: Int { _storage.capacity &- _writerSize } + var writerIndex: Int { _storage.capacity &- _writerSize } /// Reader is the position of the current Writer Index (capacity - size) public var reader: Int { writerIndex } @@ -166,7 +173,7 @@ public struct ByteBuffer { /// - Parameters: /// - memory: Current memory of the buffer /// - count: count of bytes - internal init(memory: UnsafeMutableRawPointer, count: Int) { + init(memory: UnsafeMutableRawPointer, count: Int) { _storage = Storage(count: count, alignment: alignment) _storage.copy(from: memory, count: count) _writerSize = _storage.capacity @@ -177,7 +184,11 @@ public struct ByteBuffer { /// - memory: Current memory of the buffer /// - count: count of bytes /// - removeBytes: Removes a number of bytes from the current size - internal init(memory: UnsafeMutableRawPointer, count: Int, removing removeBytes: Int) { + init( + memory: UnsafeMutableRawPointer, + count: Int, + removing removeBytes: Int) + { _storage = Storage(count: count, alignment: alignment) _storage.copy(from: memory, count: count) _writerSize = removeBytes @@ -247,7 +258,7 @@ public struct ByteBuffer { /// - bytes: Pointer to the view /// - len: Size of string @inline(__always) - mutating internal func push( + mutating func push( bytes: UnsafeBufferPointer<String.UTF8View.Element>, len: Int) -> Bool { @@ -292,20 +303,18 @@ public struct ByteBuffer { /// pops the written VTable if it's already written into the buffer /// - Parameter size: size of the `VTable` @inline(__always) - mutating internal func pop(_ size: Int) { + mutating func pop(_ size: Int) { assert((_writerSize &- size) > 0, "New size should NOT be a negative number") memset(_storage.memory.advanced(by: writerIndex), 0, _writerSize &- size) _writerSize = size } /// Clears the current size of the buffer - @inline(__always) mutating public func clearSize() { _writerSize = 0 } /// Clears the current instance of the buffer, replacing it with new memory - @inline(__always) mutating public func clear() { _writerSize = 0 alignment = 1 @@ -317,10 +326,7 @@ public struct ByteBuffer { /// - def: Type of the object /// - position: the index of the object in the buffer public func read<T>(def: T.Type, position: Int) -> T { - assert( - position + MemoryLayout<T>.size <= _storage.capacity, - "Reading out of bounds is illegal") - return _storage.memory.advanced(by: position).load(as: T.self) + _storage.memory.advanced(by: position).load(as: T.self) } /// Reads a slice from the memory assuming a type of T @@ -329,14 +335,14 @@ public struct ByteBuffer { /// - count: count of bytes in memory @inline(__always) public func readSlice<T>( - index: Int32, - count: Int32) -> [T] + index: Int, + count: Int) -> [T] { - let _index = Int(index) - let _count = Int(count) - assert(_index + _count <= _storage.capacity, "Reading out of bounds is illegal") - let start = _storage.memory.advanced(by: _index).assumingMemoryBound(to: T.self) - let array = UnsafeBufferPointer(start: start, count: _count) + assert( + index + count <= _storage.capacity, + "Reading out of bounds is illegal") + let start = _storage.memory.advanced(by: index).assumingMemoryBound(to: T.self) + let array = UnsafeBufferPointer(start: start, count: count) return Array(array) } @@ -345,17 +351,16 @@ public struct ByteBuffer { /// - index: index of the string in the buffer /// - count: length of the string /// - type: Encoding of the string - @inline(__always) public func readString( - at index: Int32, - count: Int32, + at index: Int, + count: Int, type: String.Encoding = .utf8) -> String? { - let _index = Int(index) - let _count = Int(count) - assert(_index + _count <= _storage.capacity, "Reading out of bounds is illegal") - let start = _storage.memory.advanced(by: _index).assumingMemoryBound(to: UInt8.self) - let bufprt = UnsafeBufferPointer(start: start, count: _count) + assert( + index + count <= _storage.capacity, + "Reading out of bounds is illegal") + let start = _storage.memory.advanced(by: index).assumingMemoryBound(to: UInt8.self) + let bufprt = UnsafeBufferPointer(start: start, count: count) return String(bytes: Array(bufprt), encoding: type) } @@ -363,12 +368,22 @@ public struct ByteBuffer { /// - Parameter removeBytes: the amount of bytes to remove from the current Size public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer { assert(removeBytes > 0, "Can NOT remove negative bytes") - assert(removeBytes < _storage.capacity, "Can NOT remove more bytes than the ones allocated") + assert( + removeBytes < _storage.capacity, + "Can NOT remove more bytes than the ones allocated") return ByteBuffer( memory: _storage.memory, count: _storage.capacity, removing: _writerSize &- removeBytes) } + + /// SkipPrefix Skips the first 4 bytes in case one of the following + /// functions are called `getPrefixedSizeCheckedRoot` & `getPrefixedSizeRoot` + /// which allows us to skip the first 4 bytes instead of recreating the buffer + @usableFromInline + mutating func skipPrefix() { + _writerSize = _writerSize &- MemoryLayout<Int32>.size + } } extension ByteBuffer: CustomDebugStringConvertible { diff --git a/swift/Sources/FlatBuffers/Constants.swift b/swift/Sources/FlatBuffers/Constants.swift index 470b7252..50a58178 100644 --- a/swift/Sources/FlatBuffers/Constants.swift +++ b/swift/Sources/FlatBuffers/Constants.swift @@ -32,14 +32,16 @@ public typealias VOffset = UInt16 /// Maximum size for a buffer public let FlatBufferMaxSize = UInt32.max << ((MemoryLayout<SOffset>.size * 8 - 1) - 1) -/// Protocol that confirms all the numbers +/// Protocol that All Scalars should conform to /// -/// Scalar is used to confirm all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer. +/// Scalar is used to conform all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer. public protocol Scalar: Equatable { associatedtype NumericValue var convertedEndian: NumericValue { get } } +extension Scalar where Self: Verifiable {} + extension Scalar where Self: FixedWidthInteger { /// Converts the value from BigEndian to LittleEndian /// @@ -49,7 +51,7 @@ extension Scalar where Self: FixedWidthInteger { } } -extension Double: Scalar { +extension Double: Scalar, Verifiable { public typealias NumericValue = UInt64 public var convertedEndian: UInt64 { @@ -57,7 +59,7 @@ extension Double: Scalar { } } -extension Float32: Scalar { +extension Float32: Scalar, Verifiable { public typealias NumericValue = UInt32 public var convertedEndian: UInt32 { @@ -65,7 +67,7 @@ extension Float32: Scalar { } } -extension Bool: Scalar { +extension Bool: Scalar, Verifiable { public var convertedEndian: UInt8 { self == true ? 1 : 0 } @@ -73,39 +75,39 @@ extension Bool: Scalar { public typealias NumericValue = UInt8 } -extension Int: Scalar { +extension Int: Scalar, Verifiable { public typealias NumericValue = Int } -extension Int8: Scalar { +extension Int8: Scalar, Verifiable { public typealias NumericValue = Int8 } -extension Int16: Scalar { +extension Int16: Scalar, Verifiable { public typealias NumericValue = Int16 } -extension Int32: Scalar { +extension Int32: Scalar, Verifiable { public typealias NumericValue = Int32 } -extension Int64: Scalar { +extension Int64: Scalar, Verifiable { public typealias NumericValue = Int64 } -extension UInt8: Scalar { +extension UInt8: Scalar, Verifiable { public typealias NumericValue = UInt8 } -extension UInt16: Scalar { +extension UInt16: Scalar, Verifiable { public typealias NumericValue = UInt16 } -extension UInt32: Scalar { +extension UInt32: Scalar, Verifiable { public typealias NumericValue = UInt32 } -extension UInt64: Scalar { +extension UInt64: Scalar, Verifiable { public typealias NumericValue = UInt64 } diff --git a/swift/Sources/FlatBuffers/Enum.swift b/swift/Sources/FlatBuffers/Enum.swift new file mode 100644 index 00000000..f8cbebb1 --- /dev/null +++ b/swift/Sources/FlatBuffers/Enum.swift @@ -0,0 +1,54 @@ +/* + * 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 + +/// Enum is a protocol that all flatbuffers enums should conform to +/// Since it allows us to get the actual `ByteSize` and `Value` +public protocol Enum { + /// associatedtype that the type of the enum should conform to + associatedtype T: Scalar & Verifiable + /// Size of the current associatedtype in the enum + static var byteSize: Int { get } + /// The current value the enum hosts + var value: T { get } +} + +extension Enum where Self: Verifiable { + + /// Verifies that the current value is which the bounds of the buffer, and if + /// the current `Value` is aligned properly + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - position: Current position within the buffer + /// - type: The type of the object to be verified + /// - Throws: Errors coming from `inBuffer` function + public static func verify<T>( + _ verifier: inout Verifier, + at position: Int, + of type: T.Type) throws where T: Verifiable + { + try verifier.inBuffer(position: position, of: type.self) + } + +} + +/// UnionEnum is a Protocol that allows us to create Union type of enums +/// and their value initializers. Since an `init` was required by +/// the verifier +public protocol UnionEnum: Enum { + init?(value: T) throws +} diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 9a166bac..71b71399 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -16,6 +16,9 @@ import Foundation +/// `FlatBufferBuilder` builds a `FlatBuffer` through manipulating its internal state. +/// This is done by creating a `ByteBuffer` that hosts the incoming data and +/// has a hardcoded growth limit of `2GiB` which is set by the Flatbuffers standards @frozen public struct FlatBufferBuilder { @@ -74,7 +77,9 @@ public struct FlatBufferBuilder { /// Returns A sized Buffer from the readable bytes public var sizedBuffer: ByteBuffer { assert(finished, "Data shouldn't be called before finish()") - return ByteBuffer(memory: _bb.memory.advanced(by: _bb.reader), count: Int(_bb.size)) + return ByteBuffer( + memory: _bb.memory.advanced(by: _bb.reader), + count: Int(_bb.size)) } // MARK: - Init @@ -112,7 +117,9 @@ public struct FlatBufferBuilder { for field in fields { let start = _bb.capacity &- Int(table.o) let startTable = start &- Int(_bb.read(def: Int32.self, position: start)) - let isOkay = _bb.read(def: VOffset.self, position: startTable &+ Int(field)) != 0 + let isOkay = _bb.read( + def: VOffset.self, + position: startTable &+ Int(field)) != 0 assert(isOkay, "Flatbuffers requires the following field") } } @@ -122,9 +129,15 @@ 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(offset: Offset, 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) + preAlign( + len: size &+ (prefix ? size : 0) &+ FileIdLength, + alignment: _minAlignment) assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4") _bb.push(string: fileId, len: 4) finish(offset: offset, addPrefix: prefix) @@ -134,7 +147,10 @@ public struct FlatBufferBuilder { /// - Parameters: /// - offset: Offset of the table /// - prefix: if false it wont add the size of the buffer - mutating public func finish(offset: Offset, 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) @@ -184,7 +200,10 @@ public struct FlatBufferBuilder { itr = itr &+ _vtableStorage.size guard loaded.offset != 0 else { continue } let _index = (_bb.writerIndex &+ Int(loaded.position)) - _bb.write(value: VOffset(vTableOffset &- loaded.offset), index: _index, direct: true) + _bb.write( + value: VOffset(vTableOffset &- loaded.offset), + index: _index, + direct: true) } _vtableStorage.clear() @@ -375,7 +394,9 @@ public struct FlatBufferBuilder { /// - Parameter structs: A vector of structs /// - Returns: offset of the vector mutating public func createVector<T: NativeStruct>(ofStructs structs: [T]) -> Offset { - startVector(structs.count * MemoryLayout<T>.size, elementSize: MemoryLayout<T>.alignment) + startVector( + structs.count * MemoryLayout<T>.size, + elementSize: MemoryLayout<T>.alignment) for i in structs.reversed() { _ = create(struct: i) } @@ -394,7 +415,9 @@ public struct FlatBufferBuilder { struct s: T, position: VOffset) -> Offset { let offset = create(struct: s) - _vtableStorage.add(loc: FieldLoc(offset: _bb.size, position: VOffset(position))) + _vtableStorage.add(loc: FieldLoc( + offset: _bb.size, + position: VOffset(position))) return offset } @@ -529,8 +552,6 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { var numOfFields: Int = 0 /// Last written Index var writtenIndex: Int = 0 - /// the amount of added elements into the buffer - var addedElements: Int { capacity - (numOfFields &* size) } /// Creates the memory to store the buffer in @usableFromInline @@ -555,7 +576,9 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { /// and max offset /// - Parameter loc: Location of encoded element func add(loc: FieldLoc) { - memory.baseAddress?.advanced(by: writtenIndex).storeBytes(of: loc, as: FieldLoc.self) + memory.baseAddress?.advanced(by: writtenIndex).storeBytes( + of: loc, + as: FieldLoc.self) writtenIndex = writtenIndex &+ size numOfFields = numOfFields &+ 1 maxOffset = max(loc.position, maxOffset) @@ -574,7 +597,9 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { func ensure(space: Int) { guard space &+ writtenIndex > capacity else { return } memory.deallocate() - memory = UnsafeMutableRawBufferPointer.allocate(byteCount: space, alignment: size) + memory = UnsafeMutableRawBufferPointer.allocate( + byteCount: space, + alignment: size) capacity = space } diff --git a/swift/Sources/FlatBuffers/FlatBufferObject.swift b/swift/Sources/FlatBuffers/FlatBufferObject.swift index 72325e79..cea3911e 100644 --- a/swift/Sources/FlatBuffers/FlatBufferObject.swift +++ b/swift/Sources/FlatBuffers/FlatBufferObject.swift @@ -31,15 +31,26 @@ public protocol FlatBufferObject: FlatbuffersInitializable { var __buffer: ByteBuffer! { get } } +/// `ObjectAPIPacker` is a protocol that allows object to pack and unpack from a +/// `NativeObject` to a flatbuffers Object and vice versa. public protocol ObjectAPIPacker { + /// associatedtype to the object that should be unpacked. associatedtype T + + /// `pack` tries packs the variables of a native Object into the `ByteBuffer` by using + /// the FlatBufferBuilder + /// - Parameters: + /// - builder: FlatBufferBuilder that will host incoming data + /// - obj: Object of associatedtype to the current implementer static func pack(_ builder: inout FlatBufferBuilder, obj: inout T?) -> Offset + + /// `pack` packs the variables of a native Object into the `ByteBuffer` by using + /// the FlatBufferBuilder + /// - Parameters: + /// - builder: FlatBufferBuilder that will host incoming data + /// - obj: Object of associatedtype to the current implementer static func pack(_ builder: inout FlatBufferBuilder, obj: inout T) -> Offset - mutating func unpack() -> T -} -public protocol Enum { - associatedtype T: Scalar - static var byteSize: Int { get } - var value: T { get } + /// `Unpack` unpacks a flatbuffers object into a `NativeObject` + mutating func unpack() -> T } diff --git a/swift/Sources/FlatBuffers/FlatBuffersUtils.swift b/swift/Sources/FlatBuffers/FlatBuffersUtils.swift index f0a96dbd..2ab68fd2 100644 --- a/swift/Sources/FlatBuffers/FlatBuffersUtils.swift +++ b/swift/Sources/FlatBuffers/FlatBuffersUtils.swift @@ -16,7 +16,8 @@ import Foundation -public final class FlatBuffersUtils { +/// FlatBuffersUtils hosts some utility functions that might be useful +public enum FlatBuffersUtils { /// Gets the size of the prefix /// - Parameter bb: Flatbuffer object @@ -24,7 +25,9 @@ public final class FlatBuffersUtils { bb.read(def: Int32.self, position: bb.reader) } - /// Removes the prefix by duplicating the Flatbuffer + /// Removes the prefix by duplicating the Flatbuffer this call is expensive since its + /// creates a new buffer use `readPrefixedSizeCheckedRoot` instead + /// unless a completely new buffer is required /// - Parameter bb: Flatbuffer object public static func removeSizePrefix(bb: ByteBuffer) -> ByteBuffer { bb.duplicate(removing: MemoryLayout<Int32>.size) diff --git a/swift/Sources/FlatBuffers/FlatbuffersErrors.swift b/swift/Sources/FlatBuffers/FlatbuffersErrors.swift new file mode 100644 index 00000000..97188e9e --- /dev/null +++ b/swift/Sources/FlatBuffers/FlatbuffersErrors.swift @@ -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 + +/// Collection of thrown from the Flatbuffer verifier +public enum FlatbuffersErrors: Error, Equatable { + + /// Thrown when buffer is bigger than the allowed 2GiB + case exceedsMaxSizeAllowed + /// Thrown when there is an missaligned pointer at position + /// of type + case missAlignedPointer(position: Int, type: String) + /// Thrown when trying to read a value that goes out of the + /// current buffer bounds + case outOfBounds(position: UInt, end: Int) + /// Thrown when the signed offset is out of the bounds of the + /// current buffer + case signedOffsetOutOfBounds(offset: Int, position: Int) + /// Thrown when a required field doesnt exist within the buffer + case requiredFieldDoesntExist(position: VOffset, name: String) + /// Thrown when a string is missing its NULL Terminator `\0`, + /// this can be disabled in the `VerifierOptions` + case missingNullTerminator(position: Int, str: String?) + /// Thrown when the verifier has reached the maximum tables allowed, + /// this can be disabled in the `VerifierOptions` + case maximumTables + /// Thrown when the verifier has reached the maximum depth allowed, + /// this can be disabled in the `VerifierOptions` + case maximumDepth + /// Thrown when the verifier is presented with an unknown union case + case unknownUnionCase + /// thrown when a value for a union is not found within the buffer + case valueNotFound(key: Int?, keyName: String, field: Int?, fieldName: String) + /// thrown when the size of the keys vector doesnt match fields vector + case unionVectorSize( + keyVectorSize: Int, + fieldVectorSize: Int, + unionKeyName: String, + fieldName: String) + case apparentSizeTooLarge + + public static func == (lhs: FlatbuffersErrors, rhs: FlatbuffersErrors) -> Bool { + lhs.localizedDescription == rhs.localizedDescription + } +} diff --git a/swift/Sources/FlatBuffers/Message.swift b/swift/Sources/FlatBuffers/Message.swift index 52ae487b..76b7a622 100644 --- a/swift/Sources/FlatBuffers/Message.swift +++ b/swift/Sources/FlatBuffers/Message.swift @@ -14,6 +14,10 @@ * limitations under the License. */ +import Foundation + +/// FlatBufferGRPCMessage protocol that should allow us to invoke +/// initializers directly from the GRPC generated code public protocol FlatBufferGRPCMessage { /// Raw pointer which would be pointing to the beginning of the readable bytes diff --git a/swift/Sources/FlatBuffers/NativeObject.swift b/swift/Sources/FlatBuffers/NativeObject.swift index 2f360f0c..724c2eba 100644 --- a/swift/Sources/FlatBuffers/NativeObject.swift +++ b/swift/Sources/FlatBuffers/NativeObject.swift @@ -16,6 +16,9 @@ import Foundation +/// NativeObject is a protocol that all of the `Object-API` generated code should be +/// conforming to since it allows developers the ease of use to pack and unpack their +/// Flatbuffers objects public protocol NativeObject {} extension NativeObject { @@ -36,7 +39,10 @@ extension NativeObject { /// - Returns: returns the encoded sized ByteBuffer /// - Note: The `serialize(builder:type)` can be considered as a function that allows you to create smaller builder instead of the default `1024`. /// It can be considered less expensive in terms of memory allocation - public func serialize<T: ObjectAPIPacker>(builder: inout FlatBufferBuilder, type: T.Type) -> ByteBuffer where T.T == Self { + public func serialize<T: ObjectAPIPacker>( + builder: inout FlatBufferBuilder, + type: T.Type) -> ByteBuffer where T.T == Self + { var s = self let root = type.pack(&builder, obj: &s) builder.finish(offset: root) diff --git a/swift/Sources/FlatBuffers/Root.swift b/swift/Sources/FlatBuffers/Root.swift new file mode 100644 index 00000000..8891cafb --- /dev/null +++ b/swift/Sources/FlatBuffers/Root.swift @@ -0,0 +1,68 @@ +/* + * 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 + +/// Takes in a prefixed sized buffer, where the prefixed size would be skipped. +/// And would verify that the buffer passed is a valid `Flatbuffers` Object. +/// - Parameters: +/// - byteBuffer: Buffer that needs to be checked and read +/// - options: Verifier options +/// - Throws: FlatbuffersErrors +/// - Returns: Returns a valid, checked Flatbuffers object +public func getPrefixedSizeCheckedRoot<T: FlatBufferObject & Verifiable>( + byteBuffer: inout ByteBuffer, + options: VerifierOptions = .init()) throws -> T +{ + byteBuffer.skipPrefix() + return try getCheckedRoot(byteBuffer: &byteBuffer, options: options) +} + +/// Takes in a prefixed sized buffer, where the prefixed size would be skipped. +/// Returns a `NON-Checked` flatbuffers object +/// - Parameter byteBuffer: Buffer that contains data +/// - Returns: Returns a Flatbuffers object +public func getPrefixedSizeRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) -> T { + byteBuffer.skipPrefix() + return getRoot(byteBuffer: &byteBuffer) + +} + +/// Verifies that the buffer passed is a valid `Flatbuffers` Object. +/// - Parameters: +/// - byteBuffer: Buffer that needs to be checked and read +/// - options: Verifier options +/// - Throws: FlatbuffersErrors +/// - Returns: Returns a valid, checked Flatbuffers object +public func getCheckedRoot<T: FlatBufferObject & Verifiable>( + byteBuffer: inout ByteBuffer, + options: VerifierOptions = .init()) throws -> T +{ + var verifier = try Verifier(buffer: &byteBuffer, options: options) + try ForwardOffset<T>.verify(&verifier, at: 0, of: T.self) + return T.init( + byteBuffer, + o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) + Int32(byteBuffer.reader)) +} + +/// Returns a `NON-Checked` flatbuffers object +/// - Parameter byteBuffer: Buffer that contains data +/// - Returns: Returns a Flatbuffers object +public func getRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) -> T { + T.init( + byteBuffer, + o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) + Int32(byteBuffer.reader)) +} diff --git a/swift/Sources/FlatBuffers/String+extension.swift b/swift/Sources/FlatBuffers/String+extension.swift index 7c9b06e7..5a16a81b 100644 --- a/swift/Sources/FlatBuffers/String+extension.swift +++ b/swift/Sources/FlatBuffers/String+extension.swift @@ -16,6 +16,42 @@ import Foundation +extension String: Verifiable { + + /// Verifies that the current value is which the bounds of the buffer, and if + /// the current `Value` is aligned properly + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - position: Current position within the buffer + /// - type: The type of the object to be verified + /// - Throws: Errors coming from `inBuffer`, `missingNullTerminator` and `outOfBounds` + public static func verify<T>( + _ verifier: inout Verifier, + at position: Int, + of type: T.Type) throws where T: Verifiable + { + + let range = try String.verifyRange(&verifier, at: position, of: UInt8.self) + /// Safe &+ since we already check for overflow in verify range + let stringLen = range.start &+ range.count + + if stringLen >= verifier.capacity { + throw FlatbuffersErrors.outOfBounds( + position: UInt(clamping: stringLen.magnitude), + end: verifier.capacity) + } + + let isNullTerminated = verifier._buffer.read( + def: UInt8.self, + position: stringLen) == 0 + + if !verifier._options._ignoreMissingNullTerminators && !isNullTerminated { + let str = verifier._buffer.readString(at: range.start, count: range.count) + throw FlatbuffersErrors.missingNullTerminator(position: position, str: str) + } + } +} + extension String: FlatbuffersInitializable { /// Initailizes a string from a Flatbuffers ByteBuffer @@ -23,10 +59,11 @@ extension String: FlatbuffersInitializable { /// - 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)) + let v = Int(o) + let count = bb.read(def: Int32.self, position: v) self = bb.readString( - at: Int32(MemoryLayout<Int32>.size) + o, - count: count) ?? "" + at: MemoryLayout<Int32>.size + v, + count: Int(count)) ?? "" } } @@ -53,7 +90,10 @@ extension String: NativeObject { 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 { + 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") } } diff --git a/swift/Sources/FlatBuffers/Struct.swift b/swift/Sources/FlatBuffers/Struct.swift index 0b546d9d..ac701d46 100644 --- a/swift/Sources/FlatBuffers/Struct.swift +++ b/swift/Sources/FlatBuffers/Struct.swift @@ -16,16 +16,30 @@ import Foundation +/// Struct is a representation of a mutable `Flatbuffers` struct +/// since native structs are value types and cant be mutated @frozen public struct Struct { + + /// Hosting Bytebuffer public private(set) var bb: ByteBuffer + /// Current position of the struct public private(set) var postion: Int32 + /// Initializer for a mutable flatbuffers struct + /// - Parameters: + /// - bb: Current hosting Bytebuffer + /// - position: Current position for the struct in the ByteBuffer public init(bb: ByteBuffer, position: Int32 = 0) { self.bb = bb postion = position } + /// Reads data from the buffer directly at offset O + /// - Parameters: + /// - type: Type of data to be read + /// - o: Current offset of the data + /// - Returns: Data of Type T that conforms to type Scalar public func readBuffer<T: Scalar>(of type: T.Type, at o: Int32) -> T { let r = bb.read(def: T.self, position: Int(o + postion)) return r diff --git a/swift/Sources/FlatBuffers/Table.swift b/swift/Sources/FlatBuffers/Table.swift index 7c185559..34efedd5 100644 --- a/swift/Sources/FlatBuffers/Table.swift +++ b/swift/Sources/FlatBuffers/Table.swift @@ -16,11 +16,22 @@ import Foundation +/// `Table` is a Flatbuffers object that can read, +/// mutate scalar fields within a valid flatbuffers buffer @frozen public struct Table { + + /// Hosting Bytebuffer public private(set) var bb: ByteBuffer + /// Current position of the table within the buffer public private(set) var postion: Int32 + /// Initializer for the table interface to allow generated code to read + /// data from memory + /// - Parameters: + /// - bb: ByteBuffer that stores data + /// - position: Current table position + /// - Note: This will `CRASH` if read on a big endian machine public init(bb: ByteBuffer, position: Int32 = 0) { guard isLitteEndian else { fatalError("Reading/Writing a buffer in big endian machine is not supported on swift") @@ -29,6 +40,10 @@ public struct Table { postion = position } + /// Gets the offset of the current field within the buffer by reading + /// the vtable + /// - Parameter o: current offset + /// - Returns: offset of field within buffer public func offset(_ o: Int32) -> Int32 { let vtable = postion - bb.read(def: Int32.self, position: Int(postion)) return o < bb.read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read( @@ -36,7 +51,13 @@ public struct Table { position: Int(vtable + o))) : 0 } - public func indirect(_ o: Int32) -> Int32 { o + bb.read(def: Int32.self, position: Int(o)) } + /// Gets the indirect offset of the current stored object + /// (applicable only for object arrays) + /// - Parameter o: current offset + /// - Returns: offset of field within buffer + public func indirect(_ o: Int32) -> Int32 { + o + bb.read(def: Int32.self, position: Int(o)) + } /// String reads from the buffer with respect to position of the current table. /// - Parameter offset: Offset of the string @@ -45,14 +66,15 @@ public struct Table { } /// Direct string reads from the buffer disregarding the position of the table. - /// It would be preferable to use string unless the current position of the table is not needed + /// It would be preferable to use string unless the current position of the table + /// is not needed /// - Parameter offset: Offset of the string public func directString(at offset: Int32) -> String? { var offset = offset offset += bb.read(def: Int32.self, position: Int(offset)) let count = bb.read(def: Int32.self, position: Int(offset)) - let position = offset + Int32(MemoryLayout<Int32>.size) - return bb.readString(at: position, count: count) + let position = Int(offset) + MemoryLayout<Int32>.size + return bb.readString(at: position, count: Int(count)) } /// Reads from the buffer with respect to the position in the table. @@ -81,19 +103,30 @@ public struct Table { return r } + /// Returns that current `Union` object at a specific offset + /// by adding offset to the current position of table + /// - Parameter o: offset + /// - Returns: A flatbuffers object public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T { let o = o + postion return directUnion(o) } + /// Returns a direct `Union` object at a specific offset + /// - Parameter o: offset + /// - Returns: A flatbuffers object public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T { T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o))) } + /// Returns a vector of type T at a specific offset + /// This should only be used by `Scalars` + /// - Parameter off: Readable offset + /// - Returns: Returns a vector of type [T] public func getVector<T>(at off: Int32) -> [T]? { let o = offset(off) guard o != 0 else { return nil } - return bb.readSlice(index: vector(at: o), count: vector(count: o)) + return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o))) } /// Vector count gets the count of Elements within the array @@ -115,17 +148,36 @@ public struct Table { return o + bb.read(def: Int32.self, position: Int(o)) + 4 } - static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { o + fbb.read( - def: Int32.self, - position: Int(o)) } + /// Reading an indirect offset of a table. + /// - Parameters: + /// - o: position within the buffer + /// - fbb: ByteBuffer + /// - Returns: table offset + static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { + o + fbb.read(def: Int32.self, position: Int(o)) + } + /// Gets a vtable value according to an table Offset and a field offset + /// - Parameters: + /// - o: offset relative to entire buffer + /// - vOffset: Field offset within a vtable + /// - fbb: ByteBuffer + /// - Returns: an position of a field static public func offset(_ o: Int32, vOffset: Int32, fbb: ByteBuffer) -> Int32 { let vTable = Int32(fbb.capacity) - o return vTable + Int32(fbb.read( def: Int16.self, - position: Int(vTable + vOffset - fbb.read(def: Int32.self, position: Int(vTable))))) + position: Int(vTable + vOffset - fbb.read( + def: Int32.self, + position: Int(vTable))))) } + /// Compares two objects at offset A and offset B within a ByteBuffer + /// - Parameters: + /// - off1: first offset to compare + /// - off2: second offset to compare + /// - fbb: Bytebuffer + /// - Returns: returns the difference between static public func compare(_ off1: Int32, _ off2: Int32, fbb: ByteBuffer) -> Int32 { let memorySize = Int32(MemoryLayout<Int32>.size) let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) @@ -145,6 +197,12 @@ public struct Table { return len1 - len2 } + /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer + /// - Parameters: + /// - off1: Offset to compare to + /// - key: bytes array to compare to + /// - fbb: Bytebuffer + /// - Returns: returns the difference between static public func compare(_ off1: Int32, _ key: [Byte], fbb: ByteBuffer) -> Int32 { let memorySize = Int32(MemoryLayout<Int32>.size) let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) diff --git a/swift/Sources/FlatBuffers/TableVerifier.swift b/swift/Sources/FlatBuffers/TableVerifier.swift new file mode 100644 index 00000000..6749b6f0 --- /dev/null +++ b/swift/Sources/FlatBuffers/TableVerifier.swift @@ -0,0 +1,202 @@ +/* + * 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 + +/// `TableVerifier` verifies a table object is within a provided memory. +/// It checks if all the objects for a specific generated table, are within +/// the bounds of the buffer, aligned. +public struct TableVerifier { + + /// position of current table in `ByteBuffer` + fileprivate var _position: Int + + /// Current VTable position + fileprivate var _vtable: Int + + /// Length of current VTable + fileprivate var _vtableLength: Int + + /// `Verifier` object created in the base verifable call. + fileprivate var _verifier: Verifier + + /// Creates a `TableVerifier` verifier that allows the Flatbuffer object + /// to verify the buffer before accessing any of the data. + /// + /// - Parameters: + /// - position: Current table Position + /// - vtable: Current `VTable` position + /// - vtableLength: Current `VTable` length + /// - verifier: `Verifier` Object that caches the data of the verifiable object + internal init( + position: Int, + vtable: Int, + vtableLength: Int, + verifier: inout Verifier) + { + _position = position + _vtable = vtable + _vtableLength = vtableLength + _verifier = verifier + } + + /// Dereference the current object position from the `VTable` + /// - Parameter field: Current VTable refrence to position. + /// - Throws: A `FlatbuffersErrors` incase the voffset is not aligned/outOfBounds/apparentSizeTooLarge + /// - Returns: An optional position for current field + internal mutating func dereference(_ field: VOffset) throws -> Int? { + if field >= _vtableLength { + return nil + } + + /// Reading the offset for the field needs to be read. + let offset: VOffset = try _verifier.getValue( + at: Int(clamping: _vtable &+ Int(field)) + ) + + if offset > 0 { + return Int(clamping: _position &+ Int(offset)) + } + return nil + } + + /// Visits all the fields within the table to validate the integrity + /// of the data + /// - Parameters: + /// - field: voffset of the current field to be read + /// - fieldName: fieldname to report data Errors. + /// - required: If the field has to be available in the buffer + /// - type: Type of field to be read + /// - Throws: A `FlatbuffersErrors` where the field is corrupt + public mutating func visit<T>( + field: VOffset, + fieldName: String, + required: Bool, + type: T.Type) throws where T: Verifiable + { + let derefValue = try dereference(field) + + if let value = derefValue { + try T.verify(&_verifier, at: value, of: T.self) + return + } + if required { + throw FlatbuffersErrors.requiredFieldDoesntExist( + position: field, + name: fieldName) + } + } + + /// Visits all the fields for a union object within the table to + /// validate the integrity of the data + /// - Parameters: + /// - key: Current Key Voffset + /// - field: Current field Voffset + /// - unionKeyName: Union key name + /// - fieldName: Field key name + /// - required: indicates if an object is required to be present + /// - completion: Completion is a handler that WILL be called in the generated + /// - Throws: A `FlatbuffersErrors` where the field is corrupt + public mutating func visit<T>( + unionKey key: VOffset, + unionField field: VOffset, + unionKeyName: String, + fieldName: String, + required: Bool, + completion: @escaping (inout Verifier, T, Int) throws -> Void) throws where T: UnionEnum + { + let keyPos = try dereference(key) + let valPos = try dereference(field) + + if keyPos == nil && valPos == nil { + if required { + throw FlatbuffersErrors.requiredFieldDoesntExist( + position: key, + name: unionKeyName) + } + return + } + + if let _key = keyPos, + let _val = valPos + { + /// verifiying that the key is within the buffer + try T.T.verify(&_verifier, at: _key, of: T.T.self) + guard let _enum = try T.init(value: _verifier._buffer.read( + def: T.T.self, + position: _key)) else + { + throw FlatbuffersErrors.unknownUnionCase + } + /// we are assuming that Unions will always be of type Uint8 + try completion( + &_verifier, + _enum, + _val) + return + } + throw FlatbuffersErrors.valueNotFound( + key: keyPos, + keyName: unionKeyName, + field: valPos, + fieldName: fieldName) + } + + /// Visits and validates all the objects within a union vector + /// - Parameters: + /// - key: Current Key Voffset + /// - field: Current field Voffset + /// - unionKeyName: Union key name + /// - fieldName: Field key name + /// - required: indicates if an object is required to be present + /// - completion: Completion is a handler that WILL be called in the generated + /// - Throws: A `FlatbuffersErrors` where the field is corrupt + public mutating func visitUnionVector<T>( + unionKey key: VOffset, + unionField field: VOffset, + unionKeyName: String, + fieldName: String, + required: Bool, + completion: @escaping (inout Verifier, T, Int) throws -> Void) throws where T: UnionEnum + { + let keyVectorPosition = try dereference(key) + let offsetVectorPosition = try dereference(field) + + if let keyPos = keyVectorPosition, + let valPos = offsetVectorPosition + { + try UnionVector<T>.verify( + &_verifier, + keyPosition: keyPos, + fieldPosition: valPos, + unionKeyName: unionKeyName, + fieldName: fieldName, + completion: completion) + return + } + if required { + throw FlatbuffersErrors.requiredFieldDoesntExist( + position: field, + name: fieldName) + } + } + + /// Finishs the current Table verifier, and subtracts the current + /// table from the incremented depth. + public mutating func finish() { + _verifier.finish() + } +} diff --git a/swift/Sources/FlatBuffers/VeriferOptions.swift b/swift/Sources/FlatBuffers/VeriferOptions.swift new file mode 100644 index 00000000..454dd51e --- /dev/null +++ b/swift/Sources/FlatBuffers/VeriferOptions.swift @@ -0,0 +1,52 @@ +/* + * 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 + +/// `VerifierOptions` is a set of options to verify a flatbuffer +public struct VerifierOptions { + + /// Maximum `Apparent` size if the buffer can be expanded into a DAG tree + internal var _maxApparentSize: UOffset + + /// Maximum table count allowed in a buffer + internal var _maxTableCount: UOffset + + /// Maximum depth allowed in a buffer + internal var _maxDepth: UOffset + + /// Ignoring missing null terminals in strings + internal var _ignoreMissingNullTerminators: Bool + + /// initializes the set of options for the verifier + /// - Parameters: + /// - maxDepth: Maximum depth allowed in a buffer + /// - maxTableCount: Maximum table count allowed in a buffer + /// - maxApparentSize: Maximum `Apparent` size if the buffer can be expanded into a DAG tree + /// - ignoreMissingNullTerminators: Ignoring missing null terminals in strings *Currently not supported in swift* + public init( + maxDepth: UOffset = 64, + maxTableCount: UOffset = 1000000, + maxApparentSize: UOffset = 1 << 31, + ignoreMissingNullTerminators: Bool = false) + { + _maxDepth = maxDepth + _maxTableCount = maxTableCount + _maxApparentSize = maxApparentSize + _ignoreMissingNullTerminators = ignoreMissingNullTerminators + } + +} diff --git a/swift/Sources/FlatBuffers/Verifiable.swift b/swift/Sources/FlatBuffers/Verifiable.swift new file mode 100644 index 00000000..e601cfc2 --- /dev/null +++ b/swift/Sources/FlatBuffers/Verifiable.swift @@ -0,0 +1,211 @@ +/* + * 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 + +/// Verifiable is a protocol all swift flatbuffers object should conform to, +/// since swift is similar to `cpp` and `rust` where the data is read directly +/// from `unsafeMemory` thus the need to verify if the buffer received is a valid one +public protocol Verifiable { + + /// Verifies that the current value is which the bounds of the buffer, and if + /// the current `Value` is aligned properly + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - position: Current position within the buffer + /// - type: The type of the object to be verified + /// - Throws: Errors coming from `inBuffer` function + static func verify<T>( + _ verifier: inout Verifier, + at position: Int, + of type: T.Type) throws where T: Verifiable +} + +extension Verifiable { + + /// Verifies if the current range to be read is within the bounds of the buffer, + /// and if the range is properly aligned + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - position: Current position within the buffer + /// - type: The type of the object to be verified + /// - Throws: Erros thrown from `isAligned` & `rangeInBuffer` + /// - Returns: a tuple of the start position and the count of objects within the range + @discardableResult + public static func verifyRange<T>( + _ verifier: inout Verifier, + at position: Int, of type: T.Type) throws -> (start: Int, count: Int) + { + let len: UOffset = try verifier.getValue(at: position) + let intLen = Int(len) + let start = Int(clamping: (position &+ MemoryLayout<Int32>.size).magnitude) + try verifier.isAligned(position: start, type: type.self) + try verifier.rangeInBuffer(position: start, size: intLen) + return (start, intLen) + } +} + +extension Verifiable where Self: Scalar { + + /// Verifies that the current value is which the bounds of the buffer, and if + /// the current `Value` is aligned properly + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - position: Current position within the buffer + /// - type: The type of the object to be verified + /// - Throws: Errors coming from `inBuffer` function + public static func verify<T>( + _ verifier: inout Verifier, + at position: Int, + of type: T.Type) throws where T: Verifiable + { + try verifier.inBuffer(position: position, of: type.self) + } +} + +// MARK: - ForwardOffset + +/// ForwardOffset is a container to wrap around the Generic type to be verified +/// from the flatbuffers object. +public enum ForwardOffset<U>: Verifiable where U: Verifiable { + + /// Verifies that the current value is which the bounds of the buffer, and if + /// the current `Value` is aligned properly + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - position: Current position within the buffer + /// - type: The type of the object to be verified + /// - Throws: Errors coming from `inBuffer` function + public static func verify<T>( + _ verifier: inout Verifier, + at position: Int, + of type: T.Type) throws where T: Verifiable + { + let offset: UOffset = try verifier.getValue(at: position) + let nextOffset = Int(clamping: (Int(offset) &+ position).magnitude) + try U.verify(&verifier, at: nextOffset, of: U.self) + } +} + +// MARK: - Vector + +/// Vector is a container to wrap around the Generic type to be verified +/// from the flatbuffers object. +public enum Vector<U, S>: Verifiable where U: Verifiable, S: Verifiable { + + /// Verifies that the current value is which the bounds of the buffer, and if + /// the current `Value` is aligned properly + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - position: Current position within the buffer + /// - type: The type of the object to be verified + /// - Throws: Errors coming from `inBuffer` function + public static func verify<T>( + _ verifier: inout Verifier, + at position: Int, + of type: T.Type) throws where T: Verifiable + { + /// checks if the next verification type S is equal to U of type forwardOffset + /// This had to be done since I couldnt find a solution for duplicate call functions + /// A fix will be appreciated + if U.self is ForwardOffset<S>.Type { + let range = try verifyRange(&verifier, at: position, of: UOffset.self) + for index in stride( + from: range.start, + to: Int(clamping: range.start &+ range.count), + by: MemoryLayout<UOffset>.size) + { + try U.verify(&verifier, at: index, of: U.self) + } + } else { + try S.verifyRange(&verifier, at: position, of: S.self) + } + } +} + +// MARK: - UnionVector + +/// UnionVector is a container to wrap around the Generic type to be verified +/// from the flatbuffers object. +public enum UnionVector<S> where S: UnionEnum { + + /// Completion handler for the function Verify, that passes the verifier + /// enum type and position of union field + public typealias Completion = (inout Verifier, S, Int) throws -> Void + + /// Verifies if the current range to be read is within the bounds of the buffer, + /// and if the range is properly aligned. It also verifies if the union type is a + /// *valid/supported* union type. + /// - Parameters: + /// - verifier: Verifier that hosts the buffer + /// - keyPosition: Current union key position within the buffer + /// - fieldPosition: Current union field position within the buffer + /// - unionKeyName: Name of key to written if error is presented + /// - fieldName: Name of field to written if error is presented + /// - completion: Completion is a handler that WILL be called in the generated + /// code to verify the actual objects + /// - Throws: FlatbuffersErrors + public static func verify( + _ verifier: inout Verifier, + keyPosition: Int, + fieldPosition: Int, + unionKeyName: String, + fieldName: String, + completion: @escaping Completion) throws + { + /// Get offset for union key vectors and offset vectors + let keyOffset: UOffset = try verifier.getValue(at: keyPosition) + let fieldOffset: UOffset = try verifier.getValue(at: fieldPosition) + + /// Check if values are within the buffer, returns the start position of vectors, and vector counts + /// Using &+ is safe since we already verified that the value is within the buffer, where the max is + /// going to be 2Gib and swift supports Int64 by default + let keysRange = try S.T.verifyRange( + &verifier, + at: Int(keyOffset) &+ keyPosition, + of: S.T.self) + let offsetsRange = try UOffset.verifyRange( + &verifier, + at: Int(fieldOffset) &+ fieldPosition, + of: UOffset.self) + + guard keysRange.count == offsetsRange.count else { + throw FlatbuffersErrors.unionVectorSize( + keyVectorSize: keysRange.count, + fieldVectorSize: offsetsRange.count, + unionKeyName: unionKeyName, + fieldName: fieldName) + } + + var count = 0 + /// Iterate over the vector of keys and offsets. + while count < keysRange.count { + + /// index of readable enum value in array + let keysIndex = MemoryLayout<S.T>.size * count + guard let _enum = try S.init(value: verifier._buffer.read( + def: S.T.self, + position: keysRange.start + keysIndex)) else + { + throw FlatbuffersErrors.unknownUnionCase + } + /// index of readable offset value in array + let fieldIndex = MemoryLayout<UOffset>.size * count + try completion(&verifier, _enum, offsetsRange.start + fieldIndex) + count += 1 + } + } +} diff --git a/swift/Sources/FlatBuffers/Verifier.swift b/swift/Sources/FlatBuffers/Verifier.swift new file mode 100644 index 00000000..e465b140 --- /dev/null +++ b/swift/Sources/FlatBuffers/Verifier.swift @@ -0,0 +1,199 @@ +/* + * 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 + +/// Verifier that check if the buffer passed into it is a valid, +/// safe, aligned Flatbuffers object since swift read from `unsafeMemory` +public struct Verifier { + + /// Flag to check for alignment if true + fileprivate let _checkAlignment: Bool + /// Capacity of the current buffer + fileprivate var _capacity: Int + /// Current ApparentSize + fileprivate var _apparentSize: UOffset = 0 + /// Amount of tables present within a buffer + fileprivate var _tableCount = 0 + + /// Capacity of the buffer + internal var capacity: Int { _capacity } + /// Current reached depth within the buffer + internal var _depth = 0 + /// Current verifiable ByteBuffer + internal var _buffer: ByteBuffer + /// Options for verification + internal let _options: VerifierOptions + + /// Initializer for the verifier + /// - Parameters: + /// - buffer: Bytebuffer that is required to be verified + /// - options: `VerifierOptions` that set the rule for some of the verification done + /// - checkAlignment: If alignment check is required to be preformed + /// - Throws: `exceedsMaxSizeAllowed` if capacity of the buffer is more than 2GiB + public init( + buffer: inout ByteBuffer, + options: VerifierOptions = .init(), + checkAlignment: Bool = true) throws + { + guard buffer.capacity < FlatBufferMaxSize else { + throw FlatbuffersErrors.exceedsMaxSizeAllowed + } + + _buffer = buffer + _capacity = buffer.capacity + _checkAlignment = checkAlignment + _options = options + } + + /// Resets the verifier to initial state + public mutating func reset() { + _depth = 0 + _tableCount = 0 + } + + /// Checks if the value of type `T` is aligned properly in the buffer + /// - Parameters: + /// - position: Current position + /// - type: Type of value to check + /// - Throws: `missAlignedPointer` if the pointer is not aligned properly + public mutating func isAligned<T>(position: Int, type: T.Type) throws { + + /// If check alignment is false this mutating function doesnt continue + if !_checkAlignment { return } + + /// advance pointer to position X + let ptr = _buffer._storage.memory.advanced(by: position) + /// Check if the pointer is aligned + if Int(bitPattern: ptr) & (MemoryLayout<T>.alignment &- 1) == 0 { + return + } + + throw FlatbuffersErrors.missAlignedPointer( + position: position, + type: String(describing: T.self)) + } + + /// Checks if the value of Size "X" is within the range of the buffer + /// - Parameters: + /// - position: Current postion to be read + /// - size: `Byte` Size of readable object within the buffer + /// - Throws: `outOfBounds` if the value is out of the bounds of the buffer + /// and `apparentSizeTooLarge` if the apparent size is bigger than the one specified + /// in `VerifierOptions` + public mutating func rangeInBuffer(position: Int, size: Int) throws { + let end = UInt(clamping: (position &+ size).magnitude) + if end > _buffer.capacity { + throw FlatbuffersErrors.outOfBounds(position: end, end: capacity) + } + _apparentSize = _apparentSize &+ UInt32(size) + if _apparentSize > _options._maxApparentSize { + throw FlatbuffersErrors.apparentSizeTooLarge + } + } + + /// Validates if a value of type `T` is aligned and within the bounds of + /// the buffer + /// - Parameters: + /// - position: Current readable position + /// - type: Type of value to check + /// - Throws: FlatbuffersErrors + public mutating func inBuffer<T>(position: Int, of type: T.Type) throws { + try isAligned(position: position, type: type) + try rangeInBuffer(position: position, size: MemoryLayout<T>.size) + } + + /// Visits a table at the current position and validates if the table meets + /// the rules specified in the `VerifierOptions` + /// - Parameter position: Current position to be read + /// - Throws: FlatbuffersErrors + /// - Returns: A `TableVerifier` at the current readable table + public mutating func visitTable(at position: Int) throws -> TableVerifier { + let vtablePosition = try derefOffset(position: position) + let vtableLength: VOffset = try getValue(at: vtablePosition) + + let length = Int(vtableLength) + try isAligned( + position: Int(clamping: (vtablePosition + length).magnitude), + type: VOffset.self) + try rangeInBuffer(position: vtablePosition, size: length) + + _tableCount += 1 + + if _tableCount > _options._maxTableCount { + throw FlatbuffersErrors.maximumTables + } + + _depth += 1 + + if _depth > _options._maxDepth { + throw FlatbuffersErrors.maximumDepth + } + + return TableVerifier( + position: position, + vtable: vtablePosition, + vtableLength: length, + verifier: &self) + } + + /// Validates if a value of type `T` is within the buffer and returns it + /// - Parameter position: Current position to be read + /// - Throws: `inBuffer` errors + /// - Returns: a value of type `T` usually a `VTable` or a table offset + internal mutating func getValue<T>(at position: Int) throws -> T { + try inBuffer(position: position, of: T.self) + return _buffer.read(def: T.self, position: position) + } + + /// derefrences an offset within a vtable to get the position of the field + /// in the bytebuffer + /// - Parameter position: Current readable position + /// - Throws: `inBuffer` errors & `signedOffsetOutOfBounds` + /// - Returns: Current readable position for a field + @inline(__always) + internal mutating func derefOffset(position: Int) throws -> Int { + try inBuffer(position: position, of: Int32.self) + + let offset = _buffer.read(def: Int32.self, position: position) + // switching to int32 since swift's default Int is int64 + // this should be safe since we already checked if its within + // the buffer + let _int32Position = UInt32(position) + + let reportedOverflow: (partialValue: UInt32, overflow: Bool) + if offset > 0 { + reportedOverflow = _int32Position.subtractingReportingOverflow(offset.magnitude) + } else { + reportedOverflow = _int32Position.addingReportingOverflow(offset.magnitude) + } + + /// since `subtractingReportingOverflow` & `addingReportingOverflow` returns true, + /// if there is overflow we return failure + if reportedOverflow.overflow || reportedOverflow.partialValue > _buffer.capacity { + throw FlatbuffersErrors.signedOffsetOutOfBounds( + offset: Int(offset), + position: position) + } + + return Int(reportedOverflow.partialValue) + } + + /// finishes the current iteration of verification on an object + internal mutating func finish() { + _depth -= 1 + } +} diff --git a/tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift b/tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift index 114e8f70..da9a3d9b 100644 --- a/tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift +++ b/tests/FlatBuffers.Benchmarks.swift/Sources/FlatBuffers.Benchmarks.swift/main.swift @@ -40,7 +40,7 @@ func run(name: String, runs: Int, action: () -> Void) -> Benchmark { func createDocument(Benchmarks: [Benchmark]) -> String { let separator = "-------------------------------------" var document = "\(separator)\n" - document += "\(String(format: "|\t%@\t\t|\t\t%@\t\t|", "Name", "Scores"))\n" + document += "\(String(format: "|\t%@\t\t |\t\t%@\t\t|", "Name", "Scores"))\n" document += "\(separator)\n" for i in Benchmarks { document += "\(i.description) \n" @@ -89,7 +89,9 @@ func benchmarkThreeMillionStructs() { var offsets: [Offset] = [] for _ in 0..<structCount { - fb.startVector(5 * MemoryLayout<AA>.size, elementSize: MemoryLayout<AA>.alignment) + fb.startVector( + 5 * MemoryLayout<AA>.size, + elementSize: MemoryLayout<AA>.alignment) for _ in 0..<5 { _ = fb.create(struct: AA(a: 2.4, b: 2.4)) } @@ -119,12 +121,18 @@ struct AA: NativeStruct { func benchmark(numberOfRuns runs: Int) { var benchmarks: [Benchmark] = [] let str = (0...99).map { _ -> String in "x" }.joined() - benchmarks.append(run(name: "500_000", runs: runs, action: benchmarkFiveHundredAdds)) + benchmarks.append(run( + name: "500_000", + runs: runs, + action: benchmarkFiveHundredAdds)) benchmarks.append(run(name: "10 str", runs: runs, action: create10Strings)) let hundredStr = run(name: "100 str", runs: runs) { create100Strings(str: str) } - benchmarks.append(run(name: "3M strc", runs: 1, action: benchmarkThreeMillionStructs)) + benchmarks.append(run( + name: "3M strc", + runs: 1, + action: benchmarkThreeMillionStructs)) benchmarks.append(hundredStr) print(createDocument(Benchmarks: benchmarks)) } diff --git a/tests/FlatBuffers.Test.Swift/Package.swift b/tests/FlatBuffers.Test.Swift/Package.swift index ec36de32..12618cbe 100644 --- a/tests/FlatBuffers.Test.Swift/Package.swift +++ b/tests/FlatBuffers.Test.Swift/Package.swift @@ -28,7 +28,9 @@ let package = Package( .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0"), ], targets: [ - .target(name: "SwiftFlatBuffers"), + .target( + name: "SwiftFlatBuffers", + dependencies: ["FlatBuffers"]), .testTarget( name: "FlatBuffers.Test.SwiftTests", dependencies: ["FlatBuffers", "GRPC"]), diff --git a/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer.fbs b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer.fbs new file mode 100644 index 00000000..e0356fa3 --- /dev/null +++ b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer.fbs @@ -0,0 +1,32 @@ +enum Color:ubyte (bit_flags) { + Red = 0, // color Red = (1u << 0) + /// \brief color Green + /// Green is bit_flag with value (1u << 1) + Green, + /// \brief color Blue (1u << 3) + Blue = 3, +} + +struct Test { a:short; b:byte; } + +struct Vec3 (force_align: 8) { + x:float; + y:float; + z:float; + test1:double; + test2:Color; + test3:Test; +} + +/// an example documentation comment: "monster object" +table Monster { + pos:Vec3 (id: 0); + hp:short = 100 (id: 2); + mana:short = 150 (id: 1); + name:string (id: 3, key); + color:Color = Blue (id: 6); + inventory:[ubyte] (id: 5); + testarrayoftables:[Monster] (id: 4); +} + +root_type Monster; diff --git a/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer_generated.swift b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer_generated.swift new file mode 100644 index 00000000..dffeaa87 --- /dev/null +++ b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/fuzzer_generated.swift @@ -0,0 +1,224 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// swiftlint:disable all +// swiftformat:disable all + +import FlatBuffers + +public enum Color: UInt8, Enum, Verifiable { + public typealias T = UInt8 + public static var byteSize: Int { return MemoryLayout<UInt8>.size } + public var value: UInt8 { return self.rawValue } + case red = 1 + /// \brief color Green + /// Green is bit_flag with value (1u << 1) + case green = 2 + /// \brief color Blue (1u << 3) + case blue = 8 + + public static var max: Color { return .blue } + public static var min: Color { return .red } +} + +public struct Test: NativeStruct, Verifiable { + + static func validateVersion() { FlatBuffersVersion_2_0_0() } + + private var _a: Int16 + private var _b: Int8 + private let padding0__: UInt8 = 0 + + public init(a: Int16, b: Int8) { + _a = a + _b = b + } + + public init() { + _a = 0 + _b = 0 + } + + public var a: Int16 { _a } + public var b: Int8 { _b } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: Test.self) + } +} + +public struct Test_Mutable: FlatBufferObject { + + static func validateVersion() { FlatBuffersVersion_2_0_0() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Struct + + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) } + + public var a: Int16 { return _accessor.readBuffer(of: Int16.self, at: 0) } + public var b: Int8 { return _accessor.readBuffer(of: Int8.self, at: 2) } +} + +public struct Vec3: NativeStruct, Verifiable { + + static func validateVersion() { FlatBuffersVersion_2_0_0() } + + private var _x: Float32 + private var _y: Float32 + private var _z: Float32 + private let padding0__: UInt32 = 0 + private var _test1: Double + private var _test2: UInt8 + private let padding1__: UInt8 = 0 + private var _test3: Test + private let padding2__: UInt16 = 0 + + public init(x: Float32, y: Float32, z: Float32, test1: Double, test2: Color, test3: Test) { + _x = x + _y = y + _z = z + _test1 = test1 + _test2 = test2.value + _test3 = test3 + } + + public init() { + _x = 0.0 + _y = 0.0 + _z = 0.0 + _test1 = 0.0 + _test2 = 0 + _test3 = Test() + } + + public var x: Float32 { _x } + public var y: Float32 { _y } + public var z: Float32 { _z } + public var test1: Double { _test1 } + public var test2: Color { Color(rawValue: _test2)! } + public var test3: Test { _test3 } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: Vec3.self) + } +} + +public struct Vec3_Mutable: FlatBufferObject { + + static func validateVersion() { FlatBuffersVersion_2_0_0() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Struct + + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) } + + public var x: Float32 { return _accessor.readBuffer(of: Float32.self, at: 0) } + public var y: Float32 { return _accessor.readBuffer(of: Float32.self, at: 4) } + public var z: Float32 { return _accessor.readBuffer(of: Float32.self, at: 8) } + public var test1: Double { return _accessor.readBuffer(of: Double.self, at: 16) } + public var test2: Color { return Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: 24)) ?? .red } + public var test3: Test_Mutable { return Test_Mutable(_accessor.bb, o: _accessor.postion + 26) } +} + +/// an example documentation comment: "monster object" +public struct Monster: FlatBufferObject, Verifiable { + + static func validateVersion() { FlatBuffersVersion_2_0_0() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + public static func getRootAsMonster(bb: ByteBuffer) -> Monster { return Monster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) } + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private enum VTOFFSET: VOffset { + case pos = 4 + case mana = 6 + case hp = 8 + case name = 10 + case testarrayoftables = 12 + case inventory = 14 + case color = 16 + var v: Int32 { Int32(self.rawValue) } + var p: VOffset { self.rawValue } + } + + public var pos: Vec3? { let o = _accessor.offset(VTOFFSET.pos.v); return o == 0 ? nil : _accessor.readBuffer(of: Vec3.self, at: o) } + public var mutablePos: Vec3_Mutable? { let o = _accessor.offset(VTOFFSET.pos.v); return o == 0 ? nil : Vec3_Mutable(_accessor.bb, o: o + _accessor.postion) } + public var mana: Int16 { let o = _accessor.offset(VTOFFSET.mana.v); return o == 0 ? 150 : _accessor.readBuffer(of: Int16.self, at: o) } + public var hp: Int16 { let o = _accessor.offset(VTOFFSET.hp.v); return o == 0 ? 100 : _accessor.readBuffer(of: Int16.self, at: o) } + public var name: String! { let o = _accessor.offset(VTOFFSET.name.v); return _accessor.string(at: o) } + public var nameSegmentArray: [UInt8]! { return _accessor.getVector(at: VTOFFSET.name.v) } + public var testarrayoftablesCount: Int32 { let o = _accessor.offset(VTOFFSET.testarrayoftables.v); return o == 0 ? 0 : _accessor.vector(count: o) } + public func testarrayoftables(at index: Int32) -> Monster? { let o = _accessor.offset(VTOFFSET.testarrayoftables.v); return o == 0 ? nil : Monster(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) } + public func testarrayoftablesBy(key: String) -> Monster? { let o = _accessor.offset(VTOFFSET.testarrayoftables.v); return o == 0 ? nil : Monster.lookupByKey(vector: _accessor.vector(at: o), key: key, fbb: _accessor.bb) } + public var inventoryCount: Int32 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.vector(count: o) } + public func inventory(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } + public var inventory: [UInt8] { return _accessor.getVector(at: VTOFFSET.inventory.v) ?? [] } + public var color: Color { let o = _accessor.offset(VTOFFSET.color.v); return o == 0 ? .blue : Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .blue } + public static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 7) } + public static func add(pos: Vec3?, _ fbb: inout FlatBufferBuilder) { guard let pos = pos else { return }; fbb.create(struct: pos, position: VTOFFSET.pos.p) } + public static func add(mana: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: mana, def: 150, at: VTOFFSET.mana.p) } + public static func add(hp: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: hp, def: 100, at: VTOFFSET.hp.p) } + public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VTOFFSET.name.p) } + public static func addVectorOf(testarrayoftables: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: testarrayoftables, at: VTOFFSET.testarrayoftables.p) } + public static func addVectorOf(inventory: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: inventory, at: VTOFFSET.inventory.p) } + public static func add(color: Color, _ fbb: inout FlatBufferBuilder) { fbb.add(element: color.rawValue, def: 8, at: VTOFFSET.color.p) } + public static func endMonster(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [10]); return end } + public static func createMonster( + _ fbb: inout FlatBufferBuilder, + pos: Vec3? = nil, + mana: Int16 = 150, + hp: Int16 = 100, + nameOffset name: Offset = Offset(), + testarrayoftablesVectorOffset testarrayoftables: Offset = Offset(), + inventoryVectorOffset inventory: Offset = Offset(), + color: Color = .blue + ) -> Offset { + let __start = Monster.startMonster(&fbb) + Monster.add(pos: pos, &fbb) + Monster.add(mana: mana, &fbb) + Monster.add(hp: hp, &fbb) + Monster.add(name: name, &fbb) + Monster.addVectorOf(testarrayoftables: testarrayoftables, &fbb) + Monster.addVectorOf(inventory: inventory, &fbb) + Monster.add(color: color, &fbb) + return Monster.endMonster(&fbb, start: __start) + } + public static func sortVectorOfMonster(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { + var off = offsets + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 10, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + return fbb.createVector(ofOffsets: off) + } + fileprivate static func lookupByKey(vector: Int32, key: String, fbb: ByteBuffer) -> Monster? { + let key = key.utf8.map { $0 } + var span = fbb.read(def: Int32.self, position: Int(vector - 4)) + var start: Int32 = 0 + while span != 0 { + var middle = span / 2 + let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb) + let comp = Table.compare(Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: 10, fbb: fbb), key, fbb: fbb) + if comp > 0 { + span = middle + } else if comp < 0 { + middle += 1 + start += middle + span -= middle + } else { + return Monster(fbb, o: tableOffset) + } + } + return nil + } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.pos.p, fieldName: "pos", required: false, type: Vec3.self) + try _v.visit(field: VTOFFSET.mana.p, fieldName: "mana", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.hp.p, fieldName: "hp", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: true, type: ForwardOffset<String>.self) + try _v.visit(field: VTOFFSET.testarrayoftables.p, fieldName: "testarrayoftables", required: false, type: ForwardOffset<Vector<ForwardOffset<Monster>, Monster>>.self) + try _v.visit(field: VTOFFSET.inventory.p, fieldName: "inventory", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self) + try _v.visit(field: VTOFFSET.color.p, fieldName: "color", required: false, type: Color.self) + _v.finish() + } +} + diff --git a/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/main.swift b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/main.swift index a5a23a67..86e422c6 100644 --- a/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/main.swift +++ b/tests/FlatBuffers.Test.Swift/Sources/SwiftFlatBuffers/main.swift @@ -14,5 +14,16 @@ * limitations under the License. */ -import Foundation -print("Flatbuffers") +import FlatBuffers + +@_cdecl("LLVMFuzzerTestOneInput") +public func FuzzFlatbuffers(_ start: UnsafeRawPointer, _ count: Int) -> CInt { + let bytes = UnsafeRawBufferPointer(start: start, count: count) + do { + var buffer = ByteBuffer(contiguousBytes: bytes, count: count) + let _: Monster = try getCheckedRoot(byteBuffer: &buffer) + } catch { + } + + return 0 +} diff --git a/tests/FlatBuffers.Test.Swift/SwiftTest.sh b/tests/FlatBuffers.Test.Swift/SwiftTest.sh index 5e1c6cdd..7edf8177 100755 --- a/tests/FlatBuffers.Test.Swift/SwiftTest.sh +++ b/tests/FlatBuffers.Test.Swift/SwiftTest.sh @@ -9,5 +9,17 @@ fbc --swift --gen-mutable --grpc --gen-object-api -I ${test_dir}/include_test ${ fbc --swift ${test_dir}/optional_scalars.fbs fbc --swift --gen-object-api ${test_dir}/more_defaults.fbs cd ${swift_dir} + +cd ${swift_dir}/Sources/SwiftFlatBuffers +# create better fuzzing test file +fbc --swift fuzzer.fbs +cd ${swift_dir} + swift build --build-tests swift test + +if [ $(uname -s) != Darwin ]; then + echo fuzzing + swift build -c debug -Xswiftc -sanitize=fuzzer,address -Xswiftc -parse-as-library + swift build -c release -Xswiftc -sanitize=fuzzer,address -Xswiftc -parse-as-library +fi diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift index eb57785f..21c3daf4 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift @@ -26,9 +26,11 @@ typealias Stat = MyGame_Example_Stat class FlatBuffersMonsterWriterTests: XCTestCase { func testData() { + // swiftformat:disable all let data = Data([48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) + // swiftformat:enable all let _data = ByteBuffer(data: data) - readMonster(fb: _data) + readVerifiedMonster(fb: _data) } func testReadFromOtherLanguages() { @@ -36,29 +38,36 @@ class FlatBuffersMonsterWriterTests: XCTestCase { let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon") guard let data = try? Data(contentsOf: url) else { return } let _data = ByteBuffer(data: data) - readMonster(fb: _data) + readVerifiedMonster(fb: _data) } func testCreateMonster() { let bytes = createMonster(withPrefix: false) + // swiftformat:disable all XCTAssertEqual(bytes.sizedByteArray, [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) - readMonster(fb: bytes.buffer) + // swiftformat:enable all + let monster = MyGame_Example_Monster.getRootAsMonster(bb: bytes.buffer) + readMonster(monster: monster) mutateMonster(fb: bytes.buffer) - readMonster(fb: bytes.buffer) + readMonster(monster: monster) } func testCreateMonsterResizedBuffer() { let bytes = createMonster(withPrefix: false) + // swiftformat:disable all XCTAssertEqual(bytes.sizedByteArray, [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) - readMonster(fb: bytes.sizedBuffer) + // swiftformat:enable all + readVerifiedMonster(fb: bytes.sizedBuffer) } func testCreateMonsterPrefixed() { let bytes = createMonster(withPrefix: true) + // swiftformat:disable all XCTAssertEqual(bytes.sizedByteArray, [44, 1, 0, 0, 44, 0, 0, 0, 77, 79, 78, 83, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) + // swiftformat:enable all - let newBuf = FlatBuffersUtils.removeSizePrefix(bb: bytes.buffer) - readMonster(fb: newBuf) + var buffer = bytes.buffer + readMonster(monster: getPrefixedSizeRoot(byteBuffer: &buffer)) } func testCreateMonsterUsingCreateMonsterMethodWithNilPos() { @@ -77,7 +86,15 @@ class FlatBuffersMonsterWriterTests: XCTestCase { var fbb = FlatBufferBuilder(initialSize: 1) let name = fbb.create(string: "Barney") let mStart = Monster.startMonster(&fbb) - Monster.add(pos: MyGame_Example_Vec3(x: 10, y: 0, z: 0, test1: 0, test2: .blue, test3: .init()), &fbb) + Monster.add( + pos: MyGame_Example_Vec3( + x: 10, + y: 0, + z: 0, + test1: 0, + test2: .blue, + test3: .init()), + &fbb) Monster.add(name: name, &fbb) let root = Monster.endMonster(&fbb, start: mStart) fbb.finish(offset: root) @@ -88,9 +105,13 @@ class FlatBuffersMonsterWriterTests: XCTestCase { } func testReadMonsterFromUnsafePointerWithoutCopying() { + // swiftformat:disable all var array: [UInt8] = [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0] + // swiftformat:enable all let unpacked = array.withUnsafeMutableBytes { (memory) -> MyGame_Example_MonsterT in - let bytes = ByteBuffer(assumingMemoryBound: memory.baseAddress!, capacity: memory.count) + let bytes = ByteBuffer( + assumingMemoryBound: memory.baseAddress!, + capacity: memory.count) var monster = Monster.getRootAsMonster(bb: bytes) readFlatbufferMonster(monster: &monster) let unpacked = monster.unpack() @@ -104,7 +125,10 @@ class FlatBuffersMonsterWriterTests: XCTestCase { var fbb = FlatBufferBuilder(initialSize: 1) let name = fbb.create(string: "Frodo") let bools = fbb.createVector(boolArray) - let root = Monster.createMonster(&fbb, nameOffset: name, testarrayofboolsVectorOffset: bools) + let root = Monster.createMonster( + &fbb, + nameOffset: name, + testarrayofboolsVectorOffset: bools) fbb.finish(offset: root) let monster = Monster.getRootAsMonster(bb: fbb.sizedBuffer) @@ -117,8 +141,13 @@ class FlatBuffersMonsterWriterTests: XCTestCase { } } - func readMonster(fb: ByteBuffer) { - var monster = Monster.getRootAsMonster(bb: fb) + func readVerifiedMonster(fb: ByteBuffer) { + var byteBuffer = fb + XCTAssertNoThrow(try readMonster(monster: getCheckedRoot(byteBuffer: &byteBuffer) as MyGame_Example_Monster)) + } + + func readMonster(monster: Monster) { + var monster = monster readFlatbufferMonster(monster: &monster) let unpacked: MyGame_Example_MonsterT? = monster.unpack() readObjectApi(monster: unpacked!) @@ -129,7 +158,11 @@ class FlatBuffersMonsterWriterTests: XCTestCase { func createMonster(withPrefix prefix: Bool) -> FlatBufferBuilder { var fbb = FlatBufferBuilder(initialSize: 1) - let names = [fbb.create(string: "Frodo"), fbb.create(string: "Barney"), fbb.create(string: "Wilma")] + let names = [ + fbb.create(string: "Frodo"), + fbb.create(string: "Barney"), + fbb.create(string: "Wilma"), + ] var offsets: [Offset] = [] let start1 = Monster.startMonster(&fbb) Monster.add(name: names[0], &fbb) @@ -161,7 +194,15 @@ class FlatBuffersMonsterWriterTests: XCTestCase { let stringTestVector = fbb.createVector(ofOffsets: [test1, test2]) let mStart = Monster.startMonster(&fbb) - Monster.add(pos: MyGame_Example_Vec3(x: 1, y: 2, z: 3, test1: 3, test2: .green, test3: .init(a: 5, b: 6)), &fbb) + Monster.add( + pos: MyGame_Example_Vec3( + x: 1, + y: 2, + z: 3, + test1: 3, + test2: .green, + test3: .init(a: 5, b: 6)), + &fbb) Monster.add(hp: 80, &fbb) Monster.add(name: str, &fbb) Monster.addVectorOf(inventory: inv, &fbb) diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift index ab5a5187..96cd1f73 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift @@ -52,22 +52,36 @@ final class FlatBuffersTests: XCTestCase { func testCreateFinish() { var b = FlatBufferBuilder(initialSize: 16) - let countryOff = Country.createCountry(builder: &b, name: country, log: 200, lan: 100) + let countryOff = Country.createCountry( + builder: &b, + name: country, + log: 200, + lan: 100) b.finish(offset: countryOff) + // swiftformat:disable all let v: [UInt8] = [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 12, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0] + // swiftformat:enable all XCTAssertEqual(b.sizedByteArray, v) } func testCreateFinishWithPrefix() { var b = FlatBufferBuilder(initialSize: 16) - let countryOff = Country.createCountry(builder: &b, name: country, log: 200, lan: 100) + let countryOff = Country.createCountry( + builder: &b, + name: country, + log: 200, + lan: 100) b.finish(offset: countryOff, addPrefix: true) + // swiftformat:disable all let v: [UInt8] = [44, 0, 0, 0, 16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 12, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0] + // swiftformat:enable all XCTAssertEqual(b.sizedByteArray, v) } func testReadCountry() { + // swiftformat:disable all let v: [UInt8] = [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 12, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0] + // swiftformat:enable all let buffer = ByteBuffer(bytes: v) let c = Country.getRootAsCountry(buffer) XCTAssertEqual(c.lan, 100) @@ -115,14 +129,20 @@ class Country { __t = t } - var lan: Int32 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(of: Int32.self, at: o) } - var log: Int32 { let o = __t.offset(8); return o == 0 ? 0 : __t.readBuffer(of: Int32.self, at: o) } + var lan: Int32 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer( + of: Int32.self, + at: o) } + var log: Int32 { let o = __t.offset(8); return o == 0 ? 0 : __t.readBuffer( + of: Int32.self, + at: o) } var nameVector: [UInt8]? { __t.getVector(at: 4) } var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) } @inlinable static func getRootAsCountry(_ bb: ByteBuffer) -> Country { - Country(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0)))) + Country(Table( + bb: bb, + position: Int32(bb.read(def: UOffset.self, position: 0)))) } @inlinable @@ -132,7 +152,11 @@ class Country { log: Int32, lan: Int32) -> Offset { - createCountry(builder: &builder, offset: builder.create(string: name), log: log, lan: lan) + createCountry( + builder: &builder, + offset: builder.create(string: name), + log: log, + lan: lan) } @inlinable diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift index 9addb81b..5b59b4ed 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersUnionTests.swift @@ -34,7 +34,9 @@ final class FlatBuffersUnionTests: XCTestCase { equippedOffset: weapon.o) b.finish(offset: root) let buffer = b.sizedByteArray + // swiftformat:disable all XCTAssertEqual(buffer, [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 8, 0, 7, 0, 12, 0, 10, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 20, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 5, 0, 4, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0]) + // swiftformat:enable all let monster = LocalMonster.getRootAsMonster(bb: ByteBuffer(bytes: buffer)) XCTAssertEqual(monster.weapon(at: 0)?.dmg, dmg) XCTAssertEqual(monster.weapon(at: 0)?.name, str) @@ -71,7 +73,9 @@ final class FlatBuffersUnionTests: XCTestCase { equippedOffset: weaponTwo, path: path) builder.finish(offset: orc) + // swiftformat:disable all XCTAssertEqual(builder.sizedByteArray, [32, 0, 0, 0, 0, 0, 26, 0, 48, 0, 36, 0, 0, 0, 34, 0, 28, 0, 0, 0, 24, 0, 23, 0, 16, 0, 15, 0, 8, 0, 4, 0, 26, 0, 0, 0, 44, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 76, 0, 0, 0, 0, 0, 44, 1, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 52, 0, 0, 0, 28, 0, 0, 0, 10, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 3, 0, 0, 0, 79, 114, 99, 0, 244, 255, 255, 255, 0, 0, 5, 0, 24, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 3, 0, 12, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0, 5, 0, 0, 0, 83, 119, 111, 114, 100, 0, 0, 0]) + // swiftformat:enable all } func testEnumVector() { @@ -83,7 +87,9 @@ final class FlatBuffersUnionTests: XCTestCase { ColorsNameSpace.Monster.add(colors: off, &builder) let end = ColorsNameSpace.Monster.endMonster(&builder, start: start) builder.finish(offset: end) + // swiftformat:disable all XCTAssertEqual(builder.sizedByteArray, [12, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0]) + // swiftformat:enable all let monster = ColorsNameSpace.Monster.getRootAsMonster(bb: builder.buffer) XCTAssertEqual(monster.colorsCount, 2) XCTAssertEqual(monster.colors(at: 0), .blue) @@ -121,22 +127,36 @@ final class FlatBuffersUnionTests: XCTestCase { XCTAssertEqual(movie.charactersType(at: i), characterType[Int(i)]) } - XCTAssertEqual(movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, 7) - XCTAssertEqual(movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage, swordDmg) - XCTAssertEqual(movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead, 2) + XCTAssertEqual( + movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, + 7) + XCTAssertEqual( + movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage, + swordDmg) + XCTAssertEqual( + movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead, + 2) var objc: MovieT? = movie.unpack() XCTAssertEqual(movie.charactersTypeCount, Int32(objc?.characters.count ?? 0)) - XCTAssertEqual(movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, (objc?.characters[0]?.value as? BookReader)?.booksRead) + XCTAssertEqual( + movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, + (objc?.characters[0]?.value as? BookReader)?.booksRead) fb.clear() let newMovie = Movie.pack(&fb, obj: &objc) fb.finish(offset: newMovie) let packedMovie = Movie.getRootAsMovie(bb: fb.buffer) - XCTAssertEqual(packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead) - XCTAssertEqual(packedMovie.characters(at: 1, type: Attacker.self)?.swordAttackDamage, movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage) - XCTAssertEqual(packedMovie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead, movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead) + XCTAssertEqual( + packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, + movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead) + XCTAssertEqual( + packedMovie.characters(at: 1, type: Attacker.self)?.swordAttackDamage, + movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage) + XCTAssertEqual( + packedMovie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead, + movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead) } func testStringUnion() { @@ -162,7 +182,9 @@ final class FlatBuffersUnionTests: XCTestCase { var movie = Movie.getRootAsMovie(bb: fb.sizedBuffer) XCTAssertEqual(movie.mainCharacter(type: String.self), string) - XCTAssertEqual(movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, 7) + XCTAssertEqual( + movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, + 7) XCTAssertEqual(movie.characters(at: 1, type: String.self), string) var objc: MovieT? = movie.unpack() @@ -175,7 +197,9 @@ final class FlatBuffersUnionTests: XCTestCase { let packedMovie = Movie.getRootAsMovie(bb: fb.buffer) XCTAssertEqual(packedMovie.mainCharacter(type: String.self), string) - XCTAssertEqual(packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, 7) + XCTAssertEqual( + packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead, + 7) XCTAssertEqual(packedMovie.characters(at: 1, type: String.self), string) } } @@ -239,7 +263,10 @@ struct FinalMonster { builder.add(offset: inventory, at: 14) builder.add(element: color.rawValue, def: Color3.green.rawValue, at: 16) builder.add(offset: weapons, at: 18) - builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 20) + builder.add( + element: equipment.rawValue, + def: Equipment.none.rawValue, + at: 20) builder.add(offset: equippedOffset, at: 22) builder.add(offset: path, at: 24) return Offset(offset: builder.endTable(at: start)) @@ -262,7 +289,9 @@ struct LocalMonster { } static func getRootAsMonster(bb: ByteBuffer) -> LocalMonster { - LocalMonster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0)))) + LocalMonster(Table( + bb: bb, + position: Int32(bb.read(def: UOffset.self, position: 0)))) } @inlinable @@ -290,11 +319,15 @@ struct Weapon: FlatBufferObject { init(_ t: Table) { __t = t } init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o)} - var dmg: Int16 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(of: Int16.self, at: o) } + var dmg: Int16 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer( + of: Int16.self, + at: o) } var nameVector: [UInt8]? { __t.getVector(at: 4) } var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) } - static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { Weapon(Table(bb: bb, position: i)) } + static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { Weapon(Table( + bb: bb, + position: i)) } @inlinable static func createWeapon( diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift index 9f0db17c..ccccf751 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersVectorsTests.swift @@ -30,7 +30,9 @@ final class FlatBuffersVectors: XCTestCase { let vector = [n, d] let vectorOffset = b.createVector(ofOffsets: vector) b.finish(offset: vectorOffset) + // swiftformat:disable all XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 2, 0, 0, 0, 48, 0, 0, 0, 16, 0, 0, 0, 0, 0, 10, 0, 18, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 40, 0, 0, 0, 100, 0, 0, 0, 200, 0, 0, 0, 0, 0, 10, 0, 16, 0, 4, 0, 8, 0, 12, 0, 10, 0, 0, 0, 24, 0, 0, 0, 188, 2, 0, 0, 120, 3, 0, 0, 7, 0, 0, 0, 68, 101, 110, 109, 97, 114, 107, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]) + // swiftformat:enable all } func testCreateIntArray() { @@ -38,7 +40,9 @@ final class FlatBuffersVectors: XCTestCase { var b = FlatBufferBuilder(initialSize: 20) let o = b.createVector(numbers, size: numbers.count) b.finish(offset: o) + // swiftformat:disable all XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0]) + // swiftformat:enable all } func testCreateEmptyIntArray() { @@ -54,7 +58,9 @@ final class FlatBuffersVectors: XCTestCase { var b = FlatBufferBuilder(initialSize: 20) let o = b.createVector(ofStrings: strs) b.finish(offset: o) + // swiftformat:disable all XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 2, 0, 0, 0, 20, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0, 7, 0, 0, 0, 68, 101, 110, 109, 97, 114, 107, 0]) + // swiftformat:enable all } func testCreateSharedStringVector() { let norway = "Norway" @@ -67,7 +73,9 @@ final class FlatBuffersVectors: XCTestCase { let v = [noStr, deStr, _noStr, _deStr] let end = b.createVector(ofOffsets: v) b.finish(offset: end) + // swiftformat:disable all XCTAssertEqual(b.sizedByteArray, [4, 0, 0, 0, 4, 0, 0, 0, 28, 0, 0, 0, 12, 0, 0, 0, 20, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 68, 101, 110, 109, 97, 114, 107, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0]) + // swiftformat:enable all } func testReadInt32Array() { @@ -101,7 +109,9 @@ struct Numbers { @inlinable static func getRootAsNumbers(_ bb: ByteBuffer) -> Numbers { - Numbers(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: 0)))) + Numbers(Table( + bb: bb, + position: Int32(bb.read(def: UOffset.self, position: 0)))) } var vArrayInt: [Int]? { __t.getVector(at: 4) } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift index b9b80862..660d5245 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersDoubleTests.swift @@ -23,17 +23,39 @@ final class FlatBuffersDoubleTests: XCTestCase { func testCreateFinish() { var b = FlatBufferBuilder(initialSize: 16) - let countryOff = CountryDouble.createCountry(builder: &b, name: country, log: 200, lan: 100) + let countryOff = CountryDouble.createCountry( + builder: &b, + name: country, + log: 200, + lan: 100) b.finish(offset: countryOff) - let v: [UInt8] = [16, 0, 0, 0, 0, 0, 10, 0, 28, 0, 4, 0, 8, 0, 16, 0, 10, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 64, 0, 0, 0, 0, 0, 0, 105, 64, 0, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0] + // swiftformat:disable all + let v: [UInt8] = [ + 16, 0, 0, 0, 0, 0, 10, 0, 28, 0, 4, 0, 8, 0, 16, 0, 10, + 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 64, 0, 0, 0, + 0, 0, 0, 105, 64, 0, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, + 97, 121, 0, 0 + ] + // swiftformat:enable all XCTAssertEqual(b.sizedByteArray, v) } func testCreateFinishWithPrefix() { var b = FlatBufferBuilder(initialSize: 16) - let countryOff = CountryDouble.createCountry(builder: &b, name: country, log: 200, lan: 100) + let countryOff = CountryDouble.createCountry( + builder: &b, + name: country, + log: 200, + lan: 100) b.finish(offset: countryOff, addPrefix: true) - let v: [UInt8] = [60, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 28, 0, 4, 0, 8, 0, 16, 0, 10, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 64, 0, 0, 0, 0, 0, 0, 105, 64, 0, 0, 0, 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0] + // swiftformat:disable all + let v: [UInt8] = [ + 60, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 28 + , 0, 4, 0, 8, 0, 16, 0, 10, 0, 0, 0, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 89, 64, 0, 0, 0, 0, 0, 0, 105, 64, 0, 0, 0, + 0, 6, 0, 0, 0, 78, 111, 114, 119, 97, 121, 0, 0 + ] + // swiftformat:enable all XCTAssertEqual(b.sizedByteArray, v) } } @@ -57,7 +79,11 @@ class CountryDouble { log: Double, lan: Double) -> Offset { - createCountry(builder: &builder, offset: builder.create(string: name), log: log, lan: lan) + createCountry( + builder: &builder, + offset: builder.create(string: name), + log: log, + lan: lan) } static func createCountry( diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersVerifierTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersVerifierTests.swift new file mode 100644 index 00000000..dd80abf8 --- /dev/null +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersVerifierTests.swift @@ -0,0 +1,238 @@ +/* + * 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 XCTest +@testable import FlatBuffers + +final class FlatbuffersVerifierTests: XCTestCase { + + lazy var validStorage: ByteBuffer.Storage = ByteBuffer.Storage( + count: Int(FlatBufferMaxSize) - 1, + alignment: 1) + lazy var errorStorage: ByteBuffer.Storage = ByteBuffer.Storage( + count: Int(FlatBufferMaxSize) + 1, + alignment: 1) + + var buffer: ByteBuffer! + + var validFlatbuffersObject: ByteBuffer! + var invalidFlatbuffersObject: ByteBuffer! + + override func setUp() { + // swiftformat:disable all + buffer = ByteBuffer(initialSize: 32) + add(buffer: &buffer, v: 4, p: 16) + add(buffer: &buffer, v: 4, p: 20) + + validFlatbuffersObject = ByteBuffer(bytes: [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) + + invalidFlatbuffersObject = ByteBuffer(bytes: [0, 48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) + + // swiftformat:enable all + } + + func testVeriferInitPassing() { + var buffer = ByteBuffer(initialSize: 0) + buffer._storage = validStorage + XCTAssertNoThrow(try Verifier(buffer: &buffer)) + } + + func testVeriferInitFailing() { + var buffer = ByteBuffer(initialSize: 0) + buffer._storage = errorStorage + XCTAssertThrowsError(try Verifier(buffer: &buffer)) + } + + func testVerifierCheckAlignment() { + var verifier = try! Verifier(buffer: &buffer) + do { + try verifier.isAligned(position: 20, type: Int.self) + } catch { + XCTAssertEqual( + error as? FlatbuffersErrors, + .missAlignedPointer(position: 20, type: "Int")) + } + XCTAssertNoThrow(try verifier.isAligned(position: 16, type: Int.self)) + + var newVerifer = try! Verifier(buffer: &buffer, checkAlignment: false) + XCTAssertNoThrow(try newVerifer.isAligned(position: 16, type: Int.self)) + } + + func testRangeInBuffer() { + var verifier = try! Verifier(buffer: &buffer) + let size = MemoryLayout<Int64>.size + XCTAssertNoThrow(try verifier.rangeInBuffer(position: 24, size: size)) + XCTAssertThrowsError(try verifier.rangeInBuffer(position: 26, size: size)) + XCTAssertThrowsError(try verifier.rangeInBuffer(position: 26, size: size)) + XCTAssertThrowsError(try verifier.rangeInBuffer(position: 30, size: size)) + XCTAssertThrowsError(try verifier.rangeInBuffer(position: 32, size: size)) + XCTAssertThrowsError(try verifier.rangeInBuffer(position: 34, size: size)) + + verifier = try! Verifier( + buffer: &buffer, + options: .init(maxDepth: 0, maxTableCount: 0, maxApparentSize: 4)) + do { + try verifier.rangeInBuffer(position: 24, size: size) + } catch { + XCTAssertEqual( + error as! FlatbuffersErrors, + .apparentSizeTooLarge) + } + } + + func testPositionInBuffer() { + var verifier = try! Verifier(buffer: &buffer) + XCTAssertNoThrow(try verifier.inBuffer(position: 0, of: Int64.self)) + XCTAssertNoThrow(try verifier.inBuffer(position: 24, of: Int64.self)) + XCTAssertThrowsError(try verifier.inBuffer(position: -9, of: Int64.self)) + XCTAssertThrowsError(try verifier.inBuffer(position: 25, of: Int64.self)) + XCTAssertThrowsError(try verifier.inBuffer(position: 26, of: Int32.self)) + XCTAssertThrowsError(try verifier.inBuffer(position: 26, of: Int64.self)) + XCTAssertThrowsError(try verifier.inBuffer(position: 30, of: Int64.self)) + XCTAssertThrowsError(try verifier.inBuffer(position: 32, of: Int64.self)) + XCTAssertThrowsError(try verifier.inBuffer(position: 34, of: Int64.self)) + } + + func testVisitTable() { + var verifier = try! Verifier(buffer: &validFlatbuffersObject) + XCTAssertNoThrow(try verifier.visitTable(at: 48)) + verifier.reset() + } + + func testTableVerifier() { + var verifier = try! Verifier(buffer: &validFlatbuffersObject) + + var tableVerifer = try! verifier.visitTable(at: 48) + XCTAssertNoThrow(try tableVerifer.visit( + field: 4, + fieldName: "Vec", + required: false, + type: Vec3.self)) + XCTAssertNoThrow(try tableVerifer.visit( + field: 8, + fieldName: "hp", + required: false, + type: Int16.self)) + + XCTAssertNoThrow(try tableVerifer.visit( + field: 10, + fieldName: "name", + required: true, + type: ForwardOffset<String>.self)) + + XCTAssertNoThrow(try tableVerifer.visit( + field: 14, + fieldName: "inventory", + required: false, + type: ForwardOffset<Vector<UInt8, UInt8>>.self)) + + XCTAssertNoThrow(try tableVerifer.visit( + field: 22, + fieldName: "test4", + required: false, + type: ForwardOffset<Vector<MyGame_Example_Test, MyGame_Example_Test>>.self)) + + XCTAssertNoThrow(try tableVerifer.visit( + field: 24, + fieldName: "Vector of strings", + required: false, + type: ForwardOffset<Vector<ForwardOffset<String>, String>>.self)) + + do { + try tableVerifer.visit( + field: 13, + fieldName: "notvalid", + required: false, + type: Int16.self) + } catch { + XCTAssertEqual( + error as! FlatbuffersErrors, + .missAlignedPointer(position: 25, type: "UInt16")) + } + + do { + try tableVerifer.visit( + unionKey: 18, + unionField: 20, + unionKeyName: "testType", + fieldName: "test", + required: false, + completion: { (verifier, key: MyGame_Example_Any_, pos) in + switch key { + case .none_: + break + case .monster: + try ForwardOffset<MyGame_Example_Monster>.verify( + &verifier, + at: pos, + of: MyGame_Example_Monster.self) + + case .testsimpletablewithenum: + break + case .mygameExample2Monster: + break + } + }) + } catch { + XCTAssertEqual( + error as! FlatbuffersErrors, + .missAlignedPointer(position: 25, type: "UInt16")) + } + } + + func testVerifyUnionVectors() { + // swiftformat:disable all + var byteBuffer = ByteBuffer(bytes: [20, 0, 0, 0, 77, 79, 86, 73, 12, 0, 12, 0, 0, 0, 0, 0, 8, 0, 4, 0, 12, 0, 0, 0, 8, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 24, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0, 3, 0, 0, 0, 3, 1, 4, 0, 2, 0, 0, 0, 7, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 8, 0, 0, 0]) + // swiftformat:enable all + XCTAssertNoThrow(try getCheckedRoot(byteBuffer: &byteBuffer) as Movie) + } + + func testFullVerifier() { + XCTAssertNoThrow(try getCheckedRoot(byteBuffer: &validFlatbuffersObject) as MyGame_Example_Monster) + } + + func testInvalidBuffer() { + XCTAssertThrowsError(try getCheckedRoot(byteBuffer: &invalidFlatbuffersObject) as MyGame_Example_Monster) + } + + func testValidUnionBuffer() { + let string = "Awesome \\\\t\t\nstring!" + var fb = FlatBufferBuilder() + let stringOffset = fb.create(string: string) + let characterType: [Character] = [.bookfan, .other] + + let characters = [ + fb.create(struct: BookReader(booksRead: 7)), + stringOffset, + ] + let types = fb.createVector(characterType) + let characterVector = fb.createVector(ofOffsets: characters) + + let end = Movie.createMovie( + &fb, + mainCharacterType: .other, + mainCharacterOffset: Offset(offset: stringOffset.o), + charactersTypeVectorOffset: types, + charactersVectorOffset: characterVector) + Movie.finish(&fb, end: end) + var buf = fb.sizedBuffer + XCTAssertNoThrow(try getCheckedRoot(byteBuffer: &buf) as Movie) + } + + func add(buffer: inout ByteBuffer, v: Int32, p: Int) { + buffer.write(value: v, index: p) + } +} diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift index 8ae91113..9c04bb81 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift @@ -36,11 +36,17 @@ extension FlatBuffersMonsterWriterTests { ("testCreateMonster", testCreateMonster), ("testCreateMonsterPrefixed", testCreateMonsterPrefixed), ("testCreateMonsterResizedBuffer", testCreateMonsterResizedBuffer), - ("testCreateMonsterUsingCreateMonsterMethodWithNilPos", testCreateMonsterUsingCreateMonsterMethodWithNilPos), - ("testCreateMonsterUsingCreateMonsterMethodWithPosX", testCreateMonsterUsingCreateMonsterMethodWithPosX), + ( + "testCreateMonsterUsingCreateMonsterMethodWithNilPos", + testCreateMonsterUsingCreateMonsterMethodWithNilPos), + ( + "testCreateMonsterUsingCreateMonsterMethodWithPosX", + testCreateMonsterUsingCreateMonsterMethodWithPosX), ("testData", testData), ("testReadFromOtherLanguages", testReadFromOtherLanguages), - ("testReadMonsterFromUnsafePointerWithoutCopying", testReadMonsterFromUnsafePointerWithoutCopying), + ( + "testReadMonsterFromUnsafePointerWithoutCopying", + testReadMonsterFromUnsafePointerWithoutCopying), ] } @@ -108,6 +114,25 @@ extension FlatBuffersVectors { ] } +extension FlatbuffersVerifierTests { + // DO NOT MODIFY: This is autogenerated, use: + // `swift test --generate-linuxmain` + // to regenerate. + static let __allTests__FlatbuffersVerifierTests = [ + ("testFullVerifier", testFullVerifier), + ("testInvalidBuffer", testInvalidBuffer), + ("testPositionInBuffer", testPositionInBuffer), + ("testRangeInBuffer", testRangeInBuffer), + ("testTableVerifier", testTableVerifier), + ("testValidUnionBuffer", testValidUnionBuffer), + ("testVeriferInitFailing", testVeriferInitFailing), + ("testVeriferInitPassing", testVeriferInitPassing), + ("testVerifierCheckAlignment", testVerifierCheckAlignment), + ("testVerifyUnionVectors", testVerifyUnionVectors), + ("testVisitTable", testVisitTable), + ] +} + public func __allTests() -> [XCTestCaseEntry] { [ testCase(FlatBuffersDoubleTests.__allTests__FlatBuffersDoubleTests), @@ -117,6 +142,7 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(FlatBuffersTests.__allTests__FlatBuffersTests), testCase(FlatBuffersUnionTests.__allTests__FlatBuffersUnionTests), testCase(FlatBuffersVectors.__allTests__FlatBuffersVectors), + testCase(FlatbuffersVerifierTests.__allTests__FlatbuffersVerifierTests), ] } #endif diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift index d955bb6c..9925ac3c 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift @@ -5,7 +5,7 @@ import FlatBuffers /// Composite components of Monster color. -public enum MyGame_Example_Color: UInt8, Enum { +public enum MyGame_Example_Color: UInt8, Enum, Verifiable { public typealias T = UInt8 public static var byteSize: Int { return MemoryLayout<UInt8>.size } public var value: UInt8 { return self.rawValue } @@ -15,13 +15,12 @@ public enum MyGame_Example_Color: UInt8, Enum { case green = 2 /// \brief color Blue (1u << 3) case blue = 8 - public static var max: MyGame_Example_Color { return .blue } public static var min: MyGame_Example_Color { return .red } } -public enum MyGame_Example_Race: Int8, Enum { +public enum MyGame_Example_Race: Int8, Enum, Verifiable { public typealias T = Int8 public static var byteSize: Int { return MemoryLayout<Int8>.size } public var value: Int8 { return self.rawValue } @@ -29,21 +28,24 @@ public enum MyGame_Example_Race: Int8, Enum { case human = 0 case dwarf = 1 case elf = 2 - public static var max: MyGame_Example_Race { return .elf } public static var min: MyGame_Example_Race { return .none_ } } -public enum MyGame_Example_Any_: UInt8, Enum { +public enum MyGame_Example_Any_: UInt8, UnionEnum { public typealias T = UInt8 + + public init?(value: T) { + self.init(rawValue: value) + } + public static var byteSize: Int { return MemoryLayout<UInt8>.size } public var value: UInt8 { return self.rawValue } case none_ = 0 case monster = 1 case testsimpletablewithenum = 2 case mygameExample2Monster = 3 - public static var max: MyGame_Example_Any_ { return .mygameExample2Monster } public static var min: MyGame_Example_Any_ { return .none_ } @@ -71,15 +73,19 @@ public struct MyGame_Example_Any_Union { } } } -public enum MyGame_Example_AnyUniqueAliases: UInt8, Enum { +public enum MyGame_Example_AnyUniqueAliases: UInt8, UnionEnum { public typealias T = UInt8 + + public init?(value: T) { + self.init(rawValue: value) + } + public static var byteSize: Int { return MemoryLayout<UInt8>.size } public var value: UInt8 { return self.rawValue } case none_ = 0 case m = 1 case ts = 2 case m2 = 3 - public static var max: MyGame_Example_AnyUniqueAliases { return .m2 } public static var min: MyGame_Example_AnyUniqueAliases { return .none_ } @@ -107,15 +113,19 @@ public struct MyGame_Example_AnyUniqueAliasesUnion { } } } -public enum MyGame_Example_AnyAmbiguousAliases: UInt8, Enum { +public enum MyGame_Example_AnyAmbiguousAliases: UInt8, UnionEnum { public typealias T = UInt8 + + public init?(value: T) { + self.init(rawValue: value) + } + public static var byteSize: Int { return MemoryLayout<UInt8>.size } public var value: UInt8 { return self.rawValue } case none_ = 0 case m1 = 1 case m2 = 2 case m3 = 3 - public static var max: MyGame_Example_AnyAmbiguousAliases { return .m3 } public static var min: MyGame_Example_AnyAmbiguousAliases { return .none_ } @@ -143,7 +153,7 @@ public struct MyGame_Example_AnyAmbiguousAliasesUnion { } } } -public struct MyGame_Example_Test: NativeStruct, NativeObject { +public struct MyGame_Example_Test: NativeStruct, Verifiable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -168,6 +178,10 @@ public struct MyGame_Example_Test: NativeStruct, NativeObject { public var a: Int16 { _a } public var b: Int8 { _b } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: MyGame_Example_Test.self) + } } public struct MyGame_Example_Test_Mutable: FlatBufferObject { @@ -197,7 +211,7 @@ public struct MyGame_Example_Test_Mutable: FlatBufferObject { } } -public struct MyGame_Example_Vec3: NativeStruct, NativeObject { +public struct MyGame_Example_Vec3: NativeStruct, Verifiable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -245,6 +259,10 @@ public struct MyGame_Example_Vec3: NativeStruct, NativeObject { public var test1: Double { _test1 } public var test2: MyGame_Example_Color { MyGame_Example_Color(rawValue: _test2)! } public var test3: MyGame_Example_Test { _test3 } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: MyGame_Example_Vec3.self) + } } public struct MyGame_Example_Vec3_Mutable: FlatBufferObject { @@ -281,7 +299,7 @@ public struct MyGame_Example_Vec3_Mutable: FlatBufferObject { } } -public struct MyGame_Example_Ability: NativeStruct, NativeObject { +public struct MyGame_Example_Ability: NativeStruct, Verifiable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -305,6 +323,10 @@ public struct MyGame_Example_Ability: NativeStruct, NativeObject { public var id: UInt32 { _id } public var distance: UInt32 { _distance } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: MyGame_Example_Ability.self) + } } public struct MyGame_Example_Ability_Mutable: FlatBufferObject { @@ -334,7 +356,7 @@ public struct MyGame_Example_Ability_Mutable: FlatBufferObject { } } -public struct MyGame_Example_StructOfStructs: NativeStruct, NativeObject { +public struct MyGame_Example_StructOfStructs: NativeStruct, Verifiable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -366,6 +388,10 @@ public struct MyGame_Example_StructOfStructs: NativeStruct, NativeObject { public var a: MyGame_Example_Ability { _a } public var b: MyGame_Example_Test { _b } public var c: MyGame_Example_Ability { _c } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: MyGame_Example_StructOfStructs.self) + } } public struct MyGame_Example_StructOfStructs_Mutable: FlatBufferObject { @@ -394,7 +420,7 @@ public struct MyGame_Example_StructOfStructs_Mutable: FlatBufferObject { } } -public struct MyGame_InParentNamespace: FlatBufferObject, ObjectAPIPacker { +public struct MyGame_InParentNamespace: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -422,6 +448,11 @@ public struct MyGame_InParentNamespace: FlatBufferObject, ObjectAPIPacker { let __root = MyGame_InParentNamespace.startInParentNamespace(&builder) return MyGame_InParentNamespace.endInParentNamespace(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + _v.finish() + } } public class MyGame_InParentNamespaceT: NativeObject { @@ -436,7 +467,7 @@ public class MyGame_InParentNamespaceT: NativeObject { public func serialize() -> ByteBuffer { return serialize(type: MyGame_InParentNamespace.self) } } -public struct MyGame_Example2_Monster: FlatBufferObject, ObjectAPIPacker { +public struct MyGame_Example2_Monster: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -464,6 +495,11 @@ public struct MyGame_Example2_Monster: FlatBufferObject, ObjectAPIPacker { let __root = MyGame_Example2_Monster.startMonster(&builder) return MyGame_Example2_Monster.endMonster(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + _v.finish() + } } public class MyGame_Example2_MonsterT: NativeObject { @@ -478,7 +514,7 @@ public class MyGame_Example2_MonsterT: NativeObject { public func serialize() -> ByteBuffer { return serialize(type: MyGame_Example2_Monster.self) } } -internal struct MyGame_Example_TestSimpleTableWithEnum: FlatBufferObject, ObjectAPIPacker { +internal struct MyGame_Example_TestSimpleTableWithEnum: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } internal var __buffer: ByteBuffer! { return _accessor.bb } @@ -524,6 +560,12 @@ internal struct MyGame_Example_TestSimpleTableWithEnum: FlatBufferObject, Object MyGame_Example_TestSimpleTableWithEnum.add(color: obj.color, &builder) return MyGame_Example_TestSimpleTableWithEnum.endTestSimpleTableWithEnum(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.color.p, fieldName: "color", required: false, type: MyGame_Example_Color.self) + _v.finish() + } } internal class MyGame_Example_TestSimpleTableWithEnumT: NativeObject { @@ -541,7 +583,7 @@ internal class MyGame_Example_TestSimpleTableWithEnumT: NativeObject { internal func serialize() -> ByteBuffer { return serialize(type: MyGame_Example_TestSimpleTableWithEnum.self) } } -public struct MyGame_Example_Stat: FlatBufferObject, ObjectAPIPacker { +public struct MyGame_Example_Stat: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -632,6 +674,14 @@ public struct MyGame_Example_Stat: FlatBufferObject, ObjectAPIPacker { MyGame_Example_Stat.add(count: obj.count, &builder) return MyGame_Example_Stat.endStat(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.id.p, fieldName: "id", required: false, type: ForwardOffset<String>.self) + try _v.visit(field: VTOFFSET.val.p, fieldName: "val", required: false, type: Int64.self) + try _v.visit(field: VTOFFSET.count.p, fieldName: "count", required: false, type: UInt16.self) + _v.finish() + } } public class MyGame_Example_StatT: NativeObject { @@ -654,7 +704,7 @@ public class MyGame_Example_StatT: NativeObject { public func serialize() -> ByteBuffer { return serialize(type: MyGame_Example_Stat.self) } } -public struct MyGame_Example_Referrable: FlatBufferObject, ObjectAPIPacker { +public struct MyGame_Example_Referrable: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -724,6 +774,12 @@ public struct MyGame_Example_Referrable: FlatBufferObject, ObjectAPIPacker { MyGame_Example_Referrable.add(id: obj.id, &builder) return MyGame_Example_Referrable.endReferrable(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.id.p, fieldName: "id", required: false, type: UInt64.self) + _v.finish() + } } public class MyGame_Example_ReferrableT: NativeObject { @@ -742,7 +798,7 @@ public class MyGame_Example_ReferrableT: NativeObject { } /// an example documentation comment: "monster object" -public struct MyGame_Example_Monster: FlatBufferObject, ObjectAPIPacker { +public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -1253,6 +1309,91 @@ public struct MyGame_Example_Monster: FlatBufferObject, ObjectAPIPacker { MyGame_Example_Monster.addVectorOf(scalarKeySortedTables: __scalarKeySortedTables, &builder) return MyGame_Example_Monster.endMonster(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.pos.p, fieldName: "pos", required: false, type: MyGame_Example_Vec3.self) + try _v.visit(field: VTOFFSET.mana.p, fieldName: "mana", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.hp.p, fieldName: "hp", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: true, type: ForwardOffset<String>.self) + try _v.visit(field: VTOFFSET.inventory.p, fieldName: "inventory", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self) + try _v.visit(field: VTOFFSET.color.p, fieldName: "color", required: false, type: MyGame_Example_Color.self) + try _v.visit(unionKey: VTOFFSET.testType.p, unionField: VTOFFSET.test.p, unionKeyName: "testType", fieldName: "test", required: false, completion: { (verifier, key: MyGame_Example_Any_, pos) in + switch key { + case .none_: + break // NOTE - SWIFT doesnt support none + case .monster: + try ForwardOffset<MyGame_Example_Monster>.verify(&verifier, at: pos, of: MyGame_Example_Monster.self) + case .testsimpletablewithenum: + try ForwardOffset<MyGame_Example_TestSimpleTableWithEnum>.verify(&verifier, at: pos, of: MyGame_Example_TestSimpleTableWithEnum.self) + case .mygameExample2Monster: + try ForwardOffset<MyGame_Example2_Monster>.verify(&verifier, at: pos, of: MyGame_Example2_Monster.self) + } + }) + try _v.visit(field: VTOFFSET.test4.p, fieldName: "test4", required: false, type: ForwardOffset<Vector<MyGame_Example_Test, MyGame_Example_Test>>.self) + try _v.visit(field: VTOFFSET.testarrayofstring.p, fieldName: "testarrayofstring", required: false, type: ForwardOffset<Vector<ForwardOffset<String>, String>>.self) + try _v.visit(field: VTOFFSET.testarrayoftables.p, fieldName: "testarrayoftables", required: false, type: ForwardOffset<Vector<ForwardOffset<MyGame_Example_Monster>, MyGame_Example_Monster>>.self) + try _v.visit(field: VTOFFSET.enemy.p, fieldName: "enemy", required: false, type: ForwardOffset<MyGame_Example_Monster>.self) + try _v.visit(field: VTOFFSET.testnestedflatbuffer.p, fieldName: "testnestedflatbuffer", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self) + try _v.visit(field: VTOFFSET.testempty.p, fieldName: "testempty", required: false, type: ForwardOffset<MyGame_Example_Stat>.self) + try _v.visit(field: VTOFFSET.testbool.p, fieldName: "testbool", required: false, type: Bool.self) + try _v.visit(field: VTOFFSET.testhashs32Fnv1.p, fieldName: "testhashs32Fnv1", required: false, type: Int32.self) + try _v.visit(field: VTOFFSET.testhashu32Fnv1.p, fieldName: "testhashu32Fnv1", required: false, type: UInt32.self) + try _v.visit(field: VTOFFSET.testhashs64Fnv1.p, fieldName: "testhashs64Fnv1", required: false, type: Int64.self) + try _v.visit(field: VTOFFSET.testhashu64Fnv1.p, fieldName: "testhashu64Fnv1", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.testhashs32Fnv1a.p, fieldName: "testhashs32Fnv1a", required: false, type: Int32.self) + try _v.visit(field: VTOFFSET.testhashu32Fnv1a.p, fieldName: "testhashu32Fnv1a", required: false, type: UInt32.self) + try _v.visit(field: VTOFFSET.testhashs64Fnv1a.p, fieldName: "testhashs64Fnv1a", required: false, type: Int64.self) + try _v.visit(field: VTOFFSET.testhashu64Fnv1a.p, fieldName: "testhashu64Fnv1a", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.testarrayofbools.p, fieldName: "testarrayofbools", required: false, type: ForwardOffset<Vector<Bool, Bool>>.self) + try _v.visit(field: VTOFFSET.testf.p, fieldName: "testf", required: false, type: Float32.self) + try _v.visit(field: VTOFFSET.testf2.p, fieldName: "testf2", required: false, type: Float32.self) + try _v.visit(field: VTOFFSET.testf3.p, fieldName: "testf3", required: false, type: Float32.self) + try _v.visit(field: VTOFFSET.testarrayofstring2.p, fieldName: "testarrayofstring2", required: false, type: ForwardOffset<Vector<ForwardOffset<String>, String>>.self) + try _v.visit(field: VTOFFSET.testarrayofsortedstruct.p, fieldName: "testarrayofsortedstruct", required: false, type: ForwardOffset<Vector<MyGame_Example_Ability, MyGame_Example_Ability>>.self) + try _v.visit(field: VTOFFSET.flex.p, fieldName: "flex", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self) + try _v.visit(field: VTOFFSET.test5.p, fieldName: "test5", required: false, type: ForwardOffset<Vector<MyGame_Example_Test, MyGame_Example_Test>>.self) + try _v.visit(field: VTOFFSET.vectorOfLongs.p, fieldName: "vectorOfLongs", required: false, type: ForwardOffset<Vector<Int64, Int64>>.self) + try _v.visit(field: VTOFFSET.vectorOfDoubles.p, fieldName: "vectorOfDoubles", required: false, type: ForwardOffset<Vector<Double, Double>>.self) + try _v.visit(field: VTOFFSET.parentNamespaceTest.p, fieldName: "parentNamespaceTest", required: false, type: ForwardOffset<MyGame_InParentNamespace>.self) + try _v.visit(field: VTOFFSET.vectorOfReferrables.p, fieldName: "vectorOfReferrables", required: false, type: ForwardOffset<Vector<ForwardOffset<MyGame_Example_Referrable>, MyGame_Example_Referrable>>.self) + try _v.visit(field: VTOFFSET.singleWeakReference.p, fieldName: "singleWeakReference", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.vectorOfWeakReferences.p, fieldName: "vectorOfWeakReferences", required: false, type: ForwardOffset<Vector<UInt64, UInt64>>.self) + try _v.visit(field: VTOFFSET.vectorOfStrongReferrables.p, fieldName: "vectorOfStrongReferrables", required: false, type: ForwardOffset<Vector<ForwardOffset<MyGame_Example_Referrable>, MyGame_Example_Referrable>>.self) + try _v.visit(field: VTOFFSET.coOwningReference.p, fieldName: "coOwningReference", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.vectorOfCoOwningReferences.p, fieldName: "vectorOfCoOwningReferences", required: false, type: ForwardOffset<Vector<UInt64, UInt64>>.self) + try _v.visit(field: VTOFFSET.nonOwningReference.p, fieldName: "nonOwningReference", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.vectorOfNonOwningReferences.p, fieldName: "vectorOfNonOwningReferences", required: false, type: ForwardOffset<Vector<UInt64, UInt64>>.self) + try _v.visit(unionKey: VTOFFSET.anyUniqueType.p, unionField: VTOFFSET.anyUnique.p, unionKeyName: "anyUniqueType", fieldName: "anyUnique", required: false, completion: { (verifier, key: MyGame_Example_AnyUniqueAliases, pos) in + switch key { + case .none_: + break // NOTE - SWIFT doesnt support none + case .m: + try ForwardOffset<MyGame_Example_Monster>.verify(&verifier, at: pos, of: MyGame_Example_Monster.self) + case .ts: + try ForwardOffset<MyGame_Example_TestSimpleTableWithEnum>.verify(&verifier, at: pos, of: MyGame_Example_TestSimpleTableWithEnum.self) + case .m2: + try ForwardOffset<MyGame_Example2_Monster>.verify(&verifier, at: pos, of: MyGame_Example2_Monster.self) + } + }) + try _v.visit(unionKey: VTOFFSET.anyAmbiguousType.p, unionField: VTOFFSET.anyAmbiguous.p, unionKeyName: "anyAmbiguousType", fieldName: "anyAmbiguous", required: false, completion: { (verifier, key: MyGame_Example_AnyAmbiguousAliases, pos) in + switch key { + case .none_: + break // NOTE - SWIFT doesnt support none + case .m1: + try ForwardOffset<MyGame_Example_Monster>.verify(&verifier, at: pos, of: MyGame_Example_Monster.self) + case .m2: + try ForwardOffset<MyGame_Example_Monster>.verify(&verifier, at: pos, of: MyGame_Example_Monster.self) + case .m3: + try ForwardOffset<MyGame_Example_Monster>.verify(&verifier, at: pos, of: MyGame_Example_Monster.self) + } + }) + try _v.visit(field: VTOFFSET.vectorOfEnums.p, fieldName: "vectorOfEnums", required: false, type: ForwardOffset<Vector<MyGame_Example_Color, MyGame_Example_Color>>.self) + try _v.visit(field: VTOFFSET.signedEnum.p, fieldName: "signedEnum", required: false, type: MyGame_Example_Race.self) + try _v.visit(field: VTOFFSET.testrequirednestedflatbuffer.p, fieldName: "testrequirednestedflatbuffer", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self) + try _v.visit(field: VTOFFSET.scalarKeySortedTables.p, fieldName: "scalarKeySortedTables", required: false, type: ForwardOffset<Vector<ForwardOffset<MyGame_Example_Stat>, MyGame_Example_Stat>>.self) + _v.finish() + } } public class MyGame_Example_MonsterT: NativeObject { @@ -1505,7 +1646,7 @@ public class MyGame_Example_MonsterT: NativeObject { public func serialize() -> ByteBuffer { return serialize(type: MyGame_Example_Monster.self) } } -public struct MyGame_Example_TypeAliases: FlatBufferObject, ObjectAPIPacker { +public struct MyGame_Example_TypeAliases: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -1634,6 +1775,23 @@ public struct MyGame_Example_TypeAliases: FlatBufferObject, ObjectAPIPacker { MyGame_Example_TypeAliases.addVectorOf(vf64: __vf64, &builder) return MyGame_Example_TypeAliases.endTypeAliases(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.i8.p, fieldName: "i8", required: false, type: Int8.self) + try _v.visit(field: VTOFFSET.u8.p, fieldName: "u8", required: false, type: UInt8.self) + try _v.visit(field: VTOFFSET.i16.p, fieldName: "i16", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.u16.p, fieldName: "u16", required: false, type: UInt16.self) + try _v.visit(field: VTOFFSET.i32.p, fieldName: "i32", required: false, type: Int32.self) + try _v.visit(field: VTOFFSET.u32.p, fieldName: "u32", required: false, type: UInt32.self) + try _v.visit(field: VTOFFSET.i64.p, fieldName: "i64", required: false, type: Int64.self) + try _v.visit(field: VTOFFSET.u64.p, fieldName: "u64", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.f32.p, fieldName: "f32", required: false, type: Float32.self) + try _v.visit(field: VTOFFSET.f64.p, fieldName: "f64", required: false, type: Double.self) + try _v.visit(field: VTOFFSET.v8.p, fieldName: "v8", required: false, type: ForwardOffset<Vector<Int8, Int8>>.self) + try _v.visit(field: VTOFFSET.vf64.p, fieldName: "vf64", required: false, type: ForwardOffset<Vector<Double, Double>>.self) + _v.finish() + } } public class MyGame_Example_TypeAliasesT: NativeObject { diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift index aa8d5722..c43bfbc1 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift @@ -4,20 +4,19 @@ import FlatBuffers -public enum ABC: Int32, Enum { +public enum ABC: Int32, Enum, Verifiable { public typealias T = Int32 public static var byteSize: Int { return MemoryLayout<Int32>.size } public var value: Int32 { return self.rawValue } case a = 0 case b = 1 case c = 2 - public static var max: ABC { return .c } public static var min: ABC { return .a } } -public struct MoreDefaults: FlatBufferObject, ObjectAPIPacker { +public struct MoreDefaults: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -118,6 +117,17 @@ public struct MoreDefaults: FlatBufferObject, ObjectAPIPacker { MoreDefaults.addVectorOf(bools: __bools, &builder) return MoreDefaults.endMoreDefaults(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.ints.p, fieldName: "ints", required: false, type: ForwardOffset<Vector<Int32, Int32>>.self) + try _v.visit(field: VTOFFSET.floats.p, fieldName: "floats", required: false, type: ForwardOffset<Vector<Float32, Float32>>.self) + try _v.visit(field: VTOFFSET.emptyString.p, fieldName: "emptyString", required: false, type: ForwardOffset<String>.self) + try _v.visit(field: VTOFFSET.someString.p, fieldName: "someString", required: false, type: ForwardOffset<String>.self) + try _v.visit(field: VTOFFSET.abcs.p, fieldName: "abcs", required: false, type: ForwardOffset<Vector<ABC, ABC>>.self) + try _v.visit(field: VTOFFSET.bools.p, fieldName: "bools", required: false, type: ForwardOffset<Vector<Bool, Bool>>.self) + _v.finish() + } } public class MoreDefaultsT: NativeObject { diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift index 85f9555c..4fdd7183 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/optional_scalars_generated.swift @@ -4,20 +4,19 @@ import FlatBuffers -public enum optional_scalars_OptionalByte: Int8, Enum { +public enum optional_scalars_OptionalByte: Int8, Enum, Verifiable { public typealias T = Int8 public static var byteSize: Int { return MemoryLayout<Int8>.size } public var value: Int8 { return self.rawValue } case none_ = 0 case one = 1 case two = 2 - public static var max: optional_scalars_OptionalByte { return .two } public static var min: optional_scalars_OptionalByte { return .none_ } } -public struct optional_scalars_ScalarStuff: FlatBufferObject { +public struct optional_scalars_ScalarStuff: FlatBufferObject, Verifiable { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -224,5 +223,46 @@ public struct optional_scalars_ScalarStuff: FlatBufferObject { optional_scalars_ScalarStuff.add(defaultEnum: defaultEnum, &fbb) return optional_scalars_ScalarStuff.endScalarStuff(&fbb, start: __start) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.justI8.p, fieldName: "justI8", required: false, type: Int8.self) + try _v.visit(field: VTOFFSET.maybeI8.p, fieldName: "maybeI8", required: false, type: Int8.self) + try _v.visit(field: VTOFFSET.defaultI8.p, fieldName: "defaultI8", required: false, type: Int8.self) + try _v.visit(field: VTOFFSET.justU8.p, fieldName: "justU8", required: false, type: UInt8.self) + try _v.visit(field: VTOFFSET.maybeU8.p, fieldName: "maybeU8", required: false, type: UInt8.self) + try _v.visit(field: VTOFFSET.defaultU8.p, fieldName: "defaultU8", required: false, type: UInt8.self) + try _v.visit(field: VTOFFSET.justI16.p, fieldName: "justI16", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.maybeI16.p, fieldName: "maybeI16", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.defaultI16.p, fieldName: "defaultI16", required: false, type: Int16.self) + try _v.visit(field: VTOFFSET.justU16.p, fieldName: "justU16", required: false, type: UInt16.self) + try _v.visit(field: VTOFFSET.maybeU16.p, fieldName: "maybeU16", required: false, type: UInt16.self) + try _v.visit(field: VTOFFSET.defaultU16.p, fieldName: "defaultU16", required: false, type: UInt16.self) + try _v.visit(field: VTOFFSET.justI32.p, fieldName: "justI32", required: false, type: Int32.self) + try _v.visit(field: VTOFFSET.maybeI32.p, fieldName: "maybeI32", required: false, type: Int32.self) + try _v.visit(field: VTOFFSET.defaultI32.p, fieldName: "defaultI32", required: false, type: Int32.self) + try _v.visit(field: VTOFFSET.justU32.p, fieldName: "justU32", required: false, type: UInt32.self) + try _v.visit(field: VTOFFSET.maybeU32.p, fieldName: "maybeU32", required: false, type: UInt32.self) + try _v.visit(field: VTOFFSET.defaultU32.p, fieldName: "defaultU32", required: false, type: UInt32.self) + try _v.visit(field: VTOFFSET.justI64.p, fieldName: "justI64", required: false, type: Int64.self) + try _v.visit(field: VTOFFSET.maybeI64.p, fieldName: "maybeI64", required: false, type: Int64.self) + try _v.visit(field: VTOFFSET.defaultI64.p, fieldName: "defaultI64", required: false, type: Int64.self) + try _v.visit(field: VTOFFSET.justU64.p, fieldName: "justU64", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.maybeU64.p, fieldName: "maybeU64", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.defaultU64.p, fieldName: "defaultU64", required: false, type: UInt64.self) + try _v.visit(field: VTOFFSET.justF32.p, fieldName: "justF32", required: false, type: Float32.self) + try _v.visit(field: VTOFFSET.maybeF32.p, fieldName: "maybeF32", required: false, type: Float32.self) + try _v.visit(field: VTOFFSET.defaultF32.p, fieldName: "defaultF32", required: false, type: Float32.self) + try _v.visit(field: VTOFFSET.justF64.p, fieldName: "justF64", required: false, type: Double.self) + try _v.visit(field: VTOFFSET.maybeF64.p, fieldName: "maybeF64", required: false, type: Double.self) + try _v.visit(field: VTOFFSET.defaultF64.p, fieldName: "defaultF64", required: false, type: Double.self) + try _v.visit(field: VTOFFSET.justBool.p, fieldName: "justBool", required: false, type: Bool.self) + try _v.visit(field: VTOFFSET.maybeBool.p, fieldName: "maybeBool", required: false, type: Bool.self) + try _v.visit(field: VTOFFSET.defaultBool.p, fieldName: "defaultBool", required: false, type: Bool.self) + try _v.visit(field: VTOFFSET.justEnum.p, fieldName: "justEnum", required: false, type: optional_scalars_OptionalByte.self) + try _v.visit(field: VTOFFSET.maybeEnum.p, fieldName: "maybeEnum", required: false, type: optional_scalars_OptionalByte.self) + try _v.visit(field: VTOFFSET.defaultEnum.p, fieldName: "defaultEnum", required: false, type: optional_scalars_OptionalByte.self) + _v.finish() + } } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift index 46edc512..676b0570 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift @@ -4,8 +4,13 @@ import FlatBuffers -public enum Character: UInt8, Enum { +public enum Character: UInt8, UnionEnum { public typealias T = UInt8 + + public init?(value: T) { + self.init(rawValue: value) + } + public static var byteSize: Int { return MemoryLayout<UInt8>.size } public var value: UInt8 { return self.rawValue } case none_ = 0 @@ -15,7 +20,6 @@ public enum Character: UInt8, Enum { case bookfan = 4 case other = 5 case unused = 6 - public static var max: Character { return .unused } public static var min: Character { return .none_ } @@ -52,7 +56,7 @@ public struct CharacterUnion { } } } -public struct Rapunzel: NativeStruct, NativeObject { +public struct Rapunzel: NativeStruct, Verifiable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -71,6 +75,10 @@ public struct Rapunzel: NativeStruct, NativeObject { } public var hairLength: Int32 { _hairLength } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: Rapunzel.self) + } } public struct Rapunzel_Mutable: FlatBufferObject { @@ -98,7 +106,7 @@ public struct Rapunzel_Mutable: FlatBufferObject { } } -public struct BookReader: NativeStruct, NativeObject { +public struct BookReader: NativeStruct, Verifiable, NativeObject { static func validateVersion() { FlatBuffersVersion_2_0_0() } @@ -117,6 +125,10 @@ public struct BookReader: NativeStruct, NativeObject { } public var booksRead: Int32 { _booksRead } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + try verifier.inBuffer(position: position, of: BookReader.self) + } } public struct BookReader_Mutable: FlatBufferObject { @@ -144,7 +156,7 @@ public struct BookReader_Mutable: FlatBufferObject { } } -public struct Attacker: FlatBufferObject, ObjectAPIPacker { +public struct Attacker: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -190,6 +202,12 @@ public struct Attacker: FlatBufferObject, ObjectAPIPacker { Attacker.add(swordAttackDamage: obj.swordAttackDamage, &builder) return Attacker.endAttacker(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.swordAttackDamage.p, fieldName: "swordAttackDamage", required: false, type: Int32.self) + _v.finish() + } } public class AttackerT: NativeObject { @@ -207,7 +225,7 @@ public class AttackerT: NativeObject { public func serialize() -> ByteBuffer { return serialize(type: Attacker.self) } } -public struct Movie: FlatBufferObject, ObjectAPIPacker { +public struct Movie: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_2_0_0() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -283,6 +301,47 @@ public struct Movie: FlatBufferObject, ObjectAPIPacker { Movie.addVectorOf(characters: __characters, &builder) return Movie.endMovie(&builder, start: __root) } + + public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(unionKey: VTOFFSET.mainCharacterType.p, unionField: VTOFFSET.mainCharacter.p, unionKeyName: "mainCharacterType", fieldName: "mainCharacter", required: false, completion: { (verifier, key: Character, pos) in + switch key { + case .none_: + break // NOTE - SWIFT doesnt support none + case .mulan: + try ForwardOffset<Attacker>.verify(&verifier, at: pos, of: Attacker.self) + case .rapunzel: + try Rapunzel.verify(&verifier, at: pos, of: Rapunzel.self) + case .belle: + try BookReader.verify(&verifier, at: pos, of: BookReader.self) + case .bookfan: + try BookReader.verify(&verifier, at: pos, of: BookReader.self) + case .other: + try ForwardOffset<String>.verify(&verifier, at: pos, of: String.self) + case .unused: + try ForwardOffset<String>.verify(&verifier, at: pos, of: String.self) + } + }) + try _v.visitUnionVector(unionKey: VTOFFSET.charactersType.p, unionField: VTOFFSET.characters.p, unionKeyName: "charactersType", fieldName: "characters", required: false, completion: { (verifier, key: Character, pos) in + switch key { + case .none_: + break // NOTE - SWIFT doesnt support none + case .mulan: + try ForwardOffset<Attacker>.verify(&verifier, at: pos, of: Attacker.self) + case .rapunzel: + try Rapunzel.verify(&verifier, at: pos, of: Rapunzel.self) + case .belle: + try BookReader.verify(&verifier, at: pos, of: BookReader.self) + case .bookfan: + try BookReader.verify(&verifier, at: pos, of: BookReader.self) + case .other: + try ForwardOffset<String>.verify(&verifier, at: pos, of: String.self) + case .unused: + try ForwardOffset<String>.verify(&verifier, at: pos, of: String.self) + } + }) + _v.finish() + } } public class MovieT: NativeObject { |