@@ -14,6 +14,14 @@ import Foundation
14
14
15
15
// MARK: - ByteTree decoder protocols
16
16
17
+ struct ByteTreeUserInfoKey : Hashable {
18
+ let rawValue : String
19
+
20
+ init ( rawValue: String ) {
21
+ self . rawValue = rawValue
22
+ }
23
+ }
24
+
17
25
/// A type that can be deserialized from ByteTree into a scalar value that
18
26
/// doesn't have any child nodes
19
27
protocol ByteTreeScalarDecodable {
@@ -23,7 +31,8 @@ protocol ByteTreeScalarDecodable {
23
31
/// - pointer: The pointer pointing to the start of the serialized data
24
32
/// - size: The length of the serialized data in bytes
25
33
/// - Returns: The deserialized value
26
- static func read( from pointer: UnsafeRawPointer , size: Int ) -> Self
34
+ static func read( from pointer: UnsafeRawPointer , size: Int ,
35
+ userInfo: [ ByteTreeUserInfoKey : Any ] ) -> Self
27
36
}
28
37
29
38
/// A type that can be deserialized from ByteTree into an object with child
@@ -39,7 +48,8 @@ protocol ByteTreeObjectDecodable {
39
48
/// - numFields: The number of fields that are present in the serialized
40
49
/// object
41
50
/// - Returns: The deserialized object
42
- static func read( from reader: ByteTreeObjectReader , numFields: Int ) -> Self
51
+ static func read( from reader: ByteTreeObjectReader , numFields: Int ,
52
+ userInfo: [ ByteTreeUserInfoKey : Any ] ) -> Self
43
53
}
44
54
45
55
// MARK: - Reader objects
@@ -119,14 +129,30 @@ class ByteTreeObjectReader {
119
129
120
130
/// Reader for reading the ByteTree format into Swift objects
121
131
class ByteTreeReader {
132
+ enum DeserializationError : Error , CustomStringConvertible {
133
+ case versionValidationFailed( ByteTreeReader . ProtocolVersion )
134
+
135
+ public var description : String {
136
+ switch self {
137
+ case . versionValidationFailed( let version) :
138
+ return " The serialized ByteTree version \( version) cannot be parsed " +
139
+ " by this version of swiftSyntax "
140
+ }
141
+ }
142
+ }
143
+
122
144
/// The type as which the protocol version is encoded in ByteTree
123
145
typealias ProtocolVersion = UInt32
124
146
125
147
/// A pointer pointing to the next byte of serialized data to be read
126
148
private var pointer : UnsafeRawPointer
127
149
128
- private init ( pointer: UnsafeRawPointer ) {
150
+ private var userInfo : [ ByteTreeUserInfoKey : Any ]
151
+
152
+ private init ( pointer: UnsafeRawPointer ,
153
+ userInfo: [ ByteTreeUserInfoKey : Any ] ) {
129
154
self . pointer = pointer
155
+ self . userInfo = userInfo
130
156
}
131
157
132
158
// MARK: Public entrance function
@@ -137,22 +163,45 @@ class ByteTreeReader {
137
163
/// - Parameters:
138
164
/// - rootObjectType: The type of the root object in the deserialized tree
139
165
/// - pointer: The memory location at which the serialized data resides
140
- /// - protocolVerisonValidation : A callback to determine if the data can be
166
+ /// - protocolVersionValidation : A callback to determine if the data can be
141
167
/// read, based on the format's protocol version. If the callback
142
- /// returns `false`, `nil` will be returned and reading aborded.
168
+ /// returns `false` an error will be thrown
143
169
/// - Returns: The deserialized tree or `nil` if protocol version validation
144
170
/// failed
145
171
static func read< T: ByteTreeObjectDecodable > (
146
172
_ rootObjectType: T . Type , from pointer: UnsafeRawPointer ,
147
- protocolVerisonValidation: ( ProtocolVersion ) -> Bool
148
- ) -> T ? {
149
- let reader = ByteTreeReader ( pointer: pointer)
150
- if !reader. readAndValidateProtocolVersion ( protocolVerisonValidation) {
151
- return nil
152
- }
173
+ userInfo: [ ByteTreeUserInfoKey : Any ] ,
174
+ protocolVersionValidation: ( ProtocolVersion ) -> Bool
175
+ ) throws -> T {
176
+ let reader = ByteTreeReader ( pointer: pointer, userInfo: userInfo)
177
+ try reader. readAndValidateProtocolVersion ( protocolVersionValidation)
153
178
return reader. read ( rootObjectType)
154
179
}
155
180
181
+ /// Deserialize an object tree from the ByteTree data at the given memory
182
+ /// location.
183
+ ///
184
+ /// - Parameters:
185
+ /// - rootObjectType: The type of the root object in the deserialized tree
186
+ /// - data: The data to deserialize
187
+ /// - protocolVersionValidation: A callback to determine if the data can be
188
+ /// read, based on the format's protocol version. If the callback
189
+ /// returns `false` an error will be thrown
190
+ /// - Returns: The deserialized tree
191
+ static func read< T: ByteTreeObjectDecodable > (
192
+ _ rootObjectType: T . Type , from data: Data ,
193
+ userInfo: [ ByteTreeUserInfoKey : Any ] ,
194
+ protocolVersionValidation versionValidate: ( ProtocolVersion ) -> Bool
195
+ ) throws -> T {
196
+ return try data. withUnsafeBytes { ( pointer: UnsafePointer < UInt8 > ) in
197
+ let rawPointer = UnsafeRawPointer ( pointer)
198
+ return try ByteTreeReader . read ( rootObjectType, from: rawPointer,
199
+ userInfo: userInfo,
200
+ protocolVersionValidation: versionValidate)
201
+ }
202
+ }
203
+
204
+
156
205
// MARK: Internal read functions
157
206
158
207
/// Cast the current pointer location to the given type and advance `pointer`
@@ -181,12 +230,13 @@ class ByteTreeReader {
181
230
/// protocol version can be read
182
231
private func readAndValidateProtocolVersion(
183
232
_ validationCallback: ( ProtocolVersion ) -> Bool
184
- ) -> Bool {
233
+ ) throws {
185
234
let protocolVersion = ProtocolVersion ( littleEndian:
186
235
readRaw ( ProtocolVersion . self) )
187
236
let result = validationCallback ( protocolVersion)
188
- pointer = pointer. advanced ( by: MemoryLayout< ProtocolVersion> . size)
189
- return result
237
+ if !result {
238
+ throw DeserializationError . versionValidationFailed ( protocolVersion)
239
+ }
190
240
}
191
241
192
242
/// Read the next field in the tree as an object of the specified type.
@@ -199,7 +249,7 @@ class ByteTreeReader {
199
249
let numFields = readFieldLength ( )
200
250
let objectReader = ByteTreeObjectReader ( reader: self ,
201
251
numFields: numFields)
202
- return T . read ( from: objectReader, numFields: numFields)
252
+ return T . read ( from: objectReader, numFields: numFields, userInfo : userInfo )
203
253
}
204
254
205
255
/// Read the next field in the tree as a scalar of the specified type.
@@ -213,7 +263,7 @@ class ByteTreeReader {
213
263
defer {
214
264
pointer = pointer. advanced ( by: fieldSize)
215
265
}
216
- return T . read ( from: pointer, size: fieldSize)
266
+ return T . read ( from: pointer, size: fieldSize, userInfo : userInfo )
217
267
}
218
268
219
269
/// Discard the next scalar field, advancing the pointer to the next field
@@ -230,7 +280,9 @@ class ByteTreeReader {
230
280
// Implemenation for reading an integer from memory to be shared between
231
281
// multiple types
232
282
extension ByteTreeScalarDecodable where Self : FixedWidthInteger {
233
- static func read( from pointer: UnsafeRawPointer , size: Int ) -> Self {
283
+ static func read( from pointer: UnsafeRawPointer , size: Int ,
284
+ userInfo: [ ByteTreeUserInfoKey : Any ]
285
+ ) -> Self {
234
286
assert ( size == MemoryLayout< Self> . size)
235
287
return pointer. bindMemory ( to: Self . self, capacity: 1 ) . pointee
236
288
}
@@ -241,7 +293,8 @@ extension UInt16: ByteTreeScalarDecodable {}
241
293
extension UInt32 : ByteTreeScalarDecodable { }
242
294
243
295
extension String : ByteTreeScalarDecodable {
244
- static func read( from pointer: UnsafeRawPointer , size: Int ) -> String {
296
+ static func read( from pointer: UnsafeRawPointer , size: Int ,
297
+ userInfo: [ ByteTreeUserInfoKey : Any ] ) -> String {
245
298
let data = Data ( bytes: pointer, count: size)
246
299
return String ( data: data, encoding: . utf8) !
247
300
}
@@ -250,21 +303,24 @@ extension String: ByteTreeScalarDecodable {
250
303
extension Optional : ByteTreeObjectDecodable
251
304
where
252
305
Wrapped: ByteTreeObjectDecodable {
253
- static func read( from reader: ByteTreeObjectReader , numFields: Int ) ->
254
- Optional < Wrapped > {
306
+ static func read( from reader: ByteTreeObjectReader , numFields: Int ,
307
+ userInfo: [ ByteTreeUserInfoKey : Any ]
308
+ ) -> Optional < Wrapped > {
255
309
if numFields == 0 {
256
310
return nil
257
311
} else {
258
- return Wrapped . read ( from: reader, numFields: numFields)
312
+ return Wrapped . read ( from: reader, numFields: numFields,
313
+ userInfo: userInfo)
259
314
}
260
315
}
261
316
}
262
317
263
318
extension Array : ByteTreeObjectDecodable
264
319
where
265
320
Element: ByteTreeObjectDecodable {
266
- static func read( from reader: ByteTreeObjectReader , numFields: Int ) ->
267
- Array < Element > {
321
+ static func read( from reader: ByteTreeObjectReader , numFields: Int ,
322
+ userInfo: [ ByteTreeUserInfoKey : Any ]
323
+ ) -> Array < Element > {
268
324
return ( 0 ..< numFields) . map {
269
325
return reader. readField ( Element . self, index: $0)
270
326
}
0 commit comments