1 /* 2 * Copyright 2024 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import Foundation 18 19 extension String: Verifiable { 20 21 /// Verifies that the current value is which the bounds of the buffer, and if 22 /// the current `Value` is aligned properly 23 /// - Parameters: 24 /// - verifier: Verifier that hosts the buffer 25 /// - position: Current position within the buffer 26 /// - type: The type of the object to be verified 27 /// - Throws: Errors coming from `inBuffer`, `missingNullTerminator` and `outOfBounds` 28 public static func verify<T>( 29 _ verifier: inout Verifier, 30 at position: Int, 31 of type: T.Type) throws where T: Verifiable 32 { 33 34 let range = try String.verifyRange(&verifier, at: position, of: UInt8.self) 35 /// Safe &+ since we already check for overflow in verify range 36 let stringLen = range.start &+ range.count 37 38 if stringLen >= verifier.capacity { 39 throw FlatbuffersErrors.outOfBounds( 40 position: UInt(clamping: stringLen.magnitude), 41 end: verifier.capacity) 42 } 43 44 let isNullTerminated = verifier._buffer.read( 45 def: UInt8.self, 46 position: stringLen) == 0 47 48 if !verifier._options._ignoreMissingNullTerminators && !isNullTerminated { 49 let str = verifier._buffer.readString(at: range.start, count: range.count) 50 throw FlatbuffersErrors.missingNullTerminator( 51 position: position, 52 str: str) 53 } 54 } 55 } 56 57 extension String: FlatbuffersInitializable { 58 59 /// Initailizes a string from a Flatbuffers ByteBuffer 60 /// - Parameters: 61 /// - bb: ByteBuffer containing the readable string 62 /// - o: Current position 63 public init(_ bb: ByteBuffer, o: Int32) { 64 let v = Int(o) 65 let count = bb.read(def: Int32.self, position: v) 66 self = bb.readString( 67 at: MemoryLayout<Int32>.size + v, 68 count: Int(count)) ?? "" 69 } 70 } 71 72 extension String: ObjectAPIPacker { 73 74 public static func pack( 75 _ builder: inout FlatBufferBuilder, 76 obj: inout String?) -> Offset 77 { 78 guard var obj = obj else { return Offset() } 79 return pack(&builder, obj: &obj) 80 } 81 82 public static func pack( 83 _ builder: inout FlatBufferBuilder, 84 obj: inout String) -> Offset 85 { 86 builder.create(string: obj) 87 } 88 unpacknull89 public mutating func unpack() -> String { 90 self 91 } 92 93 } 94 95 extension String: NativeObject { 96 serialize<T: ObjectAPIPacker>null97 public func serialize<T: ObjectAPIPacker>(type: T.Type) -> ByteBuffer 98 where T.T == Self 99 { 100 fatalError("serialize should never be called from string directly") 101 } 102 103 public func serialize<T: ObjectAPIPacker>( 104 builder: inout FlatBufferBuilder, 105 type: T.Type) -> ByteBuffer where T.T == Self 106 { 107 fatalError("serialize should never be called from string directly") 108 } 109 } 110