Skip to content

Commit 3060324

Browse files
committed
Added Encoder and Decoder
1 parent 6b09b8c commit 3060324

File tree

2 files changed

+206
-0
lines changed

2 files changed

+206
-0
lines changed

Sources/Decoder.swift

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//
2+
// Decoder.swift
3+
// TLVCoding
4+
//
5+
// Created by Alsey Coleman Miller on 3/8/18.
6+
// Copyright © 2018 PureSwift. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct TLVDecoder {
12+
13+
public static func decode(data: Data, from types: [TLVDecodable.Type]) throws -> [TLVDecodable] {
14+
15+
var offset = 0
16+
17+
var decodables = [TLVDecodable]()
18+
19+
while offset < data.count {
20+
21+
// validate size
22+
guard data.count >= 3
23+
else { throw DecodingError.invalidSize(data.count, context: DecodingContext(offset: offset)) }
24+
25+
// get type
26+
let typeByte = data[offset] // 0
27+
offset += 1
28+
29+
guard let type = types.first(where: { $0.typeCode.rawValue == typeByte })
30+
else { throw DecodingError.invalidType(typeByte, context: DecodingContext(offset: offset)) }
31+
32+
let length = Int(data[offset]) // 1
33+
offset += 1
34+
35+
// get value
36+
let valueData = Data(data[offset ..< offset + length])
37+
38+
guard let value = type.init(valueData: valueData)
39+
else { throw DecodingError.invalidValue(valueData, context: DecodingContext(offset: offset)) }
40+
41+
// append result
42+
decodables.append(value)
43+
44+
// adjust offset for next value
45+
offset += length
46+
}
47+
48+
return decodables
49+
}
50+
}
51+
52+
// MARK: - Supporting Types
53+
54+
public extension TLVDecoder {
55+
56+
public struct DecodingContext {
57+
58+
public let offset: Int
59+
}
60+
61+
public enum DecodingError: Swift.Error {
62+
63+
case invalidSize(Int, context: DecodingContext)
64+
case invalidType(UInt8, context: DecodingContext)
65+
case invalidValue(Data, context: DecodingContext)
66+
case decodableMismatch([TLVDecodable])
67+
}
68+
}
69+
70+
71+
// MARK: - Coder Convenience Extensions
72+
73+
public extension TLVDecoder {
74+
75+
public static func decode <Decodable: TLVDecodable> (data: Data, from type: Decodable.Type) throws -> Decodable {
76+
77+
let decodables = try decode(data: data, from: [type])
78+
79+
guard decodables.count == 1,
80+
let decodable = decodables[0] as? Decodable
81+
else { throw DecodingError.decodableMismatch(decodables) }
82+
83+
return decodable
84+
}
85+
86+
public static func decode <T1: TLVDecodable, T2: TLVDecodable>
87+
(data: Data, from types: (T1.Type, T2.Type)) throws -> (T1, T2) {
88+
89+
let decodables = try decode(data: data, from: [types.0, types.1])
90+
91+
guard decodables.count == 2,
92+
let decodable1 = decodables[0] as? T1,
93+
let decodable2 = decodables[1] as? T2
94+
else { throw DecodingError.decodableMismatch(decodables) }
95+
96+
return (decodable1, decodable2)
97+
}
98+
99+
public static func decode <T1: TLVDecodable, T2: TLVDecodable, T3: TLVDecodable>
100+
(data: Data, from types: (T1.Type, T2.Type, T3.Type)) throws -> (T1, T2, T3) {
101+
102+
let decodables = try decode(data: data, from: [types.0, types.1, types.2])
103+
104+
guard decodables.count == 3,
105+
let decodable1 = decodables[0] as? T1,
106+
let decodable2 = decodables[1] as? T2,
107+
let decodable3 = decodables[2] as? T3
108+
else { throw DecodingError.decodableMismatch(decodables) }
109+
110+
return (decodable1, decodable2, decodable3)
111+
}
112+
113+
public static func decode <T1: TLVDecodable, T2: TLVDecodable, T3: TLVDecodable, T4: TLVDecodable>
114+
(data: Data, from types: (T1.Type, T2.Type, T3.Type, T4.Type)) throws -> (T1, T2, T3, T4) {
115+
116+
let decodables = try decode(data: data, from: [types.0, types.1, types.2, types.3])
117+
118+
guard decodables.count == 4,
119+
let decodable1 = decodables[0] as? T1,
120+
let decodable2 = decodables[1] as? T2,
121+
let decodable3 = decodables[2] as? T3,
122+
let decodable4 = decodables[3] as? T4
123+
else { throw DecodingError.decodableMismatch(decodables) }
124+
125+
return (decodable1, decodable2, decodable3, decodable4)
126+
}
127+
128+
public static func decode <T1: TLVDecodable, T2: TLVDecodable, T3: TLVDecodable, T4: TLVDecodable, T5: TLVDecodable>
129+
(data: Data, from types: (T1.Type, T2.Type, T3.Type, T4.Type, T5.Type)) throws -> (T1, T2, T3, T4, T5) {
130+
131+
let decodables = try decode(data: data, from: [types.0, types.1, types.2, types.3, types.4])
132+
133+
guard decodables.count == 5,
134+
let decodable1 = decodables[0] as? T1,
135+
let decodable2 = decodables[1] as? T2,
136+
let decodable3 = decodables[2] as? T3,
137+
let decodable4 = decodables[3] as? T4,
138+
let decodable5 = decodables[4] as? T5
139+
else { throw DecodingError.decodableMismatch(decodables) }
140+
141+
return (decodable1, decodable2, decodable3, decodable4, decodable5)
142+
}
143+
144+
public static func decode <T1: TLVDecodable, T2: TLVDecodable, T3: TLVDecodable, T4: TLVDecodable, T5: TLVDecodable, T6: TLVDecodable>
145+
(data: Data, from types: (T1.Type, T2.Type, T3.Type, T4.Type, T5.Type, T6.Type)) throws -> (T1, T2, T3, T4, T5, T6) {
146+
147+
let decodables = try decode(data: data, from: [types.0, types.1, types.2, types.3, types.4, types.5])
148+
149+
guard decodables.count == 6,
150+
let decodable1 = decodables[0] as? T1,
151+
let decodable2 = decodables[1] as? T2,
152+
let decodable3 = decodables[2] as? T3,
153+
let decodable4 = decodables[3] as? T4,
154+
let decodable5 = decodables[4] as? T5,
155+
let decodable6 = decodables[5] as? T6
156+
else { throw DecodingError.decodableMismatch(decodables) }
157+
158+
return (decodable1, decodable2, decodable3, decodable4, decodable5, decodable6)
159+
}
160+
161+
public static func decodeOptional <T1: TLVDecodable, T2: TLVDecodable, T3: TLVDecodable, T4: TLVDecodable, T5: TLVDecodable, T6: TLVDecodable>
162+
(data: Data, from types: (T1.Type, T2.Type, T3.Type, T4.Type, T5.Type, T6.Type)) throws -> (T1?, T2?, T3?, T4?, T5?, T6?) {
163+
164+
let decodables = try decode(data: data, from: [types.0, types.1, types.2, types.3, types.4, types.5])
165+
.sorted(by: { type(of: $0.0).typeCode.rawValue < type(of: $0.1).typeCode.rawValue })
166+
167+
return (decodables.count > 0 ? decodables[0] as? T1 : nil,
168+
decodables.count > 1 ? decodables[1] as? T2 : nil,
169+
decodables.count > 2 ? decodables[2] as? T3 : nil,
170+
decodables.count > 3 ? decodables[3] as? T4 : nil,
171+
decodables.count > 4 ? decodables[4] as? T5 : nil,
172+
decodables.count > 5 ? decodables[5] as? T6 : nil)
173+
}
174+
}

Sources/Encoder.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//
2+
// Encoder.swift
3+
// TLVCoding
4+
//
5+
// Created by Alsey Coleman Miller on 3/8/18.
6+
// Copyright © 2018 PureSwift. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct TLVEncoder {
12+
13+
public static func encode(_ encodables: [TLVEncodable]) -> Data {
14+
15+
var data = Data()
16+
17+
for encodable in encodables {
18+
19+
let type = type(of: encodable).typeCode.rawValue
20+
21+
let valueData = encodable.valueData
22+
23+
assert(valueData.isEmpty == false)
24+
25+
let length = UInt8(valueData.count)
26+
27+
data += [type, length] + valueData
28+
}
29+
30+
return data
31+
}
32+
}

0 commit comments

Comments
 (0)