Skip to content

Commit 2ecaed1

Browse files
authored
(122026982) Introduce #Expression macro and type
* (122026982) Introduce #Expression macro and type * (122026982) Add radar to comments
1 parent cc3a63a commit 2ecaed1

15 files changed

+868
-459
lines changed

Sources/FoundationEssentials/Predicate/Archiving/EncodingContainers+PredicateExpression.swift

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#if FOUNDATION_FRAMEWORK
1414

15+
// Initial API constrained to Output == Bool
16+
1517
@available(FoundationPredicate 0.1, *)
1618
extension KeyedEncodingContainer {
1719
public mutating func encodePredicateExpression<T: PredicateExpression & Encodable, each Input>(_ expression: T, forKey key: Self.Key, variable: repeat PredicateExpressions.Variable<each Input>, predicateConfiguration: PredicateCodableConfiguration) throws where T.Output == Bool {
@@ -25,11 +27,19 @@ extension KeyedEncodingContainer {
2527
}
2628
}
2729

30+
extension PredicateExpression {
31+
fileprivate static var outputType: Any.Type {
32+
Output.self
33+
}
34+
}
35+
2836
@available(FoundationPredicate 0.1, *)
2937
extension KeyedDecodingContainer {
38+
@_optimize(none) // Work around swift optimizer crash (rdar://124533887)
3039
public mutating func decodePredicateExpression<each Input>(forKey key: Self.Key, input: repeat (each Input).Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Bool>, variable: (repeat PredicateExpressions.Variable<each Input>)) {
3140
var container = try self.nestedContainer(keyedBy: PredicateExpressionCodingKeys.self, forKey: key)
32-
return try container._decode(input: repeat each input, predicateConfiguration: predicateConfiguration)
41+
let (expr, variable) = try container._decode(input: repeat each input, output: Bool.self, predicateConfiguration: predicateConfiguration)
42+
return (expr, variable)
3343
}
3444

3545
public mutating func decodePredicateExpressionIfPresent<each Input>(forKey key: Self.Key, input: repeat (each Input).Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Bool>, variable: (repeat PredicateExpressions.Variable<each Input>))? {
@@ -56,9 +66,14 @@ extension UnkeyedEncodingContainer {
5666

5767
@available(FoundationPredicate 0.1, *)
5868
extension UnkeyedDecodingContainer {
69+
@_optimize(none) // Work around swift optimizer crash (rdar://124533887)
5970
public mutating func decodePredicateExpression<each Input>(input: repeat (each Input).Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Bool>, variable: (repeat PredicateExpressions.Variable<each Input>)) {
6071
var container = try self.nestedContainer(keyedBy: PredicateExpressionCodingKeys.self)
61-
return try container._decode(input: repeat each input, predicateConfiguration: predicateConfiguration)
72+
let (expr, variable) = try container._decode(input: repeat each input, output: Bool.self, predicateConfiguration: predicateConfiguration)
73+
guard let casted = expr as? any PredicateExpression<Bool> else {
74+
throw DecodingError.dataCorruptedError(in: self, debugDescription: "This expression has an unsupported output type of \(_typeName(type(of: expr).outputType)) (expected Bool)")
75+
}
76+
return (casted, variable)
6277
}
6378

6479
public mutating func decodePredicateExpressionIfPresent<each Input>(input: repeat (each Input).Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Bool>, variable: (repeat PredicateExpressions.Variable<each Input>))? {
@@ -70,4 +85,68 @@ extension UnkeyedDecodingContainer {
7085
}
7186
}
7287

88+
// Added API without Output Constraint
89+
90+
@available(FoundationPredicate 0.4, *)
91+
extension KeyedEncodingContainer {
92+
@_disfavoredOverload
93+
public mutating func encodePredicateExpression<T: PredicateExpression & Encodable, each Input>(_ expression: T, forKey key: Self.Key, variable: repeat PredicateExpressions.Variable<each Input>, predicateConfiguration: PredicateCodableConfiguration) throws {
94+
var container = self.nestedContainer(keyedBy: PredicateExpressionCodingKeys.self, forKey: key)
95+
try container._encode(expression, variable: repeat each variable, predicateConfiguration: predicateConfiguration)
96+
}
97+
98+
@_disfavoredOverload
99+
public mutating func encodePredicateExpressionIfPresent<T: PredicateExpression & Encodable, each Input>(_ expression: T?, forKey key: Self.Key, variable: repeat PredicateExpressions.Variable<each Input>, predicateConfiguration: PredicateCodableConfiguration) throws {
100+
guard let expression else { return }
101+
try self.encodePredicateExpression(expression, forKey: key, variable: repeat each variable, predicateConfiguration: predicateConfiguration)
102+
}
103+
}
104+
105+
@available(FoundationPredicate 0.4, *)
106+
extension KeyedDecodingContainer {
107+
public mutating func decodePredicateExpression<each Input, Output>(forKey key: Self.Key, input: repeat (each Input).Type, output: Output.Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Output>, variable: (repeat PredicateExpressions.Variable<each Input>)) {
108+
var container = try self.nestedContainer(keyedBy: PredicateExpressionCodingKeys.self, forKey: key)
109+
return try container._decode(input: repeat each input, output: output, predicateConfiguration: predicateConfiguration)
110+
}
111+
112+
public mutating func decodePredicateExpressionIfPresent<each Input, Output>(forKey key: Self.Key, input: repeat (each Input).Type, output: Output.Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Output>, variable: (repeat PredicateExpressions.Variable<each Input>))? {
113+
guard self.contains(key) else { return nil }
114+
return try self.decodePredicateExpression(forKey: key, input: repeat each input, output: output, predicateConfiguration: predicateConfiguration)
115+
}
116+
}
117+
118+
@available(FoundationPredicate 0.4, *)
119+
extension UnkeyedEncodingContainer {
120+
@_disfavoredOverload
121+
public mutating func encodePredicateExpression<T: PredicateExpression & Encodable, each Input>(_ expression: T, variable: repeat PredicateExpressions.Variable<each Input>, predicateConfiguration: PredicateCodableConfiguration) throws {
122+
var container = self.nestedContainer(keyedBy: PredicateExpressionCodingKeys.self)
123+
try container._encode(expression, variable: repeat each variable, predicateConfiguration: predicateConfiguration)
124+
}
125+
126+
@_disfavoredOverload
127+
public mutating func encodePredicateExpressionIfPresent<T: PredicateExpression & Encodable, each Input>(_ expression: T?, variable: repeat PredicateExpressions.Variable<each Input>, predicateConfiguration: PredicateCodableConfiguration) throws {
128+
guard let expression else {
129+
try self.encodeNil()
130+
return
131+
}
132+
try self.encodePredicateExpression(expression, variable: repeat each variable, predicateConfiguration: predicateConfiguration)
133+
}
134+
}
135+
136+
@available(FoundationPredicate 0.4, *)
137+
extension UnkeyedDecodingContainer {
138+
public mutating func decodePredicateExpression<each Input, Output>(input: repeat (each Input).Type, output: Output.Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Output>, variable: (repeat PredicateExpressions.Variable<each Input>)) {
139+
var container = try self.nestedContainer(keyedBy: PredicateExpressionCodingKeys.self)
140+
return try container._decode(input: repeat each input, output: output, predicateConfiguration: predicateConfiguration)
141+
}
142+
143+
public mutating func decodePredicateExpressionIfPresent<each Input, Output>(input: repeat (each Input).Type, output: Output.Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Output>, variable: (repeat PredicateExpressions.Variable<each Input>))? {
144+
if try self.decodeNil() {
145+
return nil
146+
} else {
147+
return try self.decodePredicateExpression(input: repeat each input, output: output, predicateConfiguration: predicateConfiguration)
148+
}
149+
}
150+
}
151+
73152
#endif // FOUNDATION_FRAMEWORK

Sources/FoundationEssentials/Predicate/Archiving/Predicate+Codable.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2023 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2023-2024 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -37,6 +37,17 @@ extension Predicate : Codable {
3737
}
3838
}
3939

40+
@available(FoundationPredicate 0.4, *)
41+
extension Expression : Codable {
42+
public func encode(to encoder: Encoder) throws {
43+
try self.encode(to: encoder, configuration: .default)
44+
}
45+
46+
public init(from decoder: Decoder) throws {
47+
try self.init(from: decoder, configuration: .default)
48+
}
49+
}
50+
4051
@available(FoundationPredicate 0.1, *)
4152
extension Predicate : CodableWithConfiguration {
4253
public typealias EncodingConfiguration = PredicateCodableConfiguration
@@ -58,4 +69,25 @@ extension Predicate : CodableWithConfiguration {
5869
}
5970
}
6071

72+
@available(FoundationPredicate 0.4, *)
73+
extension Expression : CodableWithConfiguration {
74+
public typealias EncodingConfiguration = PredicateCodableConfiguration
75+
public typealias DecodingConfiguration = PredicateCodableConfiguration
76+
77+
public func encode(to encoder: Encoder, configuration: EncodingConfiguration) throws {
78+
var container = encoder.unkeyedContainer()
79+
try container.encodePredicateExpression(expression, variable: repeat each variable, predicateConfiguration: configuration)
80+
}
81+
82+
public init(from decoder: Decoder, configuration: DecodingConfiguration) throws {
83+
var container = try decoder.unkeyedContainer()
84+
let result = try container.decodePredicateExpression(input: repeat (each Input).self, output: Output.self, predicateConfiguration: configuration)
85+
guard let trueExpression = result.expression as? any StandardPredicateExpression<Output> else {
86+
throw DecodingError.dataCorruptedError(in: container, debugDescription: "This archived expression is not supported by this Expression type")
87+
}
88+
self.expression = trueExpression
89+
self.variable = result.variable
90+
}
91+
}
92+
6193
#endif // FOUNDATION_FRAMEWORK

Sources/FoundationEssentials/Predicate/Archiving/PredicateCodableConfiguration.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2023 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2023-2024 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -94,7 +94,7 @@ public struct PredicateCodableConfiguration: Sendable, CustomDebugStringConverti
9494
_allowType(type, identifier: identifier, preferNewIdentifier: true)
9595
}
9696

97-
private mutating func _allowType(_ type: Any.Type, identifier: String? = nil, preferNewIdentifier: Bool) {
97+
mutating func _allowType(_ type: Any.Type, identifier: String? = nil, preferNewIdentifier: Bool) {
9898
let identifier = identifier ?? _typeName(type, qualified: true)
9999
for (id, value) in allowedTypes {
100100
if id == identifier {
@@ -349,6 +349,7 @@ extension PredicateCodableConfiguration {
349349
configuration.allowPartialType(Optional<Int>.self, identifier: "Swift.Optional")
350350
configuration.allowPartialType(Slice<String>.self, identifier: "Swift.Slice")
351351
configuration.allowPartialType(Predicate<Int>.self, identifier: "Foundation.Predicate")
352+
configuration.allowPartialType(Expression<Int, Int>.self, identifier: "Foundation.Expression")
352353

353354
// Foundation-defined operator helper types
354355
configuration.allowType(PredicateExpressions.PredicateRegex.self)

Sources/FoundationEssentials/Predicate/Archiving/ExpressionArchiving.swift renamed to Sources/FoundationEssentials/Predicate/Archiving/PredicateExpressionConstruction.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ private func _withPredicateArchivingState<R>(_ configuration: PredicateCodableCo
204204

205205
@available(FoundationPredicate 0.1, *)
206206
extension KeyedEncodingContainer where Key == PredicateExpressionCodingKeys {
207-
mutating func _encode<T: PredicateExpression & Encodable, each Input>(_ expression: T, variable: repeat PredicateExpressions.Variable<each Input>, predicateConfiguration: PredicateCodableConfiguration) throws where T.Output == Bool {
207+
mutating func _encode<T: PredicateExpression & Encodable, each Input>(_ expression: T, variable: repeat PredicateExpressions.Variable<each Input>, predicateConfiguration: PredicateCodableConfiguration) throws {
208208
var predicateConfiguration = predicateConfiguration
209209
predicateConfiguration.allowInputs(repeat (each Input).self)
210210
let structure = try ExpressionStructure(Type(expression), with: predicateConfiguration)
@@ -219,17 +219,17 @@ extension KeyedEncodingContainer where Key == PredicateExpressionCodingKeys {
219219

220220
@available(FoundationPredicate 0.1, *)
221221
extension KeyedDecodingContainer where Key == PredicateExpressionCodingKeys {
222-
mutating func _decode<each Input>(input: repeat (each Input).Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Bool>, variable: (repeat PredicateExpressions.Variable<each Input>)) {
222+
mutating func _decode<each Input, Output>(input: repeat (each Input).Type, output: Output.Type, predicateConfiguration: PredicateCodableConfiguration) throws -> (expression: any PredicateExpression<Output>, variable: (repeat PredicateExpressions.Variable<each Input>)) {
223223
var predicateConfiguration = predicateConfiguration
224224
predicateConfiguration.allowInputs(repeat (each Input).self)
225225
let structure = try self.decode(ExpressionStructure.self, forKey: .structure)
226226

227-
func decode<E: Decodable & PredicateExpression>(_: E.Type) throws -> any PredicateExpression<Bool> where E.Output == Bool {
227+
func decode<E: Decodable & PredicateExpression>(_: E.Type) throws -> any PredicateExpression<Output> where E.Output == Output {
228228
try self.decode(E.self, forKey: .expression)
229229
}
230230

231-
guard let exprType = try structure.reconstruct(with: predicateConfiguration).swiftType as? any (Decodable & PredicateExpression<Bool>).Type else {
232-
throw DecodingError.dataCorruptedError(forKey: .structure, in: self, debugDescription: "This expression is unsupported by this predicate")
231+
guard let exprType = try structure.reconstruct(with: predicateConfiguration).swiftType as? any (Decodable & PredicateExpression<Output>).Type else {
232+
throw DecodingError.dataCorruptedError(forKey: .structure, in: self, debugDescription: "This type of this expression is unsupported")
233233
}
234234
var container = try self.nestedUnkeyedContainer(forKey: .variable)
235235
return try _withPredicateArchivingState(predicateConfiguration) {

0 commit comments

Comments
 (0)