• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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