@@ -19,23 +19,54 @@ import ReflectionInternal
1919enum PredicateCodableError : Error , CustomStringConvertible {
2020 case disallowedType( typeName: String , path: String )
2121 case disallowedIdentifier( String , path: String )
22- case reconstructionFailure( PartialType , [ Type ] )
22+ case reconstructionFailure( PartialType , [ GenericArgument ] )
2323 case variadicType( typeName: String , path: String )
2424
2525 var description : String {
2626 switch self {
2727 case . disallowedType( let typeName, let path) : return " The ' \( typeName) ' type is not in the provided allowlist (required by \( path) ) "
2828 case . disallowedIdentifier( let id, let path) : return " The ' \( id) ' identifier is not in the provided allowlist (required by \( path) ) "
29- case . reconstructionFailure( let partial, let args) : return " Reconstruction of ' \( partial. name) ' with the arguments \( args. map ( \. swiftType) ) failed "
29+ case . reconstructionFailure( let partial, let args) :
30+ let types = args. map {
31+ switch $0 {
32+ case . type( let type) : _typeName ( type. swiftType)
33+ case . pack( let types) : " Pack{ \( types. map ( { _typeName ( $0. swiftType) } ) . joined ( separator: " , " ) ) } "
34+ }
35+ }
36+ return " Reconstruction of ' \( partial. name) ' with the arguments [ \( types. joined ( separator: " , " ) ) ] failed "
3037 case . variadicType( let typeName, let path) : return " The ' \( typeName) ' type is not allowed because it contains type pack parameters (required by \( path) ) "
3138 }
3239 }
3340}
3441
3542@available ( FoundationPredicate 0 . 1 , * )
3643private struct ExpressionStructure : Codable {
37- let identifier : String
38- let args : [ ExpressionStructure ]
44+ private enum Argument : Codable {
45+ case scalar( ExpressionStructure )
46+ case pack( [ ExpressionStructure ] )
47+
48+ init ( from decoder: any Decoder ) throws {
49+ let container = try decoder. singleValueContainer ( )
50+ if let scalarArg = try ? container. decode ( ExpressionStructure . self) {
51+ self = . scalar( scalarArg)
52+ } else {
53+ self = . pack( try container. decode ( [ ExpressionStructure ] . self) )
54+ }
55+ }
56+
57+ func encode( to encoder: any Encoder ) throws {
58+ switch self {
59+ case let . scalar( arg) :
60+ var container = encoder. singleValueContainer ( )
61+ try container. encode ( arg)
62+ case let . pack( args) :
63+ var container = encoder. singleValueContainer ( )
64+ try container. encode ( args)
65+ }
66+ }
67+ }
68+ private let identifier : String
69+ private let args : [ Argument ]
3970
4071 private enum CodingKeys : CodingKey {
4172 case identifier
@@ -56,7 +87,7 @@ private struct ExpressionStructure : Codable {
5687 init ( from decoder: Decoder ) throws {
5788 if let keyedContainer = try ? decoder. container ( keyedBy: CodingKeys . self) {
5889 identifier = try keyedContainer. decode ( String . self, forKey: . identifier)
59- args = try keyedContainer. decode ( [ ExpressionStructure ] . self, forKey: . args)
90+ args = try keyedContainer. decode ( [ Argument ] . self, forKey: . args)
6091 return
6192 }
6293
@@ -65,20 +96,20 @@ private struct ExpressionStructure : Codable {
6596 }
6697
6798 init ( _ type: Type , with configuration: PredicateCodableConfiguration , path: [ String ] = [ ] ) throws {
68- #if canImport(ReflectionInternal, _version: "18")
69- if type. partial? . hasParameterPacks ?? false {
70- throw PredicateCodableError . variadicType ( typeName: _typeName ( type. swiftType) , path: " / \( path. joined ( separator: " / " ) ) " )
71- }
72- #endif
7399 guard let result = configuration. _identifier ( for: type) else {
74100 throw PredicateCodableError . disallowedType ( typeName: _typeName ( type. swiftType) , path: " / \( path. joined ( separator: " / " ) ) " )
75101 }
76102
77103 self . identifier = result. identifier
78104
79105 if !result. isConcrete {
80- self . args = try type. genericArguments. map {
81- try . init( $0, with: configuration, path: path + [ result. identifier] )
106+ self . args = try type. genericArguments2. map {
107+ switch $0 {
108+ case . type( let type) :
109+ . scalar( try . init( type, with: configuration, path: path + [ result. identifier] ) )
110+ case . pack( let types) :
111+ . pack( try types. map { try . init( $0, with: configuration, path: path + [ result. identifier] ) } )
112+ }
82113 }
83114 } else {
84115 self . args = [ ]
@@ -98,17 +129,16 @@ private struct ExpressionStructure : Codable {
98129 partial = partialType
99130 }
100131
101- #if canImport(ReflectionInternal, _version: "18")
102- if partial. hasParameterPacks {
103- throw PredicateCodableError . variadicType ( typeName: partial. name, path: " / \( path. joined ( separator: " / " ) ) " )
104- }
105- #endif
106-
107- let argTypes = try args. map {
108- try $0. reconstruct ( with: configuration, path: path + [ identifier] )
132+ let argTypes : [ GenericArgument ] = try args. map {
133+ switch $0 {
134+ case let . scalar( arg) :
135+ . type( try arg. reconstruct ( with: configuration, path: path + [ identifier] ) )
136+ case let . pack( args) :
137+ . pack( try args. map { try $0. reconstruct ( with: configuration, path: path + [ identifier] ) } )
138+ }
109139 }
110140
111- guard let created = partial. create ( with: argTypes) else {
141+ guard let created = partial. create2 ( with: argTypes) else {
112142 throw PredicateCodableError . reconstructionFailure ( partial, argTypes)
113143 }
114144 return created
@@ -117,7 +147,7 @@ private struct ExpressionStructure : Codable {
117147
118148@available ( FoundationPredicate 0 . 1 , * )
119149class PredicateArchivingState {
120- let configuration : PredicateCodableConfiguration
150+ var configuration : PredicateCodableConfiguration
121151
122152 private var variableMap : [ UInt : PredicateExpressions . VariableID ]
123153
@@ -150,6 +180,7 @@ enum PredicateExpressionCodingKeys : CodingKey {
150180@available ( FoundationPredicate 0 . 1 , * )
151181fileprivate extension PredicateCodableConfiguration {
152182 mutating func allowInputs< each Input > ( _ input: repeat ( each Input ) . Type) {
183+ guard self . shouldAddInputTypes else { return }
153184 var inputTypes = [ Any . Type] ( )
154185 repeat inputTypes. append ( ( each Input) . self)
155186 for (index, type) in inputTypes. enumerated ( ) {
@@ -158,16 +189,29 @@ fileprivate extension PredicateCodableConfiguration {
158189 }
159190}
160191
192+ private func _withPredicateArchivingState< R> ( _ configuration: PredicateCodableConfiguration , _ block: ( ) throws -> R ) rethrows -> R {
193+ if let currentState = _ThreadLocal [ . predicateArchivingState] {
194+ // Store the new configuration and reset it after encoding the subtree
195+ let oldConfiguration = currentState. configuration
196+ defer { currentState. configuration = oldConfiguration }
197+
198+ currentState. configuration = configuration
199+ return try block ( )
200+ } else {
201+ var state = PredicateArchivingState ( configuration: configuration)
202+ return try _ThreadLocal. withValue ( & state, for: . predicateArchivingState, block)
203+ }
204+ }
205+
161206@available ( FoundationPredicate 0 . 1 , * )
162207extension KeyedEncodingContainer where Key == PredicateExpressionCodingKeys {
163208 mutating func _encode< T: PredicateExpression & Encodable , each Input > ( _ expression: T , variable: repeat PredicateExpressions . Variable < each Input > , predicateConfiguration: PredicateCodableConfiguration ) throws where T. Output == Bool {
164209 var predicateConfiguration = predicateConfiguration
165210 predicateConfiguration. allowInputs ( repeat ( each Input) . self)
166211 let structure = try ExpressionStructure ( Type ( expression) , with: predicateConfiguration)
167- var state = PredicateArchivingState ( configuration: predicateConfiguration)
168212 var variableContainer = self . nestedUnkeyedContainer ( forKey: . variable)
169213 repeat try variableContainer. encode ( each variable)
170- try _ThreadLocal . withValue ( & state , for : . predicateArchivingState ) {
214+ try _withPredicateArchivingState ( predicateConfiguration ) {
171215 try self . encode ( structure, forKey: . structure)
172216 try self . encode ( expression, forKey: . expression)
173217 }
@@ -188,9 +232,8 @@ extension KeyedDecodingContainer where Key == PredicateExpressionCodingKeys {
188232 guard let exprType = try structure. reconstruct ( with: predicateConfiguration) . swiftType as? any ( Decodable & PredicateExpression < Bool > ) . Type else {
189233 throw DecodingError . dataCorruptedError ( forKey: . structure, in: self , debugDescription: " This expression is unsupported by this predicate " )
190234 }
191- var state = PredicateArchivingState ( configuration: predicateConfiguration)
192235 var container = try self . nestedUnkeyedContainer ( forKey: . variable)
193- return try _ThreadLocal . withValue ( & state , for : . predicateArchivingState ) {
236+ return try _withPredicateArchivingState ( predicateConfiguration ) {
194237 let variable = ( repeat try container. decode ( PredicateExpressions . Variable< each Input> . self ) )
195238 return ( try decode ( exprType) , variable)
196239 }
0 commit comments