├── .github └── workflows │ └── swift.yml ├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── LICENSE ├── Package.swift ├── README.md ├── Sources ├── AssociatedTypeRequirementsVisitor │ ├── AssociatedTypeRequirementsTypeVisitor.swift │ ├── AssociatedTypeRequirementsVisitor.swift │ ├── _test.swift │ ├── testTypes.swift │ ├── visitors.swift │ └── visitors.swift.gyb ├── CContext │ ├── CContext.c │ └── include │ │ └── CContext.h ├── Casting │ ├── CastedProtocolValue.swift │ └── withCasted.swift ├── ProtocolConformance │ ├── ProtocolConformanceRecord.swift │ ├── fakeConformance.swift │ ├── helpers.swift │ └── helpers.swift.gyb ├── ProtocolType │ ├── ModuleName.swift │ ├── ModuleName.swift.gyb │ ├── ProtocolName.swift │ ├── ProtocolName.swift.gyb │ ├── ProtocolType.swift │ └── ProtocolType.swift.gyb └── ValuePointers │ └── withUnsafeValuePointer.swift ├── Tests ├── AssociatedTypeRequirementsKitTests │ ├── ProtocolTypeTests.swift │ ├── ValuePointersTests.swift │ ├── VisitorTests.swift │ └── XCTestManifests.swift └── LinuxMain.swift ├── commonProtocols.json ├── swift-error-message.png └── useGYB /.github/workflows/swift.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - release 8 | pull_request: 9 | branches: 10 | - develop 11 | - release 12 | 13 | jobs: 14 | macos: 15 | runs-on: macos-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: maxim-lobanov/setup-xcode@v1.1 19 | with: 20 | xcode-version: latest 21 | - name: Check Xcode version 22 | run: xcodebuild -version 23 | - name: Check Swift version 24 | run: swift --version 25 | - name: Build 26 | run: swift build 27 | - name: Test 28 | run: swift test 29 | linux: 30 | container: 31 | image: swift:${{ matrix.linux }} 32 | runs-on: ubuntu-latest 33 | strategy: 34 | matrix: 35 | linux: [bionic, xenial, focal] 36 | steps: 37 | - uses: actions/checkout@v2 38 | - name: Install libsqlite3 39 | run: apt-get update && apt-get install -y --no-install-recommends libsqlite3-dev 40 | - name: Check Swift version 41 | run: swift --version 42 | - name: Build 43 | run: swift build 44 | - name: Test 45 | run: swift test 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mathias Quintero 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "AssociatedTypeRequirementsKit", 8 | products: [ 9 | .library(name: "AssociatedTypeRequirementsKit", 10 | targets: ["AssociatedTypeRequirementsVisitor", "Casting", "ValuePointers", "ProtocolType"]), 11 | ], 12 | dependencies: [], 13 | targets: [ 14 | .target( 15 | name: "AssociatedTypeRequirementsVisitor", 16 | dependencies: ["Casting", "ValuePointers", "CContext"]), 17 | 18 | .target( 19 | name: "Casting", 20 | dependencies: ["ValuePointers", "ProtocolType"]), 21 | 22 | .target( 23 | name: "ValuePointers", 24 | dependencies: ["ProtocolConformance"]), 25 | 26 | .target( 27 | name: "ProtocolType", 28 | dependencies: []), 29 | 30 | .target( 31 | name: "ProtocolConformance", 32 | dependencies: ["ProtocolType"]), 33 | 34 | .target( 35 | name: "CContext", 36 | dependencies: []), 37 | 38 | .testTarget( 39 | name: "AssociatedTypeRequirementsKitTests", 40 | dependencies: ["AssociatedTypeRequirementsVisitor", "Casting", "ValuePointers", "ProtocolType"]), 41 | ] 42 | ) 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AssociatedTypeRequirementsKit 2 | 3 | Is Swift bothering you with those pesky error messages? Something something about associated type requirements. Like when you want to cast something to a protocol, but then: 4 | 5 | ![](swift-error-message.png) 6 | 7 | Well not to worry. Introducing AssociatedTypeRequirementsKit 🤗 8 | A collection of µFrameworks to help you get around those annoying scenarios! 9 | 10 | Our example from before is dealt like so: 11 | 12 | ```swift 13 | import AssociatedTypeRequirementsVisitor 14 | 15 | private let hasher = AnyHasher() 16 | 17 | func hashValue(value: Any) -> Int { 18 | // There's a function `AnyHasher.callAsFunction(_:Any) -> Int?` 19 | return hasher(value) ?? 0 20 | } 21 | 22 | struct AnyHasher: HashableVisitor { 23 | // This function will called by `callAsFunction(_:Any)` if the input conforms to hashable 24 | func callAsFunction(_ value: T) -> Int { 25 | return value.hashValue 26 | } 27 | } 28 | ``` 29 | 30 | ## Installation 31 | ### Swift Package Manager 32 | 33 | You can install AssociatedTypeRequirementsKit via [Swift Package Manager](https://swift.org/package-manager/) by adding the following line to your `Package.swift`: 34 | 35 | ```swift 36 | import PackageDescription 37 | 38 | let package = Package( 39 | [...] 40 | dependencies: [ 41 | .package(url: "https://github.com/nerdsupremacist/AssociatedTypeRequirementsKit.git", from: "0.1.0") 42 | ] 43 | ) 44 | ``` 45 | 46 | ## Usage 47 | 48 | ### AssociatedTypeRequirementsVisitor 49 | 50 | If you want to be able to call a function on a protocol with associated types, then you'll have to provide a generic function. Since closures cannot be generic, we have to use a protocol to encode this. 51 | 52 | For example if you want to be able to turn any SwiftUI view into an AnyView, but you don't know the type at compile time, you can use `ViewVisitor`: 53 | 54 | ```swift 55 | import AssociatedTypeRequirementsVisitor 56 | import SwiftUI 57 | 58 | private let converter = AnyViewConverter() 59 | 60 | extension AnyView { 61 | init?(_ value: Any) { 62 | guard let view = converter(value) else { return nil } 63 | self = view 64 | } 65 | } 66 | 67 | private struct AnyViewConverter : ViewVisitor { 68 | // Provide a function that can be called with all the necessary type information 69 | func callAsFunction(_ value: T) -> AnyView { 70 | return AnyView(value) 71 | } 72 | } 73 | ``` 74 | 75 | But why would you need to do this? Well, for example if you want to get all the subviews of a tuple view? 76 | 77 | ```swift 78 | extension TupleView { 79 | 80 | func subviews() -> [AnyView] { 81 | let mirror = Mirror(reflecting: self) 82 | let tuple = mirror.children.first!.value 83 | let tupleMirror = Mirror(reflecting: tuple) 84 | return tupleMirror.children.map { AnyView($0.value)! } 85 | } 86 | 87 | } 88 | ``` 89 | 90 | `ViewVisitor` is available out of the box because we are already shipping visitor protocols for the most important problematic protocols in Swift right now, and are extending the list as we go. 91 | If you have to handle your own protocol you can do it as in the following example: 92 | 93 | ```swift 94 | protocol MyProtocolVisitor: AssociatedTypeRequirementsVisitor { 95 | associatedtype Visitor = MyProtocolVisitor 96 | associatedtype Input = MyProtocol 97 | associatedtype Output 98 | 99 | func callAsFunction(_ value: T) -> Output 100 | } 101 | ``` 102 | 103 | ### Casting 104 | 105 | If you don't want to use the `AssociatedTypeRequirementsVisitor` API, you can also ask use the low level `withCasted` API and ask for the protocol conformance yourself. 106 | 107 | ```swift 108 | import Casting 109 | 110 | func test(value: Any) -> AnyHashable? { 111 | return withCasted(value, as: .hashable) { casted in 112 | // casted is CastedProtocolValue 113 | ... 114 | } 115 | } 116 | ``` 117 | 118 | But what is this `CastedProtocolValue`? Well it's a little struct that has the same layout that a function `func anyHashable(hashable: T)` would expect. So that function could be casted: 119 | 120 | ```swift 121 | import Casting 122 | 123 | func test(value: Any) -> AnyHashable? { 124 | return withCasted(value, as: .hashable) { casted in 125 | // A pointer to the function is in `functionPointer` 126 | let function = unsafeBitCast(functionPointer, (@convention(thin) (CastedProtocolValue) -> AnyHashable).self) 127 | return function(casted) 128 | } 129 | } 130 | ``` 131 | 132 | ### ValuePointers 133 | 134 | When you use the `withUnsafePointer` API from the Swift Standard Library, but with `Any` you'll notice that the pointer or bytes you get are not quite correct. 135 | That's becasue they're pointing to the existential container `Any`, which is always 32 Bytes. 136 | 137 | That's why we ship `withUnsafeValuePointer` which will always point to the actual value, instead of the container: 138 | 139 | ```swift 140 | import ValuePointers 141 | 142 | struct MyStruct { 143 | let first: String 144 | let second: String 145 | } 146 | 147 | let value = MyStruct(first: "A", second: "B") as Any 148 | let secondString = withUnsafeValuePointer(to: value) { $0.assumingMemoryBound(to: String.self).advanced(by: 1).pointee } 149 | 150 | // "B" 151 | print(secondString) 152 | ``` 153 | 154 | ### ProtocolType 155 | 156 | Whenever you want to access the meta-type of a protocol with associated types, you'll run into this exact same problem. 157 | You can use `ProtocolType` to access it via the name of the protocol: 158 | 159 | ```swift 160 | import ProtocolType 161 | 162 | let protocolType = ProtocolType(moduleName: "SwiftUI", protocolName: "View") 163 | print(protocolType?.type) // SwiftUI.View.self 164 | ``` 165 | 166 | And ProtocolType provides a set of constants already shipped. The list of constants can be changed in the `commonProtocols.json` file and can be extended further: 167 | 168 | ```swift 169 | import ProtocolType 170 | 171 | func hash(protocol protocolType: ProtocolType) -> some Hashable { 172 | return unsafeBitCast(type, as: Int.self) 173 | } 174 | 175 | let hashed = hash(protocol: .collection) 176 | ``` 177 | 178 | ## Contributions 179 | Contributions are welcome and encouraged! 180 | 181 | ## License 182 | AssociatedTypeRequirementsKit is available under the MIT license. See the LICENSE file for more info. 183 | -------------------------------------------------------------------------------- /Sources/AssociatedTypeRequirementsVisitor/AssociatedTypeRequirementsTypeVisitor.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import ProtocolConformance 4 | import ProtocolType 5 | import Casting 6 | import CContext 7 | 8 | public protocol AssociatedTypeRequirementsTypeVisitor { 9 | associatedtype Visitor 10 | associatedtype Input 11 | associatedtype Output 12 | 13 | func _test() 14 | } 15 | 16 | extension AssociatedTypeRequirementsTypeVisitor { 17 | 18 | public func callAsFunction(_ type: Any.Type) -> Output? { 19 | if _isTesting { 20 | _test() 21 | _testAssocaitedTypeRequirementVisitors(false) 22 | } 23 | 24 | guard let visitorWitnessTable = ProtocolConformanceRecord(implementationType: Self.self, protocolType: Visitor.self) else { return nil } 25 | guard let conformanceRecord = ProtocolConformanceRecord(implementationType: type, protocolType: Input.self) else { return nil } 26 | 27 | let functionPointer = visitorWitnessTable.witnessTable!.assumingMemoryBound(to: UnsafeRawPointer.self).advanced(by: 2).pointee 28 | let function = unsafeBitCast(functionPointer, to: (@convention(thin) (UnsafeRawPointer, ProtocolConformanceRecord, UnsafeRawPointer) -> Output).self) 29 | return withUnsafePointer(to: self) { selfPointer in 30 | let typePointer = unsafeBitCast(type, to: UnsafeRawPointer.self) 31 | set_self_pointer(UnsafeMutableRawPointer(mutating: UnsafeRawPointer(selfPointer))) 32 | return function(typePointer, conformanceRecord, conformanceRecord.witnessTable!) 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Sources/AssociatedTypeRequirementsVisitor/AssociatedTypeRequirementsVisitor.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import ProtocolConformance 4 | import ProtocolType 5 | import Casting 6 | import CContext 7 | 8 | public protocol AssociatedTypeRequirementsVisitor { 9 | associatedtype Visitor 10 | associatedtype Input 11 | associatedtype Output 12 | 13 | func _test() 14 | } 15 | 16 | extension AssociatedTypeRequirementsVisitor { 17 | 18 | public func callAsFunction(_ value: Any) -> Output? { 19 | if _isTesting { 20 | _test() 21 | _testAssocaitedTypeRequirementVisitors(false) 22 | } 23 | 24 | guard let visitorWitnessTable = ProtocolConformanceRecord(implementationType: Self.self, protocolType: Visitor.self) else { return nil } 25 | return withCasted(value, as: Input.self) { casted in 26 | let functionPointer = visitorWitnessTable.witnessTable!.assumingMemoryBound(to: UnsafeRawPointer.self).advanced(by: 2).pointee 27 | let function = unsafeBitCast(functionPointer, to: (@convention(thin) (CastedProtocolValue) -> Output).self) 28 | return withUnsafePointer(to: self) { selfPointer in 29 | set_self_pointer(UnsafeMutableRawPointer(mutating: UnsafeRawPointer(selfPointer))) 30 | return function(casted) 31 | } 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Sources/AssociatedTypeRequirementsVisitor/_test.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | var _isTesting = false 5 | 6 | public func _testAssocaitedTypeRequirementVisitors(_ newValue: Bool) { 7 | _isTesting = newValue 8 | } 9 | -------------------------------------------------------------------------------- /Sources/AssociatedTypeRequirementsVisitor/testTypes.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | enum TestRawRepresentable: String { 5 | case test 6 | } 7 | 8 | struct TestIdentifiable: Identifiable { 9 | let id: String 10 | } 11 | -------------------------------------------------------------------------------- /Sources/AssociatedTypeRequirementsVisitor/visitors.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import ProtocolType 4 | 5 | 6 | // Swift 7 | #if canImport(Swift) 8 | import Swift 9 | 10 | public protocol BinaryFloatingPointVisitor: AssociatedTypeRequirementsVisitor { 11 | associatedtype Visitor = BinaryFloatingPointVisitor 12 | associatedtype Input = BinaryFloatingPoint 13 | associatedtype Output 14 | 15 | func callAsFunction(_ value: T) -> Output 16 | } 17 | 18 | extension BinaryFloatingPointVisitor { 19 | 20 | @inline(never) 21 | @_optimize(none) 22 | public func _test() { 23 | _ = self(42.0) as Output 24 | } 25 | 26 | } 27 | 28 | public protocol BinaryFloatingPointTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 29 | associatedtype Visitor = BinaryFloatingPointTypeVisitor 30 | associatedtype Input = BinaryFloatingPoint 31 | associatedtype Output 32 | 33 | func callAsFunction(_ type: T.Type) -> Output 34 | } 35 | 36 | extension BinaryFloatingPointTypeVisitor { 37 | 38 | @inline(never) 39 | @_optimize(none) 40 | public func _test() { 41 | _ = self(Double.self) as Output 42 | } 43 | 44 | } 45 | 46 | public protocol EncodableVisitor: AssociatedTypeRequirementsVisitor { 47 | associatedtype Visitor = EncodableVisitor 48 | associatedtype Input = Encodable 49 | associatedtype Output 50 | 51 | func callAsFunction(_ value: T) -> Output 52 | } 53 | 54 | extension EncodableVisitor { 55 | 56 | @inline(never) 57 | @_optimize(none) 58 | public func _test() { 59 | _ = self(42) as Output 60 | } 61 | 62 | } 63 | 64 | public protocol EncodableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 65 | associatedtype Visitor = EncodableTypeVisitor 66 | associatedtype Input = Encodable 67 | associatedtype Output 68 | 69 | func callAsFunction(_ type: T.Type) -> Output 70 | } 71 | 72 | extension EncodableTypeVisitor { 73 | 74 | @inline(never) 75 | @_optimize(none) 76 | public func _test() { 77 | _ = self(Int.self) as Output 78 | } 79 | 80 | } 81 | 82 | public protocol DecodableVisitor: AssociatedTypeRequirementsVisitor { 83 | associatedtype Visitor = DecodableVisitor 84 | associatedtype Input = Decodable 85 | associatedtype Output 86 | 87 | func callAsFunction(_ value: T) -> Output 88 | } 89 | 90 | extension DecodableVisitor { 91 | 92 | @inline(never) 93 | @_optimize(none) 94 | public func _test() { 95 | _ = self(42) as Output 96 | } 97 | 98 | } 99 | 100 | public protocol DecodableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 101 | associatedtype Visitor = DecodableTypeVisitor 102 | associatedtype Input = Decodable 103 | associatedtype Output 104 | 105 | func callAsFunction(_ type: T.Type) -> Output 106 | } 107 | 108 | extension DecodableTypeVisitor { 109 | 110 | @inline(never) 111 | @_optimize(none) 112 | public func _test() { 113 | _ = self(Int.self) as Output 114 | } 115 | 116 | } 117 | 118 | public protocol RandomNumberGeneratorVisitor: AssociatedTypeRequirementsVisitor { 119 | associatedtype Visitor = RandomNumberGeneratorVisitor 120 | associatedtype Input = RandomNumberGenerator 121 | associatedtype Output 122 | 123 | func callAsFunction(_ value: T) -> Output 124 | } 125 | 126 | extension RandomNumberGeneratorVisitor { 127 | 128 | @inline(never) 129 | @_optimize(none) 130 | public func _test() { 131 | _ = self(SystemRandomNumberGenerator()) as Output 132 | } 133 | 134 | } 135 | 136 | public protocol RandomNumberGeneratorTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 137 | associatedtype Visitor = RandomNumberGeneratorTypeVisitor 138 | associatedtype Input = RandomNumberGenerator 139 | associatedtype Output 140 | 141 | func callAsFunction(_ type: T.Type) -> Output 142 | } 143 | 144 | extension RandomNumberGeneratorTypeVisitor { 145 | 146 | @inline(never) 147 | @_optimize(none) 148 | public func _test() { 149 | _ = self(SystemRandomNumberGenerator.self) as Output 150 | } 151 | 152 | } 153 | 154 | public protocol HashableVisitor: AssociatedTypeRequirementsVisitor { 155 | associatedtype Visitor = HashableVisitor 156 | associatedtype Input = Hashable 157 | associatedtype Output 158 | 159 | func callAsFunction(_ value: T) -> Output 160 | } 161 | 162 | extension HashableVisitor { 163 | 164 | @inline(never) 165 | @_optimize(none) 166 | public func _test() { 167 | _ = self(42) as Output 168 | } 169 | 170 | } 171 | 172 | public protocol HashableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 173 | associatedtype Visitor = HashableTypeVisitor 174 | associatedtype Input = Hashable 175 | associatedtype Output 176 | 177 | func callAsFunction(_ type: T.Type) -> Output 178 | } 179 | 180 | extension HashableTypeVisitor { 181 | 182 | @inline(never) 183 | @_optimize(none) 184 | public func _test() { 185 | _ = self(Int.self) as Output 186 | } 187 | 188 | } 189 | 190 | public protocol NumericVisitor: AssociatedTypeRequirementsVisitor { 191 | associatedtype Visitor = NumericVisitor 192 | associatedtype Input = Numeric 193 | associatedtype Output 194 | 195 | func callAsFunction(_ value: T) -> Output 196 | } 197 | 198 | extension NumericVisitor { 199 | 200 | @inline(never) 201 | @_optimize(none) 202 | public func _test() { 203 | _ = self(42) as Output 204 | } 205 | 206 | } 207 | 208 | public protocol NumericTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 209 | associatedtype Visitor = NumericTypeVisitor 210 | associatedtype Input = Numeric 211 | associatedtype Output 212 | 213 | func callAsFunction(_ type: T.Type) -> Output 214 | } 215 | 216 | extension NumericTypeVisitor { 217 | 218 | @inline(never) 219 | @_optimize(none) 220 | public func _test() { 221 | _ = self(Int.self) as Output 222 | } 223 | 224 | } 225 | 226 | public protocol BidirectionalCollectionVisitor: AssociatedTypeRequirementsVisitor { 227 | associatedtype Visitor = BidirectionalCollectionVisitor 228 | associatedtype Input = BidirectionalCollection 229 | associatedtype Output 230 | 231 | func callAsFunction(_ value: T) -> Output 232 | } 233 | 234 | extension BidirectionalCollectionVisitor { 235 | 236 | @inline(never) 237 | @_optimize(none) 238 | public func _test() { 239 | _ = self([42]) as Output 240 | } 241 | 242 | } 243 | 244 | public protocol BidirectionalCollectionTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 245 | associatedtype Visitor = BidirectionalCollectionTypeVisitor 246 | associatedtype Input = BidirectionalCollection 247 | associatedtype Output 248 | 249 | func callAsFunction(_ type: T.Type) -> Output 250 | } 251 | 252 | extension BidirectionalCollectionTypeVisitor { 253 | 254 | @inline(never) 255 | @_optimize(none) 256 | public func _test() { 257 | _ = self(Array.self) as Output 258 | } 259 | 260 | } 261 | 262 | public protocol RandomAccessCollectionVisitor: AssociatedTypeRequirementsVisitor { 263 | associatedtype Visitor = RandomAccessCollectionVisitor 264 | associatedtype Input = RandomAccessCollection 265 | associatedtype Output 266 | 267 | func callAsFunction(_ value: T) -> Output 268 | } 269 | 270 | extension RandomAccessCollectionVisitor { 271 | 272 | @inline(never) 273 | @_optimize(none) 274 | public func _test() { 275 | _ = self([42]) as Output 276 | } 277 | 278 | } 279 | 280 | public protocol RandomAccessCollectionTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 281 | associatedtype Visitor = RandomAccessCollectionTypeVisitor 282 | associatedtype Input = RandomAccessCollection 283 | associatedtype Output 284 | 285 | func callAsFunction(_ type: T.Type) -> Output 286 | } 287 | 288 | extension RandomAccessCollectionTypeVisitor { 289 | 290 | @inline(never) 291 | @_optimize(none) 292 | public func _test() { 293 | _ = self(Array.self) as Output 294 | } 295 | 296 | } 297 | 298 | public protocol ComparableVisitor: AssociatedTypeRequirementsVisitor { 299 | associatedtype Visitor = ComparableVisitor 300 | associatedtype Input = Comparable 301 | associatedtype Output 302 | 303 | func callAsFunction(_ value: T) -> Output 304 | } 305 | 306 | extension ComparableVisitor { 307 | 308 | @inline(never) 309 | @_optimize(none) 310 | public func _test() { 311 | _ = self(42) as Output 312 | } 313 | 314 | } 315 | 316 | public protocol ComparableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 317 | associatedtype Visitor = ComparableTypeVisitor 318 | associatedtype Input = Comparable 319 | associatedtype Output 320 | 321 | func callAsFunction(_ type: T.Type) -> Output 322 | } 323 | 324 | extension ComparableTypeVisitor { 325 | 326 | @inline(never) 327 | @_optimize(none) 328 | public func _test() { 329 | _ = self(Int.self) as Output 330 | } 331 | 332 | } 333 | 334 | public protocol CollectionVisitor: AssociatedTypeRequirementsVisitor { 335 | associatedtype Visitor = CollectionVisitor 336 | associatedtype Input = Collection 337 | associatedtype Output 338 | 339 | func callAsFunction(_ value: T) -> Output 340 | } 341 | 342 | extension CollectionVisitor { 343 | 344 | @inline(never) 345 | @_optimize(none) 346 | public func _test() { 347 | _ = self([42]) as Output 348 | } 349 | 350 | } 351 | 352 | public protocol CollectionTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 353 | associatedtype Visitor = CollectionTypeVisitor 354 | associatedtype Input = Collection 355 | associatedtype Output 356 | 357 | func callAsFunction(_ type: T.Type) -> Output 358 | } 359 | 360 | extension CollectionTypeVisitor { 361 | 362 | @inline(never) 363 | @_optimize(none) 364 | public func _test() { 365 | _ = self(Array.self) as Output 366 | } 367 | 368 | } 369 | 370 | public protocol MutableCollectionVisitor: AssociatedTypeRequirementsVisitor { 371 | associatedtype Visitor = MutableCollectionVisitor 372 | associatedtype Input = MutableCollection 373 | associatedtype Output 374 | 375 | func callAsFunction(_ value: T) -> Output 376 | } 377 | 378 | extension MutableCollectionVisitor { 379 | 380 | @inline(never) 381 | @_optimize(none) 382 | public func _test() { 383 | _ = self([42]) as Output 384 | } 385 | 386 | } 387 | 388 | public protocol MutableCollectionTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 389 | associatedtype Visitor = MutableCollectionTypeVisitor 390 | associatedtype Input = MutableCollection 391 | associatedtype Output 392 | 393 | func callAsFunction(_ type: T.Type) -> Output 394 | } 395 | 396 | extension MutableCollectionTypeVisitor { 397 | 398 | @inline(never) 399 | @_optimize(none) 400 | public func _test() { 401 | _ = self(Array.self) as Output 402 | } 403 | 404 | } 405 | 406 | public protocol RangeReplaceableCollectionVisitor: AssociatedTypeRequirementsVisitor { 407 | associatedtype Visitor = RangeReplaceableCollectionVisitor 408 | associatedtype Input = RangeReplaceableCollection 409 | associatedtype Output 410 | 411 | func callAsFunction(_ value: T) -> Output 412 | } 413 | 414 | extension RangeReplaceableCollectionVisitor { 415 | 416 | @inline(never) 417 | @_optimize(none) 418 | public func _test() { 419 | _ = self([42]) as Output 420 | } 421 | 422 | } 423 | 424 | public protocol RangeReplaceableCollectionTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 425 | associatedtype Visitor = RangeReplaceableCollectionTypeVisitor 426 | associatedtype Input = RangeReplaceableCollection 427 | associatedtype Output 428 | 429 | func callAsFunction(_ type: T.Type) -> Output 430 | } 431 | 432 | extension RangeReplaceableCollectionTypeVisitor { 433 | 434 | @inline(never) 435 | @_optimize(none) 436 | public func _test() { 437 | _ = self(Array.self) as Output 438 | } 439 | 440 | } 441 | 442 | public protocol EquatableVisitor: AssociatedTypeRequirementsVisitor { 443 | associatedtype Visitor = EquatableVisitor 444 | associatedtype Input = Equatable 445 | associatedtype Output 446 | 447 | func callAsFunction(_ value: T) -> Output 448 | } 449 | 450 | extension EquatableVisitor { 451 | 452 | @inline(never) 453 | @_optimize(none) 454 | public func _test() { 455 | _ = self(42) as Output 456 | } 457 | 458 | } 459 | 460 | public protocol EquatableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 461 | associatedtype Visitor = EquatableTypeVisitor 462 | associatedtype Input = Equatable 463 | associatedtype Output 464 | 465 | func callAsFunction(_ type: T.Type) -> Output 466 | } 467 | 468 | extension EquatableTypeVisitor { 469 | 470 | @inline(never) 471 | @_optimize(none) 472 | public func _test() { 473 | _ = self(Int.self) as Output 474 | } 475 | 476 | } 477 | 478 | public protocol SequenceVisitor: AssociatedTypeRequirementsVisitor { 479 | associatedtype Visitor = SequenceVisitor 480 | associatedtype Input = Sequence 481 | associatedtype Output 482 | 483 | func callAsFunction(_ value: T) -> Output 484 | } 485 | 486 | extension SequenceVisitor { 487 | 488 | @inline(never) 489 | @_optimize(none) 490 | public func _test() { 491 | _ = self([42]) as Output 492 | } 493 | 494 | } 495 | 496 | public protocol SequenceTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 497 | associatedtype Visitor = SequenceTypeVisitor 498 | associatedtype Input = Sequence 499 | associatedtype Output 500 | 501 | func callAsFunction(_ type: T.Type) -> Output 502 | } 503 | 504 | extension SequenceTypeVisitor { 505 | 506 | @inline(never) 507 | @_optimize(none) 508 | public func _test() { 509 | _ = self(Array.self) as Output 510 | } 511 | 512 | } 513 | 514 | public protocol IteratorProtocolVisitor: AssociatedTypeRequirementsVisitor { 515 | associatedtype Visitor = IteratorProtocolVisitor 516 | associatedtype Input = IteratorProtocol 517 | associatedtype Output 518 | 519 | func callAsFunction(_ value: T) -> Output 520 | } 521 | 522 | extension IteratorProtocolVisitor { 523 | 524 | @inline(never) 525 | @_optimize(none) 526 | public func _test() { 527 | _ = self([42].makeIterator()) as Output 528 | } 529 | 530 | } 531 | 532 | public protocol IteratorProtocolTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 533 | associatedtype Visitor = IteratorProtocolTypeVisitor 534 | associatedtype Input = IteratorProtocol 535 | associatedtype Output 536 | 537 | func callAsFunction(_ type: T.Type) -> Output 538 | } 539 | 540 | extension IteratorProtocolTypeVisitor { 541 | 542 | @inline(never) 543 | @_optimize(none) 544 | public func _test() { 545 | _ = self(Array.Iterator.self) as Output 546 | } 547 | 548 | } 549 | 550 | public protocol UnsignedIntegerVisitor: AssociatedTypeRequirementsVisitor { 551 | associatedtype Visitor = UnsignedIntegerVisitor 552 | associatedtype Input = UnsignedInteger 553 | associatedtype Output 554 | 555 | func callAsFunction(_ value: T) -> Output 556 | } 557 | 558 | extension UnsignedIntegerVisitor { 559 | 560 | @inline(never) 561 | @_optimize(none) 562 | public func _test() { 563 | _ = self(42 as UInt) as Output 564 | } 565 | 566 | } 567 | 568 | public protocol UnsignedIntegerTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 569 | associatedtype Visitor = UnsignedIntegerTypeVisitor 570 | associatedtype Input = UnsignedInteger 571 | associatedtype Output 572 | 573 | func callAsFunction(_ type: T.Type) -> Output 574 | } 575 | 576 | extension UnsignedIntegerTypeVisitor { 577 | 578 | @inline(never) 579 | @_optimize(none) 580 | public func _test() { 581 | _ = self(UInt.self) as Output 582 | } 583 | 584 | } 585 | 586 | public protocol RangeExpressionVisitor: AssociatedTypeRequirementsVisitor { 587 | associatedtype Visitor = RangeExpressionVisitor 588 | associatedtype Input = RangeExpression 589 | associatedtype Output 590 | 591 | func callAsFunction(_ value: T) -> Output 592 | } 593 | 594 | extension RangeExpressionVisitor { 595 | 596 | @inline(never) 597 | @_optimize(none) 598 | public func _test() { 599 | _ = self(0..<1) as Output 600 | } 601 | 602 | } 603 | 604 | public protocol RangeExpressionTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 605 | associatedtype Visitor = RangeExpressionTypeVisitor 606 | associatedtype Input = RangeExpression 607 | associatedtype Output 608 | 609 | func callAsFunction(_ type: T.Type) -> Output 610 | } 611 | 612 | extension RangeExpressionTypeVisitor { 613 | 614 | @inline(never) 615 | @_optimize(none) 616 | public func _test() { 617 | _ = self(Range.self) as Output 618 | } 619 | 620 | } 621 | 622 | public protocol StrideableVisitor: AssociatedTypeRequirementsVisitor { 623 | associatedtype Visitor = StrideableVisitor 624 | associatedtype Input = Strideable 625 | associatedtype Output 626 | 627 | func callAsFunction(_ value: T) -> Output 628 | } 629 | 630 | extension StrideableVisitor { 631 | 632 | @inline(never) 633 | @_optimize(none) 634 | public func _test() { 635 | _ = self(42.0) as Output 636 | } 637 | 638 | } 639 | 640 | public protocol StrideableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 641 | associatedtype Visitor = StrideableTypeVisitor 642 | associatedtype Input = Strideable 643 | associatedtype Output 644 | 645 | func callAsFunction(_ type: T.Type) -> Output 646 | } 647 | 648 | extension StrideableTypeVisitor { 649 | 650 | @inline(never) 651 | @_optimize(none) 652 | public func _test() { 653 | _ = self(Double.self) as Output 654 | } 655 | 656 | } 657 | 658 | public protocol RawRepresentableVisitor: AssociatedTypeRequirementsVisitor { 659 | associatedtype Visitor = RawRepresentableVisitor 660 | associatedtype Input = RawRepresentable 661 | associatedtype Output 662 | 663 | func callAsFunction(_ value: T) -> Output 664 | } 665 | 666 | extension RawRepresentableVisitor { 667 | 668 | @inline(never) 669 | @_optimize(none) 670 | public func _test() { 671 | _ = self(TestRawRepresentable.test) as Output 672 | } 673 | 674 | } 675 | 676 | public protocol RawRepresentableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 677 | associatedtype Visitor = RawRepresentableTypeVisitor 678 | associatedtype Input = RawRepresentable 679 | associatedtype Output 680 | 681 | func callAsFunction(_ type: T.Type) -> Output 682 | } 683 | 684 | extension RawRepresentableTypeVisitor { 685 | 686 | @inline(never) 687 | @_optimize(none) 688 | public func _test() { 689 | _ = self(TestRawRepresentable.self.self) as Output 690 | } 691 | 692 | } 693 | 694 | public protocol StringProtocolVisitor: AssociatedTypeRequirementsVisitor { 695 | associatedtype Visitor = StringProtocolVisitor 696 | associatedtype Input = StringProtocol 697 | associatedtype Output 698 | 699 | func callAsFunction(_ value: T) -> Output 700 | } 701 | 702 | extension StringProtocolVisitor { 703 | 704 | @inline(never) 705 | @_optimize(none) 706 | public func _test() { 707 | _ = self("") as Output 708 | } 709 | 710 | } 711 | 712 | public protocol StringProtocolTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 713 | associatedtype Visitor = StringProtocolTypeVisitor 714 | associatedtype Input = StringProtocol 715 | associatedtype Output 716 | 717 | func callAsFunction(_ type: T.Type) -> Output 718 | } 719 | 720 | extension StringProtocolTypeVisitor { 721 | 722 | @inline(never) 723 | @_optimize(none) 724 | public func _test() { 725 | _ = self(String.self) as Output 726 | } 727 | 728 | } 729 | 730 | public protocol SignedIntegerVisitor: AssociatedTypeRequirementsVisitor { 731 | associatedtype Visitor = SignedIntegerVisitor 732 | associatedtype Input = SignedInteger 733 | associatedtype Output 734 | 735 | func callAsFunction(_ value: T) -> Output 736 | } 737 | 738 | extension SignedIntegerVisitor { 739 | 740 | @inline(never) 741 | @_optimize(none) 742 | public func _test() { 743 | _ = self(42) as Output 744 | } 745 | 746 | } 747 | 748 | public protocol SignedIntegerTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 749 | associatedtype Visitor = SignedIntegerTypeVisitor 750 | associatedtype Input = SignedInteger 751 | associatedtype Output 752 | 753 | func callAsFunction(_ type: T.Type) -> Output 754 | } 755 | 756 | extension SignedIntegerTypeVisitor { 757 | 758 | @inline(never) 759 | @_optimize(none) 760 | public func _test() { 761 | _ = self(Int.self) as Output 762 | } 763 | 764 | } 765 | 766 | public protocol BinaryIntegerVisitor: AssociatedTypeRequirementsVisitor { 767 | associatedtype Visitor = BinaryIntegerVisitor 768 | associatedtype Input = BinaryInteger 769 | associatedtype Output 770 | 771 | func callAsFunction(_ value: T) -> Output 772 | } 773 | 774 | extension BinaryIntegerVisitor { 775 | 776 | @inline(never) 777 | @_optimize(none) 778 | public func _test() { 779 | _ = self(42) as Output 780 | } 781 | 782 | } 783 | 784 | public protocol BinaryIntegerTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 785 | associatedtype Visitor = BinaryIntegerTypeVisitor 786 | associatedtype Input = BinaryInteger 787 | associatedtype Output 788 | 789 | func callAsFunction(_ type: T.Type) -> Output 790 | } 791 | 792 | extension BinaryIntegerTypeVisitor { 793 | 794 | @inline(never) 795 | @_optimize(none) 796 | public func _test() { 797 | _ = self(Int.self) as Output 798 | } 799 | 800 | } 801 | 802 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 803 | public protocol IdentifiableVisitor: AssociatedTypeRequirementsVisitor { 804 | associatedtype Visitor = IdentifiableVisitor 805 | associatedtype Input = Identifiable 806 | associatedtype Output 807 | 808 | func callAsFunction(_ value: T) -> Output 809 | } 810 | 811 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 812 | extension IdentifiableVisitor { 813 | 814 | @inline(never) 815 | @_optimize(none) 816 | public func _test() { 817 | _ = self(TestIdentifiable(id: "test")) as Output 818 | } 819 | 820 | } 821 | 822 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 823 | public protocol IdentifiableTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 824 | associatedtype Visitor = IdentifiableTypeVisitor 825 | associatedtype Input = Identifiable 826 | associatedtype Output 827 | 828 | func callAsFunction(_ type: T.Type) -> Output 829 | } 830 | 831 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 832 | extension IdentifiableTypeVisitor { 833 | 834 | @inline(never) 835 | @_optimize(none) 836 | public func _test() { 837 | _ = self(TestIdentifiable.self) as Output 838 | } 839 | 840 | } 841 | 842 | #endif 843 | 844 | // SwiftUI 845 | #if canImport(SwiftUI) 846 | import SwiftUI 847 | 848 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 849 | public protocol ViewVisitor: AssociatedTypeRequirementsVisitor { 850 | associatedtype Visitor = ViewVisitor 851 | associatedtype Input = View 852 | associatedtype Output 853 | 854 | func callAsFunction(_ value: T) -> Output 855 | } 856 | 857 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 858 | extension ViewVisitor { 859 | 860 | @inline(never) 861 | @_optimize(none) 862 | public func _test() { 863 | _ = self(EmptyView()) as Output 864 | } 865 | 866 | } 867 | 868 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 869 | public protocol ViewTypeVisitor: AssociatedTypeRequirementsTypeVisitor { 870 | associatedtype Visitor = ViewTypeVisitor 871 | associatedtype Input = View 872 | associatedtype Output 873 | 874 | func callAsFunction(_ type: T.Type) -> Output 875 | } 876 | 877 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 878 | extension ViewTypeVisitor { 879 | 880 | @inline(never) 881 | @_optimize(none) 882 | public func _test() { 883 | _ = self(EmptyView.self) as Output 884 | } 885 | 886 | } 887 | 888 | #endif 889 | -------------------------------------------------------------------------------- /Sources/AssociatedTypeRequirementsVisitor/visitors.swift.gyb: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import ProtocolType 4 | 5 | %{ 6 | import json 7 | 8 | modules = [] 9 | with open('../../commonProtocols.json') as file: 10 | modules = json.loads(file.read()) 11 | }% 12 | % for module in modules: 13 | %{ moduleName = module['module'] }% 14 | 15 | // ${moduleName} 16 | #if canImport(${moduleName}) 17 | import ${moduleName} 18 | 19 | % for type in module['types']: 20 | %{ typeName = type['name'] }% 21 | % if 'availability' in module: 22 | ${module['availability']} 23 | % elif 'availability' in type: 24 | ${type['availability']} 25 | % end 26 | public protocol ${typeName}Visitor: AssociatedTypeRequirementsVisitor { 27 | associatedtype Visitor = ${typeName}Visitor 28 | associatedtype Input = ${typeName} 29 | associatedtype Output 30 | 31 | func callAsFunction(_ value: T) -> Output 32 | } 33 | 34 | % if 'availability' in module: 35 | ${module['availability']} 36 | % elif 'availability' in type: 37 | ${type['availability']} 38 | % end 39 | extension ${typeName}Visitor { 40 | 41 | @inline(never) 42 | @_optimize(none) 43 | public func _test() { 44 | _ = self(${type['testValue']}) as Output 45 | } 46 | 47 | } 48 | 49 | % if 'availability' in module: 50 | ${module['availability']} 51 | % elif 'availability' in type: 52 | ${type['availability']} 53 | % end 54 | public protocol ${typeName}TypeVisitor: AssociatedTypeRequirementsTypeVisitor { 55 | associatedtype Visitor = ${typeName}TypeVisitor 56 | associatedtype Input = ${typeName} 57 | associatedtype Output 58 | 59 | func callAsFunction(_ type: T.Type) -> Output 60 | } 61 | 62 | % if 'availability' in module: 63 | ${module['availability']} 64 | % elif 'availability' in type: 65 | ${type['availability']} 66 | % end 67 | extension ${typeName}TypeVisitor { 68 | 69 | @inline(never) 70 | @_optimize(none) 71 | public func _test() { 72 | _ = self(${type['testType']}.self) as Output 73 | } 74 | 75 | } 76 | 77 | % end 78 | #endif 79 | % end 80 | -------------------------------------------------------------------------------- /Sources/CContext/CContext.c: -------------------------------------------------------------------------------- 1 | 2 | void set_self_pointer(void *pointer) { 3 | #ifdef __aarch64__ 4 | __asm__("mov x20, x0"); 5 | #endif 6 | #ifdef __x86_64__ 7 | __asm__("movq %rdi, %r13"); 8 | #endif 9 | } 10 | -------------------------------------------------------------------------------- /Sources/CContext/include/CContext.h: -------------------------------------------------------------------------------- 1 | 2 | void set_self_pointer(void *pointer); 3 | -------------------------------------------------------------------------------- /Sources/Casting/CastedProtocolValue.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import ProtocolConformance 4 | 5 | public struct CastedProtocolValue { 6 | let value: UnsafeRawPointer 7 | let conformanceRecord: ProtocolConformanceRecord 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Casting/withCasted.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import ProtocolConformance 4 | import ProtocolType 5 | import ValuePointers 6 | 7 | public func withCasted(_ value: Any, as moduleName: ModuleName, _ protocolName: ProtocolName, body: (CastedProtocolValue) throws -> Result) rethrows -> Result? { 8 | guard let protocolType = ProtocolType(moduleName: moduleName, protocolName: protocolName) else { return nil } 9 | return try withCasted(value, as: protocolType, body: body) 10 | } 11 | 12 | public func withCasted(_ value: Any, as protocolType: ProtocolType, body: (CastedProtocolValue) throws -> Result) rethrows -> Result? { 13 | return try withCasted(value, as: protocolType.type, body: body) 14 | } 15 | 16 | public func withCasted(_ value: Any, as protocolType: Any.Type, body: (CastedProtocolValue) throws -> Result) rethrows -> Result? { 17 | let implementationType = type(of: value) 18 | guard let conformanceRecord = ProtocolConformanceRecord(implementationType: implementationType, protocolType: protocolType) else { return nil } 19 | return try withUnsafeValuePointer(to: value) { try body(CastedProtocolValue(value: $0, conformanceRecord: conformanceRecord)) } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ProtocolConformance/ProtocolConformanceRecord.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import ProtocolType 4 | 5 | // MARK: Getting the conformance record 6 | 7 | public struct ProtocolConformanceRecord { 8 | public let type: Any.Type 9 | public let witnessTable: UnsafeRawPointer? 10 | } 11 | 12 | extension ProtocolConformanceRecord { 13 | 14 | public init?(implementationType: Any.Type, protocolType: Any.Type) { 15 | let metadata = ProtocolMetadata(type: protocolType) 16 | guard let witnessTable = _conformsToProtocol(implementationType, metadata.protocolDescriptorVector) else { return nil } 17 | self.init(type: implementationType, witnessTable: witnessTable) 18 | } 19 | 20 | } 21 | 22 | extension ProtocolConformanceRecord { 23 | 24 | public init?(implementationType: Any.Type, protocolType: ProtocolType) { 25 | self.init(implementationType: implementationType, protocolType: protocolType.type) 26 | } 27 | 28 | } 29 | 30 | // MARK: - Checking for conformance 31 | 32 | public func does(_ implementationType: Any.Type, conformTo protocolType: Any.Type) -> Bool { 33 | let metadata = ProtocolMetadata(type: protocolType) 34 | return _conformsToProtocol(implementationType, metadata.protocolDescriptorVector) != nil 35 | } 36 | 37 | public func does(_ implementationType: Any.Type, conformTo protocolType: ProtocolType) -> Bool { 38 | return does(implementationType, conformTo: protocolType.type) 39 | } 40 | 41 | // MARK: - Structure of Protocol Metadata 42 | 43 | private struct ProtocolDescriptor { } 44 | 45 | private struct ProtocolMetadata { 46 | let kind: Int 47 | let layoutFlags: UInt32 48 | let numberOfProtocols: UInt32 49 | let protocolDescriptorVector: UnsafeMutablePointer 50 | 51 | init(type: Any.Type) { 52 | self = unsafeBitCast(type, to: UnsafeMutablePointer.self).pointee 53 | } 54 | } 55 | 56 | // MARK: - Runtime functions 57 | 58 | @_silgen_name("swift_conformsToProtocol") 59 | private func _conformsToProtocol( 60 | _ type: Any.Type, 61 | _ protocolDescriptor: UnsafeMutablePointer 62 | ) -> UnsafeRawPointer? 63 | -------------------------------------------------------------------------------- /Sources/ProtocolConformance/fakeConformance.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public func fakeConformance(_ type: Any.Type, as protocolType: T.Type = T.self) -> T { 5 | let conformance = ProtocolConformanceRecord(type: type, witnessTable: nil) 6 | return unsafeBitCast(conformance, to: protocolType) 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ProtocolConformance/helpers.swift: -------------------------------------------------------------------------------- 1 | 2 | import ProtocolType 3 | 4 | // Swift 5 | public func isBinaryFloatingPoint(_ type: Any.Type) -> Bool { 6 | return does(type, conformTo: .binaryFloatingPoint) 7 | } 8 | 9 | public func isEncodable(_ type: Any.Type) -> Bool { 10 | return does(type, conformTo: .encodable) 11 | } 12 | 13 | public func isDecodable(_ type: Any.Type) -> Bool { 14 | return does(type, conformTo: .decodable) 15 | } 16 | 17 | public func isRandomNumberGenerator(_ type: Any.Type) -> Bool { 18 | return does(type, conformTo: .randomNumberGenerator) 19 | } 20 | 21 | public func isHashable(_ type: Any.Type) -> Bool { 22 | return does(type, conformTo: .hashable) 23 | } 24 | 25 | public func isNumeric(_ type: Any.Type) -> Bool { 26 | return does(type, conformTo: .numeric) 27 | } 28 | 29 | public func isBidirectionalCollection(_ type: Any.Type) -> Bool { 30 | return does(type, conformTo: .bidirectionalCollection) 31 | } 32 | 33 | public func isRandomAccessCollection(_ type: Any.Type) -> Bool { 34 | return does(type, conformTo: .randomAccessCollection) 35 | } 36 | 37 | public func isComparable(_ type: Any.Type) -> Bool { 38 | return does(type, conformTo: .comparable) 39 | } 40 | 41 | public func isCollection(_ type: Any.Type) -> Bool { 42 | return does(type, conformTo: .collection) 43 | } 44 | 45 | public func isMutableCollection(_ type: Any.Type) -> Bool { 46 | return does(type, conformTo: .mutableCollection) 47 | } 48 | 49 | public func isRangeReplaceableCollection(_ type: Any.Type) -> Bool { 50 | return does(type, conformTo: .rangeReplaceableCollection) 51 | } 52 | 53 | public func isEquatable(_ type: Any.Type) -> Bool { 54 | return does(type, conformTo: .equatable) 55 | } 56 | 57 | public func isSequence(_ type: Any.Type) -> Bool { 58 | return does(type, conformTo: .sequence) 59 | } 60 | 61 | public func isIteratorProtocol(_ type: Any.Type) -> Bool { 62 | return does(type, conformTo: .iteratorProtocol) 63 | } 64 | 65 | public func isUnsignedInteger(_ type: Any.Type) -> Bool { 66 | return does(type, conformTo: .unsignedInteger) 67 | } 68 | 69 | public func isRangeExpression(_ type: Any.Type) -> Bool { 70 | return does(type, conformTo: .rangeExpression) 71 | } 72 | 73 | public func isStrideable(_ type: Any.Type) -> Bool { 74 | return does(type, conformTo: .strideable) 75 | } 76 | 77 | public func isRawRepresentable(_ type: Any.Type) -> Bool { 78 | return does(type, conformTo: .rawRepresentable) 79 | } 80 | 81 | public func isStringProtocol(_ type: Any.Type) -> Bool { 82 | return does(type, conformTo: .stringProtocol) 83 | } 84 | 85 | public func isSignedInteger(_ type: Any.Type) -> Bool { 86 | return does(type, conformTo: .signedInteger) 87 | } 88 | 89 | public func isBinaryInteger(_ type: Any.Type) -> Bool { 90 | return does(type, conformTo: .binaryInteger) 91 | } 92 | 93 | public func isIdentifiable(_ type: Any.Type) -> Bool { 94 | return does(type, conformTo: .identifiable) 95 | } 96 | 97 | // SwiftUI 98 | public func isView(_ type: Any.Type) -> Bool { 99 | return does(type, conformTo: .view) 100 | } 101 | 102 | -------------------------------------------------------------------------------- /Sources/ProtocolConformance/helpers.swift.gyb: -------------------------------------------------------------------------------- 1 | 2 | import ProtocolType 3 | 4 | %{ 5 | import json 6 | 7 | modules = [] 8 | with open('../../commonProtocols.json') as file: 9 | modules = json.loads(file.read()) 10 | }% 11 | % for module in modules: 12 | // ${module['module']} 13 | % for type in module['types']: 14 | %{ name = type['name'] }% 15 | public func is${name}(_ type: Any.Type) -> Bool { 16 | return does(type, conformTo: .${name[0].lower()}${name[1:]}) 17 | } 18 | 19 | % end 20 | % end 21 | -------------------------------------------------------------------------------- /Sources/ProtocolType/ModuleName.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct ModuleName : RawRepresentable, Equatable { 5 | public let rawValue: String 6 | 7 | public init(rawValue: String) { 8 | self.rawValue = rawValue 9 | } 10 | } 11 | 12 | extension ModuleName : ExpressibleByStringLiteral { 13 | 14 | public init(stringLiteral value: String) { 15 | self.init(rawValue: value) 16 | } 17 | 18 | } 19 | 20 | 21 | extension ModuleName { 22 | 23 | public static let swift: ModuleName = "Swift" 24 | public static let swiftUI: ModuleName = "SwiftUI" 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Sources/ProtocolType/ModuleName.swift.gyb: -------------------------------------------------------------------------------- 1 | 2 | %{ 3 | import json 4 | 5 | modules = [] 6 | with open('../../commonProtocols.json') as file: 7 | modules = json.loads(file.read()) 8 | }% 9 | import Foundation 10 | 11 | public struct ModuleName : RawRepresentable, Equatable { 12 | public let rawValue: String 13 | 14 | public init(rawValue: String) { 15 | self.rawValue = rawValue 16 | } 17 | } 18 | 19 | extension ModuleName : ExpressibleByStringLiteral { 20 | 21 | public init(stringLiteral value: String) { 22 | self.init(rawValue: value) 23 | } 24 | 25 | } 26 | 27 | 28 | extension ModuleName { 29 | 30 | % for module in modules: 31 | %{ name = module['module'] }% 32 | public static let ${name[0].lower()}${name[1:]}: ModuleName = "${name}" 33 | % end 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Sources/ProtocolType/ProtocolName.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct ProtocolName : RawRepresentable, Equatable { 5 | public let rawValue: String 6 | 7 | public init(rawValue: String) { 8 | self.rawValue = rawValue 9 | } 10 | } 11 | 12 | extension ProtocolName : ExpressibleByStringLiteral { 13 | 14 | public init(stringLiteral value: String) { 15 | self.init(rawValue: value) 16 | } 17 | 18 | } 19 | 20 | extension ProtocolName { 21 | 22 | // Swift 23 | public static let binaryFloatingPoint: ProtocolName = "BinaryFloatingPoint" 24 | public static let encodable: ProtocolName = "Encodable" 25 | public static let decodable: ProtocolName = "Decodable" 26 | public static let randomNumberGenerator: ProtocolName = "RandomNumberGenerator" 27 | public static let hashable: ProtocolName = "Hashable" 28 | public static let numeric: ProtocolName = "Numeric" 29 | public static let bidirectionalCollection: ProtocolName = "BidirectionalCollection" 30 | public static let randomAccessCollection: ProtocolName = "RandomAccessCollection" 31 | public static let comparable: ProtocolName = "Comparable" 32 | public static let collection: ProtocolName = "Collection" 33 | public static let mutableCollection: ProtocolName = "MutableCollection" 34 | public static let rangeReplaceableCollection: ProtocolName = "RangeReplaceableCollection" 35 | public static let equatable: ProtocolName = "Equatable" 36 | public static let sequence: ProtocolName = "Sequence" 37 | public static let iteratorProtocol: ProtocolName = "IteratorProtocol" 38 | public static let unsignedInteger: ProtocolName = "UnsignedInteger" 39 | public static let rangeExpression: ProtocolName = "RangeExpression" 40 | public static let strideable: ProtocolName = "Strideable" 41 | public static let rawRepresentable: ProtocolName = "RawRepresentable" 42 | public static let stringProtocol: ProtocolName = "StringProtocol" 43 | public static let signedInteger: ProtocolName = "SignedInteger" 44 | public static let binaryInteger: ProtocolName = "BinaryInteger" 45 | public static let identifiable: ProtocolName = "Identifiable" 46 | 47 | // SwiftUI 48 | public static let view: ProtocolName = "View" 49 | } 50 | -------------------------------------------------------------------------------- /Sources/ProtocolType/ProtocolName.swift.gyb: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | %{ 5 | import json 6 | 7 | modules = [] 8 | with open('../../commonProtocols.json') as file: 9 | modules = json.loads(file.read()) 10 | }% 11 | public struct ProtocolName : RawRepresentable, Equatable { 12 | public let rawValue: String 13 | 14 | public init(rawValue: String) { 15 | self.rawValue = rawValue 16 | } 17 | } 18 | 19 | extension ProtocolName : ExpressibleByStringLiteral { 20 | 21 | public init(stringLiteral value: String) { 22 | self.init(rawValue: value) 23 | } 24 | 25 | } 26 | 27 | extension ProtocolName { 28 | % for module in modules: 29 | 30 | // ${module['module']} 31 | % for type in module['types']: 32 | %{ name = type['name'] }% 33 | public static let ${name[0].lower()}${name[1:]}: ProtocolName = "${name}" 34 | % end 35 | % end 36 | } 37 | -------------------------------------------------------------------------------- /Sources/ProtocolType/ProtocolType.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct ProtocolType { 5 | public let type: Any.Type 6 | 7 | public init?(moduleName: ModuleName, protocolName: ProtocolName) { 8 | let name = mangledName(moduleName: moduleName, protocolName: protocolName) 9 | guard let type = _typeByName(name) else { return nil } 10 | self.type = type 11 | } 12 | } 13 | 14 | extension ProtocolType { 15 | 16 | // Swift 17 | public static let binaryFloatingPoint = ProtocolType(moduleName: .swift, protocolName: .binaryFloatingPoint)! 18 | public static let encodable = ProtocolType(moduleName: .swift, protocolName: .encodable)! 19 | public static let decodable = ProtocolType(moduleName: .swift, protocolName: .decodable)! 20 | public static let randomNumberGenerator = ProtocolType(moduleName: .swift, protocolName: .randomNumberGenerator)! 21 | public static let hashable = ProtocolType(moduleName: .swift, protocolName: .hashable)! 22 | public static let numeric = ProtocolType(moduleName: .swift, protocolName: .numeric)! 23 | public static let bidirectionalCollection = ProtocolType(moduleName: .swift, protocolName: .bidirectionalCollection)! 24 | public static let randomAccessCollection = ProtocolType(moduleName: .swift, protocolName: .randomAccessCollection)! 25 | public static let comparable = ProtocolType(moduleName: .swift, protocolName: .comparable)! 26 | public static let collection = ProtocolType(moduleName: .swift, protocolName: .collection)! 27 | public static let mutableCollection = ProtocolType(moduleName: .swift, protocolName: .mutableCollection)! 28 | public static let rangeReplaceableCollection = ProtocolType(moduleName: .swift, protocolName: .rangeReplaceableCollection)! 29 | public static let equatable = ProtocolType(moduleName: .swift, protocolName: .equatable)! 30 | public static let sequence = ProtocolType(moduleName: .swift, protocolName: .sequence)! 31 | public static let iteratorProtocol = ProtocolType(moduleName: .swift, protocolName: .iteratorProtocol)! 32 | public static let unsignedInteger = ProtocolType(moduleName: .swift, protocolName: .unsignedInteger)! 33 | public static let rangeExpression = ProtocolType(moduleName: .swift, protocolName: .rangeExpression)! 34 | public static let strideable = ProtocolType(moduleName: .swift, protocolName: .strideable)! 35 | public static let rawRepresentable = ProtocolType(moduleName: .swift, protocolName: .rawRepresentable)! 36 | public static let stringProtocol = ProtocolType(moduleName: .swift, protocolName: .stringProtocol)! 37 | public static let signedInteger = ProtocolType(moduleName: .swift, protocolName: .signedInteger)! 38 | public static let binaryInteger = ProtocolType(moduleName: .swift, protocolName: .binaryInteger)! 39 | public static let identifiable = ProtocolType(moduleName: .swift, protocolName: .identifiable)! 40 | 41 | // SwiftUI 42 | public static let view = ProtocolType(moduleName: .swiftUI, protocolName: .view)! 43 | 44 | } 45 | 46 | private func mangledName(moduleName: ModuleName, protocolName: ProtocolName) -> String { 47 | 48 | switch moduleName { 49 | case .swift: 50 | switch protocolName { 51 | case .encodable: 52 | return "SE" 53 | case .decodable: 54 | return "Sd" 55 | case .randomNumberGenerator: 56 | return "SG" 57 | case .hashable: 58 | return "SH" 59 | case .numeric: 60 | return "Sj" 61 | case .bidirectionalCollection: 62 | return "SK" 63 | case .randomAccessCollection: 64 | return "Sk" 65 | case .comparable: 66 | return "SL" 67 | case .mutableCollection: 68 | return "SM" 69 | case .rangeReplaceableCollection: 70 | return "Sm" 71 | case .equatable: 72 | return "SQ" 73 | case .sequence: 74 | return "ST" 75 | case .iteratorProtocol: 76 | return "St" 77 | case .unsignedInteger: 78 | return "SU" 79 | case .rangeExpression: 80 | return "SX" 81 | case .strideable: 82 | return "Sx" 83 | case .stringProtocol: 84 | return "Sy" 85 | case .signedInteger: 86 | return "SZ" 87 | case .binaryInteger: 88 | return "Sz" 89 | default: 90 | break 91 | } 92 | default: 93 | break 94 | } 95 | 96 | return "\(moduleName.rawValue.count)\(moduleName.rawValue)\(protocolName.rawValue.count)\(protocolName.rawValue)_p" 97 | } 98 | -------------------------------------------------------------------------------- /Sources/ProtocolType/ProtocolType.swift.gyb: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | %{ 5 | import json 6 | 7 | modules = [] 8 | with open('../../commonProtocols.json') as file: 9 | modules = json.loads(file.read()) 10 | }% 11 | public struct ProtocolType { 12 | public let type: Any.Type 13 | 14 | public init?(moduleName: ModuleName, protocolName: ProtocolName) { 15 | let name = mangledName(moduleName: moduleName, protocolName: protocolName) 16 | guard let type = _typeByName(name) else { return nil } 17 | self.type = type 18 | } 19 | } 20 | 21 | extension ProtocolType { 22 | % for module in modules: 23 | %{ moduleName = module['module'] }% 24 | 25 | // ${moduleName} 26 | % for type in module['types']: 27 | %{ typeName = type['name'] }% 28 | public static let ${typeName[0].lower()}${typeName[1:]} = ProtocolType(moduleName: .${moduleName[0].lower()}${moduleName[1:]}, protocolName: .${typeName[0].lower()}${typeName[1:]})! 29 | % end 30 | % end 31 | 32 | } 33 | 34 | private func mangledName(moduleName: ModuleName, protocolName: ProtocolName) -> String { 35 | 36 | switch moduleName { 37 | % for module in modules: 38 | %{ moduleName = module['module'] }% 39 | %{ specialCases = [type for type in module['types'] if 'mangledShorthand' in type] }% 40 | % if len(specialCases) > 0: 41 | case .${moduleName[0].lower()}${moduleName[1:]}: 42 | switch protocolName { 43 | % for type in specialCases: 44 | %{ typeName = type['name'] }% 45 | case .${typeName[0].lower()}${typeName[1:]}: 46 | return "${type['mangledShorthand']}" 47 | % end 48 | default: 49 | break 50 | } 51 | % end 52 | % end 53 | default: 54 | break 55 | } 56 | 57 | return "\(moduleName.rawValue.count)\(moduleName.rawValue)\(protocolName.rawValue.count)\(protocolName.rawValue)_p" 58 | } 59 | -------------------------------------------------------------------------------- /Sources/ValuePointers/withUnsafeValuePointer.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import Foundation 4 | import ProtocolConformance 5 | 6 | /// Pointer to actual value without knowing the type at compile time. It will point to the correct part no matter how it's internal memory works 7 | public func withUnsafeValuePointer(to value: Any, body: (UnsafeRawPointer) throws -> Result) rethrows -> Result { 8 | return try pointable(for: type(of: value)).withUnsafeRawPointer(to: value, body: body) 9 | } 10 | 11 | /// Bytes of the actual value without knowing the value at compile time, even when it doesn't fit in the 32 bytes of Any 12 | public func withUnsafeValueBytes(of value: Any, body: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result { 13 | return try pointable(for: type(of: value)).withUnsafeRawBytes(of: value, body: body) 14 | } 15 | 16 | private func pointable(for type: Any.Type) -> Pointable.Type { 17 | return fakeConformance(type) 18 | } 19 | 20 | private protocol Pointable { } 21 | extension Pointable { 22 | static func withUnsafeRawPointer(to value: Any, body: (UnsafeRawPointer) throws -> Result) rethrows -> Result { 23 | return try withUnsafePointer(to: value as! Self) { try body(UnsafeRawPointer($0)) } 24 | } 25 | 26 | static func withUnsafeRawBytes(of value: Any, body: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result { 27 | return try withUnsafeBytes(of: value as! Self, body) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/AssociatedTypeRequirementsKitTests/ProtocolTypeTests.swift: -------------------------------------------------------------------------------- 1 | 2 | import XCTest 3 | import ProtocolType 4 | 5 | final class ProtocolTypeTests: XCTestCase { 6 | func testTypeIsResolved() { 7 | let type = ProtocolType(moduleName: "AssociatedTypeRequirementsKitTests", protocolName: "TestProtocol") 8 | XCTAssertNotNil(type) 9 | } 10 | 11 | func testWrongTypeIsNil() { 12 | let type = ProtocolType(moduleName: "AssociatedTypeRequirementsKitTests", protocolName: "SomeType") 13 | XCTAssertNil(type) 14 | } 15 | } 16 | 17 | protocol TestProtocol { } 18 | -------------------------------------------------------------------------------- /Tests/AssociatedTypeRequirementsKitTests/ValuePointersTests.swift: -------------------------------------------------------------------------------- 1 | 2 | import XCTest 3 | import ValuePointers 4 | 5 | final class ValuePointersTests: XCTestCase { 6 | struct BigStruct { 7 | let first: String 8 | let second: String 9 | let third: String 10 | let fourth: String 11 | let fifth: String 12 | let sixth: String 13 | } 14 | 15 | func testBytesAreCorrect() { 16 | let value = BigStruct(first: "1", second: "2", third: "3", fourth: "4", fifth: "5", sixth: "6") 17 | let normalCount = withUnsafeBytes(of: value) { $0.count } 18 | let anyCount = withUnsafeBytes(of: value as Any) { $0.count } 19 | let ourCount = withUnsafeValueBytes(of: value) { $0.count } 20 | 21 | XCTAssertNotEqual(normalCount, anyCount) 22 | XCTAssertEqual(normalCount, ourCount) 23 | 24 | let thirdString = withUnsafeValueBytes(of: value) { $0.baseAddress!.advanced(by: 2 * MemoryLayout.size).load(as: String.self) } 25 | XCTAssertEqual(thirdString, "3") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/AssociatedTypeRequirementsKitTests/VisitorTests.swift: -------------------------------------------------------------------------------- 1 | 2 | import XCTest 3 | import AssociatedTypeRequirementsVisitor 4 | 5 | #if canImport(SwiftUI) 6 | import SwiftUI 7 | #endif 8 | 9 | final class VisitorTests: XCTestCase { 10 | func testVisitDecodableType() { 11 | let type: Any.Type = SomeDedecodable.self 12 | let json = """ 13 | { 14 | "a": "A", 15 | "b": "B" 16 | } 17 | """ 18 | let value = JSONDecoder().decodeIfPossible(type, from: json.data(using: .utf8)!) 19 | XCTAssertNotNil(value) 20 | } 21 | 22 | func testVisitHashable() { 23 | let value = "String" 24 | let hashed = value.hashValue 25 | let hasher = AnyHasher() 26 | let recledtedHash = hasher(value as Any) 27 | XCTAssertNotNil(recledtedHash) 28 | XCTAssertEqual(hashed, recledtedHash) 29 | } 30 | 31 | #if canImport(SwiftUI) 32 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 33 | func testVisitView() { 34 | let value: Any = Text("One two three four") 35 | let eraser = ViewTypeEraser() 36 | let anyView = eraser(value) 37 | XCTAssertNotNil(anyView) 38 | XCTAssertNil(eraser(123)) 39 | } 40 | #endif 41 | } 42 | 43 | struct SomeDedecodable: Decodable { 44 | let a: String 45 | let b: String 46 | } 47 | 48 | extension JSONDecoder { 49 | 50 | func decodeIfPossible(_ type: Any.Type, from data: Data) -> Any? { 51 | let visitor = JSONDecoderVisitor(decoder: self, data: data) 52 | return visitor(type) 53 | } 54 | 55 | } 56 | 57 | private struct JSONDecoderVisitor: DecodableTypeVisitor { 58 | let decoder: JSONDecoder 59 | let data: Data 60 | 61 | func callAsFunction(_ type: T.Type) -> Any { 62 | return try! decoder.decode(type, from: data) 63 | } 64 | } 65 | 66 | struct AnyHasher: HashableVisitor { 67 | func callAsFunction(_ value: T) -> Int { 68 | var hasher = Hasher() 69 | value.hash(into: &hasher) 70 | return hasher.finalize() 71 | } 72 | } 73 | 74 | #if canImport(SwiftUI) 75 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) 76 | struct ViewTypeEraser: ViewVisitor { 77 | 78 | func callAsFunction(_ value: T) -> AnyView { 79 | if let value = value as? AnyView { 80 | return value 81 | } 82 | return AnyView(value) 83 | } 84 | 85 | } 86 | #endif 87 | -------------------------------------------------------------------------------- /Tests/AssociatedTypeRequirementsKitTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | #if !canImport(ObjectiveC) 2 | import XCTest 3 | 4 | extension ProtocolTypeTests { 5 | // DO NOT MODIFY: This is autogenerated, use: 6 | // `swift test --generate-linuxmain` 7 | // to regenerate. 8 | static let __allTests__ProtocolTypeTests = [ 9 | ("testTypeIsResolved", testTypeIsResolved), 10 | ("testWrongTypeIsNil", testWrongTypeIsNil), 11 | ] 12 | } 13 | 14 | extension ValuePointersTests { 15 | // DO NOT MODIFY: This is autogenerated, use: 16 | // `swift test --generate-linuxmain` 17 | // to regenerate. 18 | static let __allTests__ValuePointersTests = [ 19 | ("testBytesAreCorrect", testBytesAreCorrect), 20 | ] 21 | } 22 | 23 | extension VisitorTests { 24 | // DO NOT MODIFY: This is autogenerated, use: 25 | // `swift test --generate-linuxmain` 26 | // to regenerate. 27 | static let __allTests__VisitorTests = [ 28 | ("testVisitDecodableType", testVisitDecodableType), 29 | ("testVisitHashable", testVisitHashable), 30 | // ("testVisitView", testVisitView), 31 | ] 32 | } 33 | 34 | public func __allTests() -> [XCTestCaseEntry] { 35 | return [ 36 | testCase(ProtocolTypeTests.__allTests__ProtocolTypeTests), 37 | testCase(ValuePointersTests.__allTests__ValuePointersTests), 38 | testCase(VisitorTests.__allTests__VisitorTests), 39 | ] 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import AssociatedTypeRequirementsKitTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += AssociatedTypeRequirementsKitTests.__allTests() 7 | 8 | XCTMain(tests) 9 | -------------------------------------------------------------------------------- /commonProtocols.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "module" : "Swift", 4 | "types" : [ 5 | { 6 | "name" : "BinaryFloatingPoint", 7 | "mangledName" : "SB", 8 | "testType": "Double", 9 | "testValue": "42.0" 10 | }, 11 | { 12 | "name" : "Encodable", 13 | "mangledShorthand" : "SE", 14 | "testType": "Int", 15 | "testValue": "42" 16 | }, 17 | { 18 | "name" : "Decodable", 19 | "mangledShorthand" : "Sd", 20 | "testType": "Int", 21 | "testValue": "42" 22 | }, 23 | { 24 | "name" : "RandomNumberGenerator", 25 | "mangledShorthand" : "SG", 26 | "testType": "SystemRandomNumberGenerator", 27 | "testValue": "SystemRandomNumberGenerator()" 28 | }, 29 | { 30 | "name" : "Hashable", 31 | "mangledShorthand" : "SH", 32 | "testType": "Int", 33 | "testValue": "42" 34 | }, 35 | { 36 | "name" : "Numeric", 37 | "mangledShorthand" : "Sj", 38 | "testType": "Int", 39 | "testValue": "42" 40 | }, 41 | { 42 | "name" : "BidirectionalCollection", 43 | "mangledShorthand" : "SK", 44 | "testType": "Array", 45 | "testValue": "[42]" 46 | }, 47 | { 48 | "name" : "RandomAccessCollection", 49 | "mangledShorthand" : "Sk", 50 | "testType": "Array", 51 | "testValue": "[42]" 52 | }, 53 | { 54 | "name" : "Comparable", 55 | "mangledShorthand" : "SL", 56 | "testType": "Int", 57 | "testValue": "42" 58 | }, 59 | { 60 | "name" : "Collection", 61 | "mangledName" : "Sl", 62 | "testType": "Array", 63 | "testValue": "[42]" 64 | }, 65 | { 66 | "name" : "MutableCollection", 67 | "mangledShorthand" : "SM", 68 | "testType": "Array", 69 | "testValue": "[42]" 70 | }, 71 | { 72 | "name" : "RangeReplaceableCollection", 73 | "mangledShorthand" : "Sm", 74 | "testType": "Array", 75 | "testValue": "[42]" 76 | }, 77 | { 78 | "name" : "Equatable", 79 | "mangledShorthand" : "SQ", 80 | "testType": "Int", 81 | "testValue": "42" 82 | }, 83 | { 84 | "name" : "Sequence", 85 | "mangledShorthand" : "ST", 86 | "testType": "Array", 87 | "testValue": "[42]" 88 | }, 89 | { 90 | "name" : "IteratorProtocol", 91 | "mangledShorthand" : "St", 92 | "testType": "Array.Iterator", 93 | "testValue": "[42].makeIterator()" 94 | }, 95 | { 96 | "name" : "UnsignedInteger", 97 | "mangledShorthand" : "SU", 98 | "testType": "UInt", 99 | "testValue": "42 as UInt" 100 | }, 101 | { 102 | "name" : "RangeExpression", 103 | "mangledShorthand" : "SX", 104 | "testType": "Range", 105 | "testValue": "0..<1" 106 | }, 107 | { 108 | "name" : "Strideable", 109 | "mangledShorthand" : "Sx", 110 | "testType": "Double", 111 | "testValue": "42.0" 112 | }, 113 | { 114 | "name" : "RawRepresentable", 115 | "mangledName" : "SY", 116 | "testType": "TestRawRepresentable.self", 117 | "testValue": "TestRawRepresentable.test" 118 | }, 119 | { 120 | "name" : "StringProtocol", 121 | "mangledShorthand" : "Sy", 122 | "testType": "String", 123 | "testValue": "\"\"" 124 | }, 125 | { 126 | "name" : "SignedInteger", 127 | "mangledShorthand" : "SZ", 128 | "testType": "Int", 129 | "testValue": "42" 130 | }, 131 | { 132 | "name" : "BinaryInteger", 133 | "mangledShorthand" : "Sz", 134 | "testType": "Int", 135 | "testValue": "42" 136 | }, 137 | { 138 | "name" : "Identifiable", 139 | "availability" : "@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)", 140 | "testType": "TestIdentifiable", 141 | "testValue": "TestIdentifiable(id: \"test\")" 142 | } 143 | ] 144 | }, 145 | { 146 | "module": "SwiftUI", 147 | "availability" : "@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)", 148 | "types" : [ 149 | { 150 | "name" : "View", 151 | "testType": "EmptyView", 152 | "testValue": "EmptyView()" 153 | } 154 | ] 155 | } 156 | ] 157 | -------------------------------------------------------------------------------- /swift-error-message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdsupremacist/AssociatedTypeRequirementsKit/2e4c49c21ffb2135f1c99fbfcf2119c9d24f5e8c/swift-error-message.png -------------------------------------------------------------------------------- /useGYB: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find . -name '*.gyb' | \ 4 | while read file; do \ 5 | gyb --line-directive '' -o "${file%.gyb}" "$file"; \ 6 | done 7 | --------------------------------------------------------------------------------