1
+ import COperatingSystem
2
+ import Foundation
3
+
1
4
/// Reference wrapper for `PostgreSQLData` being mutated
2
5
/// by the PostgreSQL data coders.
3
6
final class PartialPostgreSQLData {
4
7
/// The partial data.
5
- var data : PostgreSQLData
8
+ var data : [ String : PostgreSQLData ]
6
9
7
10
/// Creates a new `PartialPostgreSQLData`.
8
- init ( data: PostgreSQLData ) {
11
+ init ( data: [ String : PostgreSQLData ] ) {
9
12
self . data = data
10
13
}
11
14
12
15
/// Sets the `PostgreSQLData` at supplied coding path.
13
16
func set( _ data: PostgreSQLData , at path: [ CodingKey ] ) {
14
- set ( & self . data, to: data, at: path)
17
+ guard path. count == 1 else {
18
+ fatalError ( )
19
+ }
20
+ self . data [ path [ 0 ] . stringValue] = data
21
+ // set(&self.data, to: data, at: path)
15
22
}
16
23
17
24
/// Returns the value, if one at from the given path.
18
25
func get( at path: [ CodingKey ] ) -> PostgreSQLData ? {
19
- var child = data
20
- for seg in path {
21
- switch child {
22
- case . array( let arr) :
23
- guard let index = seg. intValue, arr. count > index else {
24
- return nil
25
- }
26
- child = arr [ index]
27
- case . dictionary( let dict) :
28
- guard let value = dict [ seg. stringValue] else {
29
- return nil
30
- }
31
- child = value
32
- default :
33
- return nil
34
- }
35
- }
36
- return child
37
- }
38
-
39
- /// Sets the mutable `PostgreSQLData` to supplied data at coding path.
40
- private func set( _ context: inout PostgreSQLData , to value: PostgreSQLData , at path: [ CodingKey ] ) {
41
- guard path. count >= 1 else {
42
- context = value
43
- return
44
- }
45
-
46
- let end = path [ 0 ]
47
-
48
- var child : PostgreSQLData ?
49
- switch path. count {
50
- case 1 :
51
- child = value
52
- case 2 ... :
53
- if let index = end. intValue {
54
- let array = context. array ?? [ ]
55
- if array. count > index {
56
- child = array [ index]
57
- } else {
58
- child = PostgreSQLData . array ( [ ] )
59
- }
60
- set ( & child!, to: value, at: Array ( path [ 1 ... ] ) )
61
- } else {
62
- child = context. dictionary ? [ end. stringValue] ?? PostgreSQLData . dictionary ( [ : ] )
63
- set ( & child!, to: value, at: Array ( path [ 1 ... ] ) )
64
- }
65
- default : break
66
- }
67
-
68
- if let index = end. intValue {
69
- if case . array( var arr) = context {
70
- if arr. count > index {
71
- arr [ index] = child ?? . null
72
- } else {
73
- arr. append ( child ?? . null)
74
- }
75
- context = . array( arr)
76
- } else if let child = child {
77
- context = . array( [ child] )
78
- }
79
- } else {
80
- if case . dictionary( var dict) = context {
81
- dict [ end. stringValue] = child
82
- context = . dictionary( dict)
83
- } else if let child = child {
84
- context = . dictionary( [
85
- end. stringValue: child
86
- ] )
87
- }
26
+ guard path. count == 1 else {
27
+ fatalError ( )
88
28
}
29
+ return self . data [ path [ 0 ] . stringValue]
30
+ // var child = data
31
+ // for seg in path {
32
+ // switch child {
33
+ // case .array(let arr):
34
+ // guard let index = seg.intValue, arr.count > index else {
35
+ // return nil
36
+ // }
37
+ // child = arr[index]
38
+ // case .dictionary(let dict):
39
+ // guard let value = dict[seg.stringValue] else {
40
+ // return nil
41
+ // }
42
+ // child = value
43
+ // default:
44
+ // return nil
45
+ // }
46
+ // }
47
+ // return child
89
48
}
49
+
50
+ // /// Sets the mutable `PostgreSQLData` to supplied data at coding path.
51
+ // private func set(_ context: inout PostgreSQLData, to value: PostgreSQLData, at path: [CodingKey]) {
52
+ // guard path.count >= 1 else {
53
+ // context = value
54
+ // return
55
+ // }
56
+ //
57
+ // let end = path[0]
58
+ //
59
+ // var child: PostgreSQLData?
60
+ // switch path.count {
61
+ // case 1:
62
+ // child = value
63
+ // case 2...:
64
+ // if let index = end.intValue {
65
+ // let array = context.array ?? []
66
+ // if array.count > index {
67
+ // child = array[index]
68
+ // } else {
69
+ // child = PostgreSQLData.array([])
70
+ // }
71
+ // set(&child!, to: value, at: Array(path[1...]))
72
+ // } else {
73
+ // child = context.dictionary?[end.stringValue] ?? PostgreSQLData.dictionary([:])
74
+ // set(&child!, to: value, at: Array(path[1...]))
75
+ // }
76
+ // default: break
77
+ // }
78
+ //
79
+ // if let index = end.intValue {
80
+ // if case .array(var arr) = context {
81
+ // if arr.count > index {
82
+ // arr[index] = child ?? .null
83
+ // } else {
84
+ // arr.append(child ?? .null)
85
+ // }
86
+ // context = .array(arr)
87
+ // } else if let child = child {
88
+ // context = .array([child])
89
+ // }
90
+ // } else {
91
+ // if case .dictionary(var dict) = context {
92
+ // dict[end.stringValue] = child
93
+ // context = .dictionary(dict)
94
+ // } else if let child = child {
95
+ // context = .dictionary([
96
+ // end.stringValue: child
97
+ // ])
98
+ // }
99
+ // }
100
+ // }
90
101
}
91
102
92
103
93
104
/// MARK: Encoding Convenience
94
105
106
+ extension FixedWidthInteger {
107
+ /// Big-endian bytes for this integer.
108
+ fileprivate var data : Data {
109
+ var bytes = [ UInt8] ( repeating: 0 , count: Self . bitWidth / 8 )
110
+ var intNetwork = bigEndian
111
+ memcpy ( & bytes, & intNetwork, bytes. count)
112
+ return Data ( bytes)
113
+ }
114
+ }
115
+
116
+ extension FloatingPoint {
117
+ /// Big-endian bytes for this floating-point number.
118
+ fileprivate var data : Data {
119
+ var bytes = [ UInt8] ( repeating: 0 , count: MemoryLayout< Self> . size)
120
+ var copy = self
121
+ memcpy ( & bytes, & copy, bytes. count)
122
+ return Data ( bytes. reversed ( ) )
123
+ }
124
+ }
125
+
126
+ extension Data {
127
+ /// Converts this data to a floating-point number.
128
+ fileprivate func makeFloatingPoint< F> ( _ type: F . Type = F . self) -> F where F: FloatingPoint {
129
+ return Data ( reversed ( ) ) . unsafeCast ( )
130
+ }
131
+
132
+ /// Converts this data to a fixed-width integer.
133
+ fileprivate func makeFixedWidthInteger< I> ( _ type: I . Type = I . self) -> I where I: FixedWidthInteger {
134
+ return unsafeCast ( to: I . self) . bigEndian
135
+ }
136
+
137
+ fileprivate func unsafeCast< T> ( to type: T . Type = T . self) -> T {
138
+ return withUnsafeBytes { ( pointer: UnsafePointer < T > ) -> T in
139
+ return pointer. pointee
140
+ }
141
+ }
142
+
143
+ /// Convert the row's data into a string, throwing if invalid encoding.
144
+ fileprivate func makeString( encoding: String . Encoding = . utf8) throws -> String {
145
+ guard let string = String ( data: self , encoding: encoding) else {
146
+ throw PostgreSQLError ( identifier: " utf8String " , reason: " Unexpected non-UTF8 string. " )
147
+ }
148
+
149
+ return string
150
+ }
151
+ }
152
+
95
153
extension PartialPostgreSQLData {
96
154
/// Sets a generic fixed width integer to the supplied path.
97
155
func setFixedWidthInteger< U> ( _ value: U , at path: [ CodingKey ] ) throws
98
156
where U: FixedWidthInteger
99
157
{
158
+ // switch U.bitWidth {
159
+ // case 8: try set(.int8(safeCast(value, at: path)), at: path)
160
+ // case 16: try set(.int16(safeCast(value, at: path)), at: path)
161
+ // case 32: try set(.int32(safeCast(value, at: path)), at: path)
162
+ // case 64: try set(.int64(safeCast(value, at: path)), at: path)
163
+ // default: throw DecodingError.typeMismatch(U.self, .init(codingPath: path, debugDescription: "Integer bit width not supported: \(U.bitWidth)"))
164
+ // }
165
+ let type : PostgreSQLDataType
100
166
switch U . bitWidth {
101
- case 8 : try set ( . int8 ( safeCast ( value , at : path ) ) , at : path )
102
- case 16 : try set ( . int16 ( safeCast ( value , at : path ) ) , at : path )
103
- case 32 : try set ( . int32 ( safeCast ( value , at : path ) ) , at : path )
104
- case 64 : try set ( . int64 ( safeCast ( value , at : path ) ) , at : path )
167
+ case 8 : type = . char
168
+ case 16 : type = . int2
169
+ case 32 : type = . int4
170
+ case 64 : type = . int8
105
171
default : throw DecodingError . typeMismatch ( U . self, . init( codingPath: path, debugDescription: " Integer bit width not supported: \( U . bitWidth) " ) )
106
172
}
173
+ set ( . init( type: type, data: value. data) , at: path)
107
174
}
108
175
109
176
/// Sets an encodable value at the supplied path.
@@ -142,14 +209,18 @@ extension PartialPostgreSQLData {
142
209
}
143
210
144
211
/// Gets a `Float` from the supplied path or throws a decoding error.
145
- func requireFixedWidthItenger < I> ( _ type: I . Type = I . self, at path: [ CodingKey ] ) throws -> I
212
+ func requireFixedWidthInteger < I> ( _ type: I . Type = I . self, at path: [ CodingKey ] ) throws -> I
146
213
where I: FixedWidthInteger
147
214
{
148
- switch try requireGet ( I . self, at: path) {
149
- case . int8( let value) : return try safeCast ( value, at: path)
150
- case . int16( let value) : return try safeCast ( value, at: path)
151
- case . int32( let value) : return try safeCast ( value, at: path)
152
- case . int64( let value) : return try safeCast ( value, at: path)
215
+ let data = try requireGet ( I . self, at: path)
216
+ guard let value = data. data else {
217
+ fatalError ( )
218
+ }
219
+ switch data. type {
220
+ case . char: return try safeCast ( value. makeFixedWidthInteger ( Int8 . self) , at: path)
221
+ case . int2: return try safeCast ( value. makeFixedWidthInteger ( Int16 . self) , at: path)
222
+ case . int4: return try safeCast ( value. makeFixedWidthInteger ( Int32 . self) , at: path)
223
+ case . int8: return try safeCast ( value. makeFixedWidthInteger ( Int64 . self) , at: path)
153
224
default : throw DecodingError . typeMismatch ( type, . init( codingPath: path, debugDescription: " " ) )
154
225
}
155
226
}
@@ -176,29 +247,41 @@ extension PartialPostgreSQLData {
176
247
func requireFloatingPoint< F> ( _ type: F . Type = F . self, at path: [ CodingKey ] ) throws -> F
177
248
where F: BinaryFloatingPoint
178
249
{
179
- switch try requireGet ( F . self, at: path) {
180
- case . int8( let value) : return F ( value)
181
- case . int16( let value) : return F ( value)
182
- case . int32( let value) : return F ( value)
183
- case . int64( let value) : return F ( value)
184
- case . float( let value) : return F ( value)
185
- case . double( let value) : return F ( value)
250
+ let data = try requireGet ( F . self, at: path)
251
+ guard let value = data. data else {
252
+ fatalError ( )
253
+ }
254
+ switch data. type {
255
+ case . char: return F ( value. makeFixedWidthInteger ( Int8 . self) )
256
+ case . int2: return F ( value. makeFixedWidthInteger ( Int16 . self) )
257
+ case . int4: return F ( value. makeFixedWidthInteger ( Int32 . self) )
258
+ case . int8: return F ( value. makeFixedWidthInteger ( Int64 . self) )
259
+ case . float4: return F ( value. makeFloatingPoint ( Float . self) )
260
+ case . float8: return F ( value. makeFloatingPoint ( Double . self) )
186
261
default : throw DecodingError . typeMismatch ( F . self, . init( codingPath: path, debugDescription: " " ) )
187
262
}
188
263
}
189
264
190
265
/// Gets a `String` from the supplied path or throws a decoding error.
191
266
func requireString( at path: [ CodingKey ] ) throws -> String {
192
- switch try requireGet ( String . self, at: path) {
193
- case . string( let value) : return value
267
+ let data = try requireGet ( String . self, at: path)
268
+ guard let value = data. data else {
269
+ fatalError ( )
270
+ }
271
+ switch data. type {
272
+ case . text: return String ( data: value, encoding: . utf8) !! " Non-utf8 "
194
273
default : throw DecodingError . typeMismatch ( String . self, . init( codingPath: path, debugDescription: " " ) )
195
274
}
196
275
}
197
276
198
277
/// Gets a `Bool` from the supplied path or throws a decoding error.
199
278
func requireBool( at path: [ CodingKey ] ) throws -> Bool {
200
- switch try requireGet ( Bool . self, at: path) {
201
- case . bool( let value) : return value
279
+ let data = try requireGet ( String . self, at: path)
280
+ guard let value = data. data else {
281
+ fatalError ( )
282
+ }
283
+ switch data. type {
284
+ case . char: return value. makeFixedWidthInteger ( Int8 . self) == 1
202
285
default : throw DecodingError . typeMismatch ( Bool . self, . init( codingPath: path, debugDescription: " " ) )
203
286
}
204
287
}
0 commit comments