@@ -13,148 +13,122 @@ public final class PostgresDataEncoder {
13
13
if let custom = value as? PostgresDataConvertible , let data = custom. postgresData {
14
14
return data
15
15
} else {
16
- let context = _Context ( )
17
- try value. encode ( to: _Encoder ( context: context) )
18
- if let value = context. value {
19
- return value
20
- } else if let array = context. array {
21
- let elementType = array. first? . type ?? . jsonb
22
- assert ( array. filter { $0. type != elementType } . isEmpty, " Array does not contain all: \( elementType) " )
23
- return PostgresData ( array: array, elementType: elementType)
24
- } else {
25
- return try PostgresData ( jsonb: self . json. encode ( _Wrapper ( value) ) )
16
+ let encoder = _Encoder ( parent: self )
17
+ do {
18
+ try value. encode ( to: encoder)
19
+ switch encoder. value {
20
+ case . invalid: throw _Encoder. AssociativeValueSentinel ( ) // this is usually "nothing was encoded at all", not an associative value, but the desired action is the same
21
+ case . scalar( let scalar) : return scalar
22
+ case . indexed( let indexed) :
23
+ let elementType = indexed. contents. first? . type ?? . jsonb
24
+ assert ( indexed. contents. allSatisfy { $0. type == elementType } , " Type \( type ( of: value) ) was encoded as a heterogenous array; this is unsupported. " )
25
+ return PostgresData ( array: indexed. contents, elementType: elementType)
26
+ }
27
+ } catch is _Encoder . AssociativeValueSentinel {
28
+ #if swift(<5.7)
29
+ struct _Wrapper : Encodable {
30
+ let encodable : Encodable
31
+ init ( _ encodable: Encodable ) { self . encodable = encodable }
32
+ func encode( to encoder: Encoder ) throws { try self . encodable. encode ( to: encoder) }
33
+ }
34
+ return try PostgresData ( jsonb: self . json. encode ( _Wrapper ( value) ) ) // Swift <5.7 will complain that "Encodable does not conform to Encodable" without the wrapper
35
+ #else
36
+ return try PostgresData ( jsonb: self . json. encode ( value) )
37
+ #endif
26
38
}
27
39
}
28
40
}
29
41
30
- final class _Context {
31
- var value : PostgresData ?
32
- var array : [ PostgresData ] ?
33
-
34
- init ( ) { }
35
- }
36
-
37
- struct _Encoder : Encoder {
38
- var userInfo : [ CodingUserInfoKey : Any ] {
39
- [ : ]
40
- }
41
- var codingPath : [ CodingKey ] {
42
- [ ]
42
+ private final class _Encoder : Encoder {
43
+ struct AssociativeValueSentinel : Error { }
44
+ enum Value {
45
+ final class RefArray < T> { var contents : [ T ] = [ ] }
46
+ case invalid, indexed( RefArray < PostgresData > ) , scalar( PostgresData )
47
+
48
+ var isValid : Bool { if case . invalid = self { return false } ; return true }
49
+ mutating func requestIndexed( for encoder: _Encoder ) {
50
+ switch self {
51
+ case . scalar( _) : preconditionFailure ( " Invalid request for both single-value and unkeyed containers from the same encoder. " )
52
+ case . invalid: self = . indexed( . init( ) ) // no existing value, make new array
53
+ case . indexed( _) : break // existing array, adopt it for appending (support for superEncoder())
54
+ }
55
+ }
56
+ mutating func storeScalar( _ scalar: PostgresData ) {
57
+ switch self {
58
+ case . indexed( _) , . scalar( _) : preconditionFailure ( " Invalid request for multiple containers from the same encoder. " )
59
+ case . invalid: self = . scalar( scalar) // no existing value, store the incoming
60
+ }
61
+ }
62
+ var indexedCount : Int {
63
+ switch self {
64
+ case . invalid, . scalar( _) : preconditionFailure ( " Internal error in encoder (requested indexed count from non-indexed state) " )
65
+ case . indexed( let ref) : return ref. contents. count
66
+ }
67
+ }
68
+ mutating func addToIndexed( _ scalar: PostgresData ) {
69
+ switch self {
70
+ case . invalid, . scalar( _) : preconditionFailure ( " Internal error in encoder (attempted store to indexed in non-indexed state) " )
71
+ case . indexed( let ref) : ref. contents. append ( scalar)
72
+ }
73
+ }
43
74
}
44
- let context : _Context
45
-
46
- func container< Key> ( keyedBy type: Key . Type ) -> KeyedEncodingContainer < Key >
47
- where Key : CodingKey
48
- {
49
- . init( _KeyedEncoder < Key > ( ) )
75
+
76
+ var userInfo : [ CodingUserInfoKey : Any ] { [ : ] } ; var codingPath : [ CodingKey ] { [ ] }
77
+ var parent : PostgresDataEncoder , value : Value
78
+
79
+ init ( parent: PostgresDataEncoder , value: Value = . invalid) { ( self . parent, self . value) = ( parent, value) }
80
+ func container< K: CodingKey > ( keyedBy: K . Type ) -> KeyedEncodingContainer < K > {
81
+ precondition ( !self . value. isValid, " Requested multiple containers from the same encoder. " )
82
+ return . init( _FailingKeyedContainer ( ) )
50
83
}
51
-
52
84
func unkeyedContainer( ) -> UnkeyedEncodingContainer {
53
- self . context . array = [ ]
54
- return _UnkeyedEncoder ( context : self . context )
85
+ self . value . requestIndexed ( for : self )
86
+ return _UnkeyedValueContainer ( encoder : self )
55
87
}
56
-
57
88
func singleValueContainer( ) -> SingleValueEncodingContainer {
58
- _ValueEncoder ( context: self . context)
59
- }
60
- }
61
-
62
- struct _UnkeyedEncoder : UnkeyedEncodingContainer {
63
- var codingPath : [ CodingKey ] {
64
- [ ]
65
- }
66
- var count : Int {
67
- 0
68
- }
69
-
70
- var context : _Context
71
-
72
- func encodeNil( ) throws {
73
- self . context. array!. append ( . null)
74
- }
75
-
76
- func encode< T> ( _ value: T ) throws where T : Encodable {
77
- try self . context. array!. append ( PostgresDataEncoder ( ) . encode ( value) )
78
- }
79
-
80
- func nestedContainer< NestedKey> (
81
- keyedBy keyType: NestedKey . Type
82
- ) -> KeyedEncodingContainer < NestedKey >
83
- where NestedKey : CodingKey
84
- {
85
- fatalError ( )
86
- }
87
-
88
- func nestedUnkeyedContainer( ) -> UnkeyedEncodingContainer {
89
- fatalError ( )
90
- }
91
-
92
- func superEncoder( ) -> Encoder {
93
- fatalError ( )
94
- }
95
- }
96
-
97
- struct _KeyedEncoder < Key> : KeyedEncodingContainerProtocol
98
- where Key: CodingKey
99
- {
100
- var codingPath : [ CodingKey ] {
101
- [ ]
102
- }
103
-
104
- func encodeNil( forKey key: Key ) throws {
105
- // do nothing
106
- }
107
-
108
- func encode< T> ( _ value: T , forKey key: Key ) throws where T : Encodable {
109
- // do nothing
110
- }
111
-
112
- func nestedContainer< NestedKey> (
113
- keyedBy keyType: NestedKey . Type ,
114
- forKey key: Key
115
- ) -> KeyedEncodingContainer < NestedKey >
116
- where NestedKey : CodingKey
117
- {
118
- fatalError ( )
119
- }
120
-
121
- func nestedUnkeyedContainer( forKey key: Key ) -> UnkeyedEncodingContainer {
122
-
123
- fatalError ( )
124
- }
125
-
126
- func superEncoder( ) -> Encoder {
127
- fatalError ( )
128
- }
129
-
130
- func superEncoder( forKey key: Key ) -> Encoder {
131
- fatalError ( )
132
- }
133
- }
134
-
135
-
136
- struct _ValueEncoder : SingleValueEncodingContainer {
137
- var codingPath : [ CodingKey ] {
138
- [ ]
139
- }
140
- let context : _Context
141
-
142
- func encodeNil( ) throws {
143
- self . context. value = . null
144
- }
145
-
146
- func encode< T> ( _ value: T ) throws where T : Encodable {
147
- self . context. value = try PostgresDataEncoder ( ) . encode ( value)
148
- }
149
- }
150
-
151
- struct _Wrapper : Encodable {
152
- let encodable : Encodable
153
- init ( _ encodable: Encodable ) {
154
- self . encodable = encodable
155
- }
156
- func encode( to encoder: Encoder ) throws {
157
- try self . encodable. encode ( to: encoder)
89
+ precondition ( !self . value. isValid, " Requested multiple containers from the same encoder. " )
90
+ return _SingleValueContainer ( encoder: self )
91
+ }
92
+
93
+ struct _UnkeyedValueContainer : UnkeyedEncodingContainer {
94
+ let encoder : _Encoder ; var codingPath : [ CodingKey ] { self . encoder. codingPath }
95
+ var count : Int { self . encoder. value. indexedCount }
96
+ mutating func encodeNil( ) throws { self . encoder. value. addToIndexed ( . null) }
97
+ mutating func encode< T: Encodable > ( _ value: T ) throws { self . encoder. value. addToIndexed ( try self . encoder. parent. encode ( value) ) }
98
+ mutating func nestedContainer< K: CodingKey > ( keyedBy: K . Type ) -> KeyedEncodingContainer < K > { self . superEncoder ( ) . container ( keyedBy: K . self) }
99
+ mutating func nestedUnkeyedContainer( ) -> UnkeyedEncodingContainer { self . superEncoder ( ) . unkeyedContainer ( ) }
100
+ mutating func superEncoder( ) -> Encoder { _Encoder ( parent: self . encoder. parent, value: self . encoder. value) } // NOT the same as self.encoder
101
+ }
102
+
103
+ struct _SingleValueContainer : SingleValueEncodingContainer {
104
+ let encoder : _Encoder ; var codingPath : [ CodingKey ] { self . encoder. codingPath }
105
+ func encodeNil( ) throws { self . encoder. value. storeScalar ( . null) }
106
+ func encode< T: Encodable > ( _ value: T ) throws { self . encoder. value. storeScalar ( try self . encoder. parent. encode ( value) ) }
107
+ }
108
+
109
+ /// This pair of types is only necessary because we can't directly throw an error from various Encoder and
110
+ /// encoding container methods. We define duplicate types rather than the old implementation's use of a
111
+ /// no-action keyed container because it can save a significant amount of time otherwise spent uselessly calling
112
+ /// nested methods in some cases.
113
+ struct _TaintedEncoder : Encoder , UnkeyedEncodingContainer , SingleValueEncodingContainer {
114
+ var userInfo : [ CodingUserInfoKey : Any ] { [ : ] } ; var codingPath : [ CodingKey ] { [ ] } ; var count : Int { 0 }
115
+ func container< K: CodingKey > ( keyedBy: K . Type ) -> KeyedEncodingContainer < K > { . init( _FailingKeyedContainer ( ) ) }
116
+ func nestedContainer< K: CodingKey > ( keyedBy: K . Type ) -> KeyedEncodingContainer < K > { . init( _FailingKeyedContainer ( ) ) }
117
+ func unkeyedContainer( ) -> UnkeyedEncodingContainer { self }
118
+ func nestedUnkeyedContainer( ) -> UnkeyedEncodingContainer { self }
119
+ func singleValueContainer( ) -> SingleValueEncodingContainer { self }
120
+ func superEncoder( ) -> Encoder { self }
121
+ func encodeNil( ) throws { throw AssociativeValueSentinel ( ) }
122
+ func encode< T: Encodable > ( _: T ) throws { throw AssociativeValueSentinel ( ) }
123
+ }
124
+ struct _FailingKeyedContainer < K: CodingKey > : KeyedEncodingContainerProtocol {
125
+ var codingPath : [ CodingKey ] { [ ] }
126
+ func encodeNil( forKey: K ) throws { throw AssociativeValueSentinel ( ) }
127
+ func encode< T: Encodable > ( _: T , forKey: K ) throws { throw AssociativeValueSentinel ( ) }
128
+ func nestedContainer< NK: CodingKey > ( keyedBy: NK . Type , forKey: K ) -> KeyedEncodingContainer < NK > { . init( _FailingKeyedContainer < NK > ( ) ) }
129
+ func nestedUnkeyedContainer( forKey: K ) -> UnkeyedEncodingContainer { _TaintedEncoder ( ) }
130
+ func superEncoder( ) -> Encoder { _TaintedEncoder ( ) }
131
+ func superEncoder( forKey: K ) -> Encoder { _TaintedEncoder ( ) }
158
132
}
159
133
}
160
134
}
0 commit comments