Created
September 28, 2025 22:41
-
-
Save Segmentational/3c1ece052fc73e01ab6933f6126bbd07 to your computer and use it in GitHub Desktop.
Swift-Prose-Expression-Predicate.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // Prose.swift | |
| // Swift-Predicates | |
| // | |
| // Created by Segmentational on 9/28/25. | |
| // | |
| import Foundation | |
| /// A predicate-based expression. | |
| /// | |
| /// **Prose**: *Written or spoken language in its ordinary form, without metrical structure.* | |
| /// | |
| /// - Note: The underlying structure of a `Predicate` is composed of `PredicateExpressions` objects. These | |
| /// represent the individual components and operations within the predicate's logical condition, providing type safety | |
| /// at compile time. | |
| protocol Prose: Sendable { | |
| func prose() -> String | |
| } | |
| extension String: Prose { | |
| func prose() -> String { | |
| "String" | |
| } | |
| } | |
| // Repeated for each supported operator. | |
| extension PredicateExpressions.Equal: Prose where LHS: Prose, RHS: Prose { | |
| func prose() -> String { | |
| return """ | |
| (\(String(lhs.prose())) EQUALS \(rhs.prose())) | |
| """ | |
| } | |
| } | |
| // MARK: - PredicateExpressions Prose Conformances | |
| // Render literal values like "AAPL" or 210.0 | |
| extension PredicateExpressions.Value: Prose { | |
| func prose() -> String { | |
| "\(value)" | |
| } | |
| } | |
| //extension PredicateExpressions.Value: Prose where Output == Double { | |
| // func prose() -> String { | |
| // "\(value)" | |
| // } | |
| //} | |
| // Render key paths like Example.symbol or Example.price | |
| extension PredicateExpressions.KeyPath: Prose { | |
| func prose() -> String { | |
| let base = String(String(reflecting: keyPath).split(separator: ".").first ?? "").dropFirst() | |
| let property = String(String(reflecting: keyPath).split(separator: ".").last ?? "") | |
| return """ | |
| \(base).\(property) | |
| """ | |
| } | |
| } | |
| struct Example: Sendable, Hashable, Equatable, Codable { | |
| var symbol: String | |
| var price: Double | |
| } | |
| // MARK: - Predicate Convenience | |
| extension Predicate { | |
| func prose() -> String? { | |
| guard let expression = expression as? Prose else { return nil } | |
| return expression.prose() | |
| } | |
| } | |
| #if DEBUG && canImport(Playgrounds) | |
| import Playgrounds | |
| #Playground { | |
| // MARK: - Examples | |
| let p1: Predicate<Example> = #Predicate { | |
| $0.symbol == "AAPL" | |
| } | |
| let p2: Predicate<Example> = #Predicate { q in | |
| q.price == 210.0 | |
| } | |
| let p3: Predicate<Example> = #Predicate { q in | |
| q.price == 220.0 | |
| } | |
| // Prints the prose representation | |
| print(p1.prose() ?? "No prose for p1") | |
| print(p2.prose() ?? "No prose for p2") | |
| print(p3.prose() ?? "No prose for p2") | |
| } | |
| #endif | |
| // MARK: - Swift 6 Concurrency Shims | |
| // Some toolchains don't yet mark KeyPath types as Sendable even when Root/Value are Sendable. | |
| // The #Predicate macro expansion can require these to be Sendable. Provide local, conditional | |
| // conformances to unblock builds under strict concurrency. These are safe because KeyPath values | |
| // are immutable and thread-safe by design. We still mark them @unchecked to reflect the retroactive nature. | |
| #if swift(>=6) | |
| extension KeyPath: @unchecked @retroactive Sendable where Root: Sendable, Value: Sendable {} | |
| extension WritableKeyPath: @unchecked Sendable where Root: Sendable, Value: Sendable {} | |
| extension ReferenceWritableKeyPath: @unchecked Sendable where Root: Sendable, Value: Sendable {} | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment