An easy-to-host PDS on the ATProtocol, iPhone and MacOS. Maintain control of your keys and data, always.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(identity-wallet): patch swift-rs to pass --disable-sandbox on macOS 26

authored by

Malpercio and committed by
Tangled
d201e889 f11b75e6

+2123 -5
+9
Cargo.toml
··· 80 80 common = { path = "crates/common" } 81 81 crypto = { path = "crates/crypto" } 82 82 repo-engine = { path = "crates/repo-engine" } 83 + 84 + # ── Local patches ───────────────────────────────────────────────────────────── 85 + # 86 + # swift-rs 1.0.7 does not pass --disable-sandbox to `swift build`. On macOS 26 87 + # (Tahoe), sandbox_apply() returns EPERM during manifest compilation, breaking 88 + # the Tauri ios-api build step. The local patch adds --disable-sandbox. 89 + # Remove when swift-rs ships a fix upstream. 90 + [patch.crates-io] 91 + swift-rs = { path = "apps/identity-wallet/swift-rs-patch" }
+1 -1
apps/identity-wallet/CLAUDE.md
··· 242 242 243 243 Swift Package Manager sandboxes its manifest compilation using `sandbox-exec`. On macOS 26 (Tahoe), `sandbox_apply()` returns `EPERM` in this context, causing `swift-rs`'s build script (used by Tauri) to fail with "Failed to compile swift package Tauri". 244 244 245 - **Fix:** Already resolved. `src-tauri/.cargo/config.toml` sets `SWIFTPM_ENABLE_SANDBOX = "0"` in `[env]`, which tells SPM not to apply a sandbox when compiling `Package.swift` manifests. This is inherited by the `tauri` build script's child `swift` process. 245 + **Fix:** Already resolved. A local patch of `swift-rs` 1.0.7 at `apps/identity-wallet/swift-rs-patch/` adds `--disable-sandbox` to the `swift build` invocation inside `SwiftLinker::link`. The workspace `Cargo.toml` wires this in via `[patch.crates-io]`. Remove the patch entry when swift-rs ships a fix upstream. 246 246 247 247 --- 248 248
-4
apps/identity-wallet/src-tauri/.cargo/config.toml
··· 13 13 14 14 [env] 15 15 RUST_TEST_THREADS = "1" 16 - # Swift Package Manager uses sandbox-exec to sandbox manifest compilation. 17 - # On macOS 26 (Tahoe), sandbox_apply() returns EPERM, failing the Tauri ios-api 18 - # build step. Disabling the SPM sandbox is safe for local dev builds. 19 - SWIFTPM_ENABLE_SANDBOX = "0" 20 16 CC_aarch64_apple_ios_sim = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" 21 17 CC_aarch64_apple_ios = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" 22 18 CC_aarch64_apple_darwin = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"
+1
apps/identity-wallet/swift-rs-patch/.cargo-ok
··· 1 + {"v":1}
+6
apps/identity-wallet/swift-rs-patch/.cargo_vcs_info.json
··· 1 + { 2 + "git": { 3 + "sha1": "f64a4514de07f450ec5b6aa297624cd3479d9579" 4 + }, 5 + "path_in_vcs": "" 6 + }
+1
apps/identity-wallet/swift-rs-patch/.gitattributes
··· 1 + example/* linguist-vendored
+38
apps/identity-wallet/swift-rs-patch/.github/workflows/main.yaml
··· 1 + name: Build 2 + 3 + on: 4 + push: 5 + branches: [ master ] 6 + pull_request: 7 + 8 + env: 9 + CARGO_TERM_COLOR: always 10 + RUST_BACKTRACE: 1 11 + 12 + jobs: 13 + build: 14 + name: Build 15 + runs-on: macos-latest 16 + strategy: 17 + matrix: 18 + rust: [stable, beta] 19 + steps: 20 + - uses: actions/checkout@v3 21 + name: Checkout 22 + - name: Install specific rust version 23 + run: | 24 + rustup install ${{ matrix.rust }} --profile minimal 25 + rustup component add --toolchain ${{ matrix.rust }} rustfmt clippy 26 + - name: Setup cache 27 + uses: Swatinem/rust-cache@v2 28 + - name: Test example 29 + working-directory: example 30 + run: cargo +${{ matrix.rust }} run 31 + - name: Run Tests 32 + env: 33 + TEST_SWIFT_RS: "true" 34 + run: cargo +${{ matrix.rust }} test --features build 35 + - name: Check Code Formatting 36 + run: cargo +${{ matrix.rust }} fmt --all -- --check 37 + - name: Lints 38 + run: cargo +${{ matrix.rust }} clippy -- -D warnings
+7
apps/identity-wallet/swift-rs-patch/.gitignore
··· 1 + .build/ 2 + target/ 3 + .swiftpm/ 4 + .idea/ 5 + .DS_Store 6 + icon.txt 7 + **/Cargo.lock
+73
apps/identity-wallet/swift-rs-patch/Cargo.toml
··· 1 + # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO 2 + # 3 + # When uploading crates to the registry Cargo will automatically 4 + # "normalize" Cargo.toml files for maximal compatibility 5 + # with all versions of Cargo and also rewrite `path` dependencies 6 + # to registry (e.g., crates.io) dependencies. 7 + # 8 + # If you are reading this file be aware that the original Cargo.toml 9 + # will likely look very different (and much more reasonable). 10 + # See Cargo.toml.orig for the original contents. 11 + 12 + [package] 13 + edition = "2021" 14 + name = "swift-rs" 15 + version = "1.0.7" 16 + authors = ["The swift-rs contributors"] 17 + build = "src-rs/test-build.rs" 18 + exclude = [ 19 + "/src-swift", 20 + "*.swift", 21 + ] 22 + autobins = false 23 + autoexamples = false 24 + autotests = false 25 + autobenches = false 26 + description = "Call Swift from Rust with ease!" 27 + readme = "README.md" 28 + license = "MIT OR Apache-2.0" 29 + repository = "https://github.com/Brendonovich/swift-rs" 30 + 31 + [package.metadata."docs.rs"] 32 + all-features = true 33 + rustdoc-args = [ 34 + "--cfg", 35 + "docsrs", 36 + ] 37 + 38 + [lib] 39 + name = "swift_rs" 40 + path = "src-rs/lib.rs" 41 + 42 + [[test]] 43 + name = "test_bindings" 44 + path = "tests/test_bindings.rs" 45 + 46 + [dependencies.base64] 47 + version = "0.21.0" 48 + 49 + [dependencies.serde] 50 + version = "1.0" 51 + features = ["derive"] 52 + optional = true 53 + 54 + [dependencies.serde_json] 55 + version = "1.0" 56 + optional = true 57 + 58 + [dev-dependencies.serial_test] 59 + version = "0.10" 60 + 61 + [build-dependencies.serde] 62 + version = "1.0" 63 + features = ["derive"] 64 + 65 + [build-dependencies.serde_json] 66 + version = "1.0" 67 + 68 + [features] 69 + build = [ 70 + "serde", 71 + "serde_json", 72 + ] 73 + default = []
+34
apps/identity-wallet/swift-rs-patch/Cargo.toml.orig
··· 1 + [package] 2 + name = "swift-rs" 3 + version = "1.0.7" 4 + description = "Call Swift from Rust with ease!" 5 + authors = ["The swift-rs contributors"] 6 + license = "MIT OR Apache-2.0" 7 + repository = "https://github.com/Brendonovich/swift-rs" 8 + edition = "2021" 9 + exclude=["/src-swift", "*.swift"] 10 + build = "src-rs/test-build.rs" 11 + 12 + # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features 13 + [package.metadata."docs.rs"] 14 + all-features = true 15 + rustdoc-args = ["--cfg", "docsrs"] 16 + 17 + [lib] 18 + path = "src-rs/lib.rs" 19 + 20 + [dependencies] 21 + base64 = "0.21.0" 22 + serde = { version = "1.0", features = ["derive"], optional = true} 23 + serde_json = { version = "1.0", optional = true } 24 + 25 + [build-dependencies] 26 + serde = { version = "1.0", features = ["derive"]} 27 + serde_json = { version = "1.0" } 28 + 29 + [dev-dependencies] 30 + serial_test = "0.10" 31 + 32 + [features] 33 + default = [] 34 + build = ["serde", "serde_json"]
+201
apps/identity-wallet/swift-rs-patch/LICENSE-APACHE
··· 1 + Apache License 2 + Version 2.0, January 2004 3 + http://www.apache.org/licenses/ 4 + 5 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 + 7 + 1. Definitions. 8 + 9 + "License" shall mean the terms and conditions for use, reproduction, 10 + and distribution as defined by Sections 1 through 9 of this document. 11 + 12 + "Licensor" shall mean the copyright owner or entity authorized by 13 + the copyright owner that is granting the License. 14 + 15 + "Legal Entity" shall mean the union of the acting entity and all 16 + other entities that control, are controlled by, or are under common 17 + control with that entity. For the purposes of this definition, 18 + "control" means (i) the power, direct or indirect, to cause the 19 + direction or management of such entity, whether by contract or 20 + otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 + outstanding shares, or (iii) beneficial ownership of such entity. 22 + 23 + "You" (or "Your") shall mean an individual or Legal Entity 24 + exercising permissions granted by this License. 25 + 26 + "Source" form shall mean the preferred form for making modifications, 27 + including but not limited to software source code, documentation 28 + source, and configuration files. 29 + 30 + "Object" form shall mean any form resulting from mechanical 31 + transformation or translation of a Source form, including but 32 + not limited to compiled object code, generated documentation, 33 + and conversions to other media types. 34 + 35 + "Work" shall mean the work of authorship, whether in Source or 36 + Object form, made available under the License, as indicated by a 37 + copyright notice that is included in or attached to the work 38 + (an example is provided in the Appendix below). 39 + 40 + "Derivative Works" shall mean any work, whether in Source or Object 41 + form, that is based on (or derived from) the Work and for which the 42 + editorial revisions, annotations, elaborations, or other modifications 43 + represent, as a whole, an original work of authorship. For the purposes 44 + of this License, Derivative Works shall not include works that remain 45 + separable from, or merely link (or bind by name) to the interfaces of, 46 + the Work and Derivative Works thereof. 47 + 48 + "Contribution" shall mean any work of authorship, including 49 + the original version of the Work and any modifications or additions 50 + to that Work or Derivative Works thereof, that is intentionally 51 + submitted to Licensor for inclusion in the Work by the copyright owner 52 + or by an individual or Legal Entity authorized to submit on behalf of 53 + the copyright owner. For the purposes of this definition, "submitted" 54 + means any form of electronic, verbal, or written communication sent 55 + to the Licensor or its representatives, including but not limited to 56 + communication on electronic mailing lists, source code control systems, 57 + and issue tracking systems that are managed by, or on behalf of, the 58 + Licensor for the purpose of discussing and improving the Work, but 59 + excluding communication that is conspicuously marked or otherwise 60 + designated in writing by the copyright owner as "Not a Contribution." 61 + 62 + "Contributor" shall mean Licensor and any individual or Legal Entity 63 + on behalf of whom a Contribution has been received by Licensor and 64 + subsequently incorporated within the Work. 65 + 66 + 2. Grant of Copyright License. Subject to the terms and conditions of 67 + this License, each Contributor hereby grants to You a perpetual, 68 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 + copyright license to reproduce, prepare Derivative Works of, 70 + publicly display, publicly perform, sublicense, and distribute the 71 + Work and such Derivative Works in Source or Object form. 72 + 73 + 3. Grant of Patent License. Subject to the terms and conditions of 74 + this License, each Contributor hereby grants to You a perpetual, 75 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 + (except as stated in this section) patent license to make, have made, 77 + use, offer to sell, sell, import, and otherwise transfer the Work, 78 + where such license applies only to those patent claims licensable 79 + by such Contributor that are necessarily infringed by their 80 + Contribution(s) alone or by combination of their Contribution(s) 81 + with the Work to which such Contribution(s) was submitted. If You 82 + institute patent litigation against any entity (including a 83 + cross-claim or counterclaim in a lawsuit) alleging that the Work 84 + or a Contribution incorporated within the Work constitutes direct 85 + or contributory patent infringement, then any patent licenses 86 + granted to You under this License for that Work shall terminate 87 + as of the date such litigation is filed. 88 + 89 + 4. Redistribution. You may reproduce and distribute copies of the 90 + Work or Derivative Works thereof in any medium, with or without 91 + modifications, and in Source or Object form, provided that You 92 + meet the following conditions: 93 + 94 + (a) You must give any other recipients of the Work or 95 + Derivative Works a copy of this License; and 96 + 97 + (b) You must cause any modified files to carry prominent notices 98 + stating that You changed the files; and 99 + 100 + (c) You must retain, in the Source form of any Derivative Works 101 + that You distribute, all copyright, patent, trademark, and 102 + attribution notices from the Source form of the Work, 103 + excluding those notices that do not pertain to any part of 104 + the Derivative Works; and 105 + 106 + (d) If the Work includes a "NOTICE" text file as part of its 107 + distribution, then any Derivative Works that You distribute must 108 + include a readable copy of the attribution notices contained 109 + within such NOTICE file, excluding those notices that do not 110 + pertain to any part of the Derivative Works, in at least one 111 + of the following places: within a NOTICE text file distributed 112 + as part of the Derivative Works; within the Source form or 113 + documentation, if provided along with the Derivative Works; or, 114 + within a display generated by the Derivative Works, if and 115 + wherever such third-party notices normally appear. The contents 116 + of the NOTICE file are for informational purposes only and 117 + do not modify the License. You may add Your own attribution 118 + notices within Derivative Works that You distribute, alongside 119 + or as an addendum to the NOTICE text from the Work, provided 120 + that such additional attribution notices cannot be construed 121 + as modifying the License. 122 + 123 + You may add Your own copyright statement to Your modifications and 124 + may provide additional or different license terms and conditions 125 + for use, reproduction, or distribution of Your modifications, or 126 + for any such Derivative Works as a whole, provided Your use, 127 + reproduction, and distribution of the Work otherwise complies with 128 + the conditions stated in this License. 129 + 130 + 5. Submission of Contributions. Unless You explicitly state otherwise, 131 + any Contribution intentionally submitted for inclusion in the Work 132 + by You to the Licensor shall be under the terms and conditions of 133 + this License, without any additional terms or conditions. 134 + Notwithstanding the above, nothing herein shall supersede or modify 135 + the terms of any separate license agreement you may have executed 136 + with Licensor regarding such Contributions. 137 + 138 + 6. Trademarks. This License does not grant permission to use the trade 139 + names, trademarks, service marks, or product names of the Licensor, 140 + except as required for reasonable and customary use in describing the 141 + origin of the Work and reproducing the content of the NOTICE file. 142 + 143 + 7. Disclaimer of Warranty. Unless required by applicable law or 144 + agreed to in writing, Licensor provides the Work (and each 145 + Contributor provides its Contributions) on an "AS IS" BASIS, 146 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 + implied, including, without limitation, any warranties or conditions 148 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 + PARTICULAR PURPOSE. You are solely responsible for determining the 150 + appropriateness of using or redistributing the Work and assume any 151 + risks associated with Your exercise of permissions under this License. 152 + 153 + 8. Limitation of Liability. In no event and under no legal theory, 154 + whether in tort (including negligence), contract, or otherwise, 155 + unless required by applicable law (such as deliberate and grossly 156 + negligent acts) or agreed to in writing, shall any Contributor be 157 + liable to You for damages, including any direct, indirect, special, 158 + incidental, or consequential damages of any character arising as a 159 + result of this License or out of the use or inability to use the 160 + Work (including but not limited to damages for loss of goodwill, 161 + work stoppage, computer failure or malfunction, or any and all 162 + other commercial damages or losses), even if such Contributor 163 + has been advised of the possibility of such damages. 164 + 165 + 9. Accepting Warranty or Additional Liability. While redistributing 166 + the Work or Derivative Works thereof, You may choose to offer, 167 + and charge a fee for, acceptance of support, warranty, indemnity, 168 + or other liability obligations and/or rights consistent with this 169 + License. However, in accepting such obligations, You may act only 170 + on Your own behalf and on Your sole responsibility, not on behalf 171 + of any other Contributor, and only if You agree to indemnify, 172 + defend, and hold each Contributor harmless for any liability 173 + incurred by, or claims asserted against, such Contributor by reason 174 + of your accepting any such warranty or additional liability. 175 + 176 + END OF TERMS AND CONDITIONS 177 + 178 + APPENDIX: How to apply the Apache License to your work. 179 + 180 + To apply the Apache License to your work, attach the following 181 + boilerplate notice, with the fields enclosed by brackets "{}" 182 + replaced with your own identifying information. (Don't include 183 + the brackets!) The text should be enclosed in the appropriate 184 + comment syntax for the file format. We also recommend that a 185 + file or class name and description of purpose be included on the 186 + same "printed page" as the copyright notice for easier 187 + identification within third-party archives. 188 + 189 + Copyright 2023 The swift-rs developers 190 + 191 + Licensed under the Apache License, Version 2.0 (the "License"); 192 + you may not use this file except in compliance with the License. 193 + You may obtain a copy of the License at 194 + 195 + http://www.apache.org/licenses/LICENSE-2.0 196 + 197 + Unless required by applicable law or agreed to in writing, software 198 + distributed under the License is distributed on an "AS IS" BASIS, 199 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 + See the License for the specific language governing permissions and 201 + limitations under the License.
+19
apps/identity-wallet/swift-rs-patch/LICENSE-MIT
··· 1 + Copyright (c) 2023 The swift-rs Developers 2 + 3 + Permission is hereby granted, free of charge, to any person obtaining a copy 4 + of this software and associated documentation files (the "Software"), to deal 5 + in the Software without restriction, including without limitation the rights 6 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 + copies of the Software, and to permit persons to whom the Software is 8 + furnished to do so, subject to the following conditions: 9 + 10 + The above copyright notice and this permission notice shall be included in all 11 + copies or substantial portions of the Software. 12 + 13 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 + SOFTWARE.
+483
apps/identity-wallet/swift-rs-patch/README.md
··· 1 + # swift-rs 2 + 3 + ![Crates.io](https://img.shields.io/crates/v/swift-rs?color=blue&style=flat-square) 4 + ![docs.rs](https://img.shields.io/docsrs/swift-rs?color=blue&style=flat-square) 5 + 6 + Call Swift functions from Rust with ease! 7 + 8 + ## Setup 9 + 10 + Add `swift-rs` to your project's `dependencies` and `build-dependencies`: 11 + 12 + ```toml 13 + [dependencies] 14 + swift-rs = "1.0.5" 15 + 16 + [build-dependencies] 17 + swift-rs = { version = "1.0.5", features = ["build"] } 18 + ``` 19 + 20 + Next, some setup work must be done: 21 + 22 + 1. Ensure your swift code is organized into a Swift Package. 23 + This can be done in XCode by selecting File -> New -> Project -> Multiplatform -> Swift Package and importing your existing code. 24 + 2. Add `SwiftRs` as a dependency to your Swift package and make the build type `.static`. 25 + ```swift 26 + let package = Package( 27 + dependencies: [ 28 + .package(url: "https://github.com/Brendonovich/swift-rs", from: "1.0.5") 29 + ], 30 + products: [ 31 + .library( 32 + type: .static, 33 + ), 34 + ], 35 + targets: [ 36 + .target( 37 + // Must specify swift-rs as a dependency of your target 38 + dependencies: [ 39 + .product( 40 + name: "SwiftRs", 41 + package: "swift-rs" 42 + ) 43 + ], 44 + ) 45 + ] 46 + ) 47 + ``` 48 + 3. Create a `build.rs` file in your project's root folder, if you don't have one already. 49 + 4. Use `SwiftLinker` in your `build.rs` file to link both the Swift runtime and your Swift package. 50 + The package name should be the same as is specified in your `Package.swift` file, 51 + and the path should point to your Swift project's root folder relative to your crate's root folder. 52 + 53 + ```rust 54 + use swift_rs::SwiftLinker; 55 + 56 + fn build() { 57 + // swift-rs has a minimum of macOS 10.13 58 + // Ensure the same minimum supported macOS version is specified as in your `Package.swift` file. 59 + SwiftLinker::new("10.13") 60 + // Only if you are also targetting iOS 61 + // Ensure the same minimum supported iOS version is specified as in your `Package.swift` file 62 + .with_ios("11") 63 + .with_package(PACKAGE_NAME, PACKAGE_PATH) 64 + .link(); 65 + 66 + // Other build steps 67 + } 68 + ``` 69 + 70 + With those steps completed, you should be ready to start using Swift code from Rust! 71 + 72 + If you experience the error `dyld[16008]: Library not loaded: @rpath/libswiftCore.dylib` 73 + when using `swift-rs` with [Tauri](https://tauri.app) ensure you have set your 74 + [Tauri minimum system version](https://tauri.app/v1/guides/building/macos#setting-a-minimum-system-version) 75 + to `10.15` or higher in your `tauri.config.json`. 76 + 77 + ## Calling basic functions 78 + 79 + To allow calling a Swift function from Rust, it must follow some rules: 80 + 81 + 1. It must be global 82 + 2. It must be annotated with `@_cdecl`, so that it is callable from C 83 + 3. It must only use types that can be represented in Objective-C, 84 + so only classes that derive `NSObject`, as well as scalars such as Int and Bool. 85 + This excludes strings, arrays, generics (though all of these can be sent with workarounds) 86 + and structs (which are strictly forbidden). 87 + 88 + For this example we will use a function that simply squares a number: 89 + 90 + ```swift 91 + public func squareNumber(number: Int) -> Int { 92 + return number * number 93 + } 94 + ``` 95 + 96 + So far, this function meets requirements 1 and 3: it is global and public, and only uses the Int type, which is Objective-C compatible. 97 + However, it is not annotated with `@_cdecl`. 98 + To fix this, we must call `@_cdecl` before the function's declaration and specify the name that the function is exposed to Rust with as its only argument. 99 + To keep with Rust's naming conventions, we will export this function in snake case as `square_number`. 100 + 101 + ```swift 102 + @_cdecl("square_number") 103 + public func squareNumber(number: Int) -> Int { 104 + return number * number 105 + } 106 + ``` 107 + 108 + Now that `squareNumber` is properly exposed to Rust, we can start interfacing with it. 109 + This can be done using the `swift!` macro, with the `Int` type helping to provide a similar function signature: 110 + 111 + ```rust 112 + use swift_rs::swift; 113 + 114 + swift!(fn square_number(number: Int) -> Int); 115 + ``` 116 + 117 + Lastly, you can call the function from regular Rust functions. 118 + Note that <b>all</b> calls to a Swift function are unsafe, 119 + and require wrapping in an `unsafe {}` block or `unsafe fn`. 120 + 121 + ```rust 122 + fn main() { 123 + let input: Int = 4; 124 + let output = unsafe { square_number(input) }; 125 + 126 + println!("Input: {}, Squared: {}", input, output); 127 + // Prints "Input: 4, Squared: 16" 128 + } 129 + ``` 130 + 131 + Check [the documentation](TODO) for all available helper types. 132 + 133 + ## Returning objects from Swift 134 + 135 + Let's say that we want our `squareNumber` function to return not only the result, but also the original input. 136 + A standard way to do this in Swift would be with a struct: 137 + 138 + ```swift 139 + struct SquareNumberResult { 140 + var input: Int 141 + var output: Int 142 + } 143 + ``` 144 + 145 + We are not allowed to do this, though, since structs cannot be represented in Objective-C. 146 + Instead, we must use a class that extends `NSObject`: 147 + 148 + ```swift 149 + class SquareNumberResult: NSObject { 150 + var input: Int 151 + var output: Int 152 + 153 + init(_ input: Int, _ output: Int) { 154 + self.input = input; 155 + self.output = output 156 + } 157 + } 158 + ``` 159 + 160 + <sub><sup>Yes, this class could contain the squaring logic too, but that is irrelevant for this example 161 + 162 + An instance of this class can then be returned from `squareNumber`: 163 + 164 + ```swift 165 + @_cdecl("square_number") 166 + public func squareNumber(input: Int) -> SquareNumberResult { 167 + let output = input * input 168 + return SquareNumberResult(input, output) 169 + } 170 + ``` 171 + 172 + As you can see, returning an `NSObject` from Swift isn't too difficult. 173 + The same can't be said for the Rust implementation, though. 174 + `squareNumber` doesn't actually return a struct containing `input` and `output`, 175 + but instead a pointer to a `SquareNumberResult` stored somewhere in memory. 176 + Additionally, this value contains more data than just `input` and `output`: 177 + Since it is an `NSObject`, it contains extra data that must be accounted for when using it in Rust. 178 + 179 + This may sound daunting, but it's not actually a problem thanks to `SRObject<T>`. 180 + This type manages the pointer internally, and takes a generic argument for a struct that we can access the data through. 181 + Let's see how we'd implement `SquareNumberResult` in Rust: 182 + 183 + ```rust 184 + use swift_rs::{swift, Int, SRObject}; 185 + 186 + // Any struct that is used in a C function must be annotated 187 + // with this, and since our Swift function is exposed as a 188 + // C function with @_cdecl, this is necessary here 189 + #[repr(C)] 190 + // Struct matches the class declaration in Swift 191 + struct SquareNumberResult { 192 + input: Int, 193 + output: Int 194 + } 195 + 196 + // SRObject abstracts away the underlying pointer and will automatically deref to 197 + // &SquareNumberResult through the Deref trait 198 + swift!(fn square_number(input: Int) -> SRObject<SquareNumberResult>); 199 + ``` 200 + 201 + Then, using the new return value is just like using `SquareNumberResult` directly: 202 + 203 + ```rust 204 + fn main() { 205 + let input = 4; 206 + let result = unsafe { square_number(input) }; 207 + 208 + let result_input = result.input; // 4 209 + let result_output = result.output; // 16 210 + } 211 + ``` 212 + 213 + Creating objects in Rust and then passing them to Swift is not supported. 214 + 215 + ## Optionals 216 + 217 + `swift-rs` also supports Swift's `nil` type, but only for functions that return optional `NSObject`s. 218 + Functions returning optional primitives cannot be represented in Objective C, and thus are not supported. 219 + 220 + Let's say we have a function returning an optional `SRString`: 221 + 222 + ```swift 223 + @_cdecl("optional_string") 224 + func optionalString(returnNil: Bool) -> SRString? { 225 + if (returnNil) return nil 226 + else return SRString("lorem ipsum") 227 + } 228 + ``` 229 + 230 + Thanks to Rust's [null pointer optimisation](https://doc.rust-lang.org/std/option/index.html#representation), 231 + the optional nature of `SRString?` can be represented by wrapping `SRString` in Rust's `Option<T>` type! 232 + 233 + ```rust 234 + use swift_rs::{swift, Bool, SRString}; 235 + 236 + swift!(optional_string(return_nil: Bool) -> Option<SRString>) 237 + ``` 238 + 239 + Null pointers are actually the reason why a function that returns an optional primitive cannot be represented in C. 240 + If this were to be supported, how could a `nil` be differentiated from a number? It can't! 241 + 242 + ## Complex types 243 + 244 + So far we have only looked at using primitive types and structs/classes, 245 + but this leaves out some of the most important data structures: arrays (`SRArray<T>`) and strings (`SRString`). 246 + These types must be treated with caution, however, and are not as flexible as their native Swift & Rust counterparts. 247 + 248 + ### Strings 249 + 250 + Strings can be passed between Rust and Swift through `SRString`, which can be created from native strings in either language. 251 + 252 + **As an argument** 253 + 254 + ```swift 255 + import SwiftRs 256 + 257 + @_cdecl("swift_print") 258 + public func swiftPrint(value: SRString) { 259 + // .to_string() converts the SRString to a Swift String 260 + print(value.to_string()) 261 + } 262 + ``` 263 + 264 + ```rust 265 + use swift_rs::{swift, SRString, SwiftRef}; 266 + 267 + swift!(fn swift_print(value: &SRString)); 268 + 269 + fn main() { 270 + // SRString can be created by simply calling .into() on any string reference. 271 + // This will allocate memory in Swift and copy the string 272 + let value: SRString = "lorem ipsum".into(); 273 + 274 + unsafe { swift_print(&value) }; // Will print "lorem ipsum" to the console 275 + } 276 + ``` 277 + 278 + **As a return value** 279 + 280 + ```swift 281 + import SwiftRs 282 + 283 + @_cdecl("get_string") 284 + public func getString() -> SRString { 285 + let value = "lorem ipsum" 286 + 287 + // SRString can be created from a regular String 288 + return SRString(value) 289 + } 290 + ``` 291 + 292 + ```rust 293 + use swift_rs::{swift, SRString}; 294 + 295 + swift!(fn get_string() -> SRString); 296 + 297 + fn main() { 298 + let value_srstring = unsafe { get_string() }; 299 + 300 + // SRString can be converted to an &str using as_str()... 301 + let value_str: &str = value_srstring.as_str(); 302 + // or though the Deref trait 303 + let value_str: &str = &*value_srstring; 304 + 305 + // SRString also implements Display 306 + println!("{}", value_srstring); // Will print "lorem ipsum" to the console 307 + } 308 + ``` 309 + 310 + ### Arrays 311 + 312 + **Primitive Arrays** 313 + 314 + Representing arrays properly is tricky, since we cannot use generics as Swift arguments or return values according to rule 3. 315 + Instead, `swift-rs` provides a generic `SRArray<T>` that can be embedded inside another class that extends `NSObject` that is not generic, 316 + but is restricted to a single element type. 317 + 318 + ```swift 319 + import SwiftRs 320 + 321 + // Argument/Return values can contain generic types, but cannot be generic themselves. 322 + // This includes extending generic types. 323 + class IntArray: NSObject { 324 + var data: SRArray<Int> 325 + 326 + init(_ data: [Int]) { 327 + self.data = SRArray(data) 328 + } 329 + } 330 + 331 + @_cdecl("get_numbers") 332 + public func getNumbers() -> IntArray { 333 + let numbers = [1, 2, 3, 4] 334 + 335 + return IntArray(numbers) 336 + } 337 + ``` 338 + 339 + ```rust 340 + use swift_rs::{Int, SRArray, SRObject}; 341 + 342 + #[repr(C)] 343 + struct IntArray { 344 + data: SRArray<Int> 345 + } 346 + 347 + // Since IntArray extends NSObject in its Swift implementation, 348 + // it must be wrapped in SRObject on the Rust side 349 + swift!(fn get_numbers() -> SRObject<IntArray>); 350 + 351 + fn main() { 352 + let numbers = unsafe { get_numbers() }; 353 + 354 + // SRArray can be accessed as a slice via as_slice 355 + let numbers_slice: &[Int] = numbers.data.as_slice(); 356 + 357 + assert_eq!(numbers_slice, &[1, 2, 3, 4]); 358 + } 359 + ``` 360 + 361 + To simplify things on the rust side, we can actually do away with the `IntArray` struct. 362 + Since `IntArray` only has one field, its memory layout is identical to that of `SRArray<usize>`, 363 + so our Rust implementation can be simplified at the cost of equivalence with our Swift code: 364 + 365 + ```rust 366 + // We still need to wrap the array in SRObject since 367 + // the wrapper class in Swift is an NSObject 368 + swift!(fn get_numbers() -> SRObject<SRArray<Int>>); 369 + ``` 370 + 371 + **NSObject Arrays** 372 + 373 + What if we want to return an `NSObject` array? There are two options on the Swift side: 374 + 375 + 1. Continue using `SRArray` and a custom wrapper type, or 376 + 2. Use `SRObjectArray`, a wrapper type provided by `swift-rs` that accepts any `NSObject` as its elements. 377 + This can be easier than continuing to create wrapper types, but sacrifices some type safety. 378 + 379 + There is also `SRObjectArray<T>` for Rust, which is compatible with any single-element Swift wrapper type (and of course `SRObjectArray` in Swift), 380 + and automatically wraps its elements in `SRObject<T>`, so there's very little reason to not use it unless you _really_ like custom wrapper types. 381 + 382 + Using `SRObjectArray` in both Swift and Rust with a basic custom class/struct can be done like this: 383 + 384 + ```swift 385 + import SwiftRs 386 + 387 + class IntTuple: NSObject { 388 + var item1: Int 389 + var item2: Int 390 + 391 + init(_ item1: Int, _ item2: Int) { 392 + self.item1 = item1 393 + self.item2 = item2 394 + } 395 + } 396 + 397 + @_cdecl("get_tuples") 398 + public func getTuples() -> SRObjectArray { 399 + let tuple1 = IntTuple(0,1), 400 + tuple2 = IntTuple(2,3), 401 + tuple3 = IntTuple(4,5) 402 + 403 + let tupleArray: [IntTuple] = [ 404 + tuple1, 405 + tuple2, 406 + tuple3 407 + ] 408 + 409 + // Type safety is only lost when the Swift array is converted to an SRObjectArray 410 + return SRObjectArray(tupleArray) 411 + } 412 + ``` 413 + 414 + ```rust 415 + use swift_rs::{swift, Int, SRObjectArray}; 416 + 417 + #[repr(C)] 418 + struct IntTuple { 419 + item1: Int, 420 + item2: Int 421 + } 422 + 423 + // No need to wrap IntTuple in SRObject<T> since 424 + // SRObjectArray<T> does it automatically 425 + swift!(fn get_tuples() -> SRObjectArray<IntTuple>); 426 + 427 + fn main() { 428 + let tuples = unsafe { get_tuples() }; 429 + 430 + for tuple in tuples.as_slice() { 431 + // Will print each tuple's contents to the console 432 + println!("Item 1: {}, Item 2: {}", tuple.item1, tuple.item2); 433 + } 434 + } 435 + ``` 436 + 437 + Complex types can contain whatever combination of primitives and `SRObject<T>` you like, just remember to follow the 3 rules! 438 + 439 + ## Bonuses 440 + 441 + ### SRData 442 + 443 + A wrapper type for `SRArray<T>` designed for storing `u8`s - essentially just a byte buffer. 444 + 445 + ### Tighter Memory Control with `autoreleasepool!` 446 + 447 + If you've come to Swift from an Objective-C background, you likely know the utility of `@autoreleasepool` blocks. 448 + `swift-rs` has your back on this too, just wrap your block of code with a `autoreleasepool!`, and that block of code now executes with its own autorelease pool! 449 + 450 + ```rust 451 + use swift_rs::autoreleasepool; 452 + 453 + for _ in 0..10000 { 454 + autoreleasepool!({ 455 + // do some memory intensive thing here 456 + }); 457 + } 458 + ``` 459 + 460 + ## Limitations 461 + 462 + Currently, the only types that can be created from Rust are number types, boolean, `SRString`, and `SRData`. 463 + This is because those types are easy to allocate memory for, either on the stack or on the heap via calling out to swift, 464 + whereas other types are not. This may be implemented in the future, though. 465 + 466 + Mutating values across Swift and Rust is not currently an aim for this library, it is purely for providing arguments and returning values. 467 + Besides, this would go against Rust's programming model, potentially allowing for multiple shared references to a value instead of interior mutability via something like a Mutex. 468 + 469 + ## License 470 + 471 + Licensed under either of 472 + 473 + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 474 + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 475 + 476 + at your option. 477 + 478 + ### Contribution 479 + 480 + Unless you explicitly state otherwise, any contribution intentionally 481 + submitted for inclusion in the work by you, as defined in the Apache-2.0 482 + license, shall be dual licensed as above, without any additional terms or 483 + conditions.
+26
apps/identity-wallet/swift-rs-patch/src-rs/autorelease.rs
··· 1 + /// Run code with its own autorelease pool. Semantically, this is identical 2 + /// to [`@autoreleasepool`](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html) 3 + /// in Objective-C 4 + /// 5 + /// 6 + /// ```no_run 7 + /// use swift_rs::autoreleasepool; 8 + /// 9 + /// autoreleasepool!({ 10 + /// // do something memory intensive stuff 11 + /// }) 12 + /// ``` 13 + #[macro_export] 14 + macro_rules! autoreleasepool { 15 + ( $expr:expr ) => {{ 16 + extern "C" { 17 + fn objc_autoreleasePoolPush() -> *mut std::ffi::c_void; 18 + fn objc_autoreleasePoolPop(context: *mut std::ffi::c_void); 19 + } 20 + 21 + let pool = unsafe { objc_autoreleasePoolPush() }; 22 + let r = { $expr }; 23 + unsafe { objc_autoreleasePoolPop(pool) }; 24 + r 25 + }}; 26 + }
+325
apps/identity-wallet/swift-rs-patch/src-rs/build.rs
··· 1 + #![allow(dead_code)] 2 + use std::{env, fmt::Display, path::Path, path::PathBuf, process::Command}; 3 + 4 + use serde::Deserialize; 5 + 6 + #[derive(Debug, Deserialize)] 7 + #[serde(rename_all = "camelCase")] 8 + struct SwiftTarget { 9 + triple: String, 10 + unversioned_triple: String, 11 + module_triple: String, 12 + //pub swift_runtime_compatibility_version: String, 13 + #[serde(rename = "librariesRequireRPath")] 14 + libraries_require_rpath: bool, 15 + } 16 + 17 + #[derive(Debug, Deserialize)] 18 + #[serde(rename_all = "camelCase")] 19 + struct SwiftPaths { 20 + runtime_library_paths: Vec<String>, 21 + runtime_library_import_paths: Vec<String>, 22 + runtime_resource_path: String, 23 + } 24 + 25 + #[derive(Deserialize)] 26 + struct SwiftEnv { 27 + target: SwiftTarget, 28 + paths: SwiftPaths, 29 + } 30 + 31 + impl SwiftEnv { 32 + fn new(minimum_macos_version: &str, minimum_ios_version: Option<&str>) -> Self { 33 + let rust_target = RustTarget::from_env(); 34 + let target = rust_target.swift_target_triple(minimum_macos_version, minimum_ios_version); 35 + 36 + let swift_target_info_str = Command::new("swift") 37 + .args(["-target", &target, "-print-target-info"]) 38 + .output() 39 + .unwrap() 40 + .stdout; 41 + 42 + serde_json::from_slice(&swift_target_info_str).unwrap() 43 + } 44 + } 45 + 46 + #[allow(clippy::upper_case_acronyms)] 47 + enum RustTargetOS { 48 + MacOS, 49 + IOS, 50 + } 51 + 52 + impl RustTargetOS { 53 + fn from_env() -> Self { 54 + match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() { 55 + "macos" => RustTargetOS::MacOS, 56 + "ios" => RustTargetOS::IOS, 57 + _ => panic!("unexpected target operating system"), 58 + } 59 + } 60 + 61 + fn to_swift(&self) -> &'static str { 62 + match self { 63 + Self::MacOS => "macosx", 64 + Self::IOS => "ios", 65 + } 66 + } 67 + } 68 + 69 + impl Display for RustTargetOS { 70 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 71 + match self { 72 + Self::MacOS => write!(f, "macos"), 73 + Self::IOS => write!(f, "ios"), 74 + } 75 + } 76 + } 77 + 78 + #[allow(clippy::upper_case_acronyms)] 79 + enum SwiftSDK { 80 + MacOS, 81 + IOS, 82 + IOSSimulator, 83 + } 84 + 85 + impl SwiftSDK { 86 + fn from_os(os: &RustTargetOS) -> Self { 87 + let target = env::var("TARGET").unwrap(); 88 + let simulator = target.ends_with("ios-sim") 89 + || (target.starts_with("x86_64") && target.ends_with("ios")); 90 + 91 + match os { 92 + RustTargetOS::MacOS => Self::MacOS, 93 + RustTargetOS::IOS if simulator => Self::IOSSimulator, 94 + RustTargetOS::IOS => Self::IOS, 95 + } 96 + } 97 + 98 + fn clang_lib_extension(&self) -> &'static str { 99 + match self { 100 + Self::MacOS => "osx", 101 + Self::IOS => "ios", 102 + Self::IOSSimulator => "iossim", 103 + } 104 + } 105 + } 106 + 107 + impl Display for SwiftSDK { 108 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 109 + match self { 110 + Self::MacOS => write!(f, "macosx"), 111 + Self::IOSSimulator => write!(f, "iphonesimulator"), 112 + Self::IOS => write!(f, "iphoneos"), 113 + } 114 + } 115 + } 116 + 117 + struct RustTarget { 118 + arch: String, 119 + os: RustTargetOS, 120 + sdk: SwiftSDK, 121 + } 122 + 123 + impl RustTarget { 124 + fn from_env() -> Self { 125 + let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); 126 + let os = RustTargetOS::from_env(); 127 + let sdk = SwiftSDK::from_os(&os); 128 + 129 + Self { arch, os, sdk } 130 + } 131 + 132 + fn swift_target_triple( 133 + &self, 134 + minimum_macos_version: &str, 135 + minimum_ios_version: Option<&str>, 136 + ) -> String { 137 + let unversioned = self.unversioned_swift_target_triple(); 138 + format!( 139 + "{unversioned}{}{}", 140 + match (&self.os, minimum_ios_version) { 141 + (RustTargetOS::MacOS, _) => minimum_macos_version, 142 + (RustTargetOS::IOS, Some(version)) => version, 143 + _ => "", 144 + }, 145 + // simulator suffix 146 + matches!(self.sdk, SwiftSDK::IOSSimulator) 147 + .then(|| "-simulator".to_string()) 148 + .unwrap_or_default() 149 + ) 150 + } 151 + 152 + fn unversioned_swift_target_triple(&self) -> String { 153 + format!( 154 + "{}-apple-{}", 155 + match self.arch.as_str() { 156 + "aarch64" => "arm64", 157 + a => a, 158 + }, 159 + self.os.to_swift(), 160 + ) 161 + } 162 + } 163 + 164 + struct SwiftPackage { 165 + name: String, 166 + path: PathBuf, 167 + } 168 + 169 + /// Builder for linking the Swift runtime and custom packages. 170 + #[cfg(feature = "build")] 171 + pub struct SwiftLinker { 172 + packages: Vec<SwiftPackage>, 173 + macos_min_version: String, 174 + ios_min_version: Option<String>, 175 + } 176 + 177 + impl SwiftLinker { 178 + /// Creates a new [`SwiftLinker`] with a minimum macOS verison. 179 + /// 180 + /// Minimum macOS version must be at least 10.13. 181 + pub fn new(macos_min_version: &str) -> Self { 182 + Self { 183 + packages: vec![], 184 + macos_min_version: macos_min_version.to_string(), 185 + ios_min_version: None, 186 + } 187 + } 188 + 189 + /// Instructs the [`SwiftLinker`] to also compile for iOS 190 + /// using the specified minimum iOS version. 191 + /// 192 + /// Minimum iOS version must be at least 11. 193 + pub fn with_ios(mut self, min_version: &str) -> Self { 194 + self.ios_min_version = Some(min_version.to_string()); 195 + self 196 + } 197 + 198 + /// Adds a package to be linked against. 199 + /// `name` should match the `name` field in your `Package.swift`, 200 + /// and `path` should point to the root of your Swift package relative 201 + /// to your crate's root. 202 + pub fn with_package(mut self, name: &str, path: impl AsRef<Path>) -> Self { 203 + self.packages.extend([SwiftPackage { 204 + name: name.to_string(), 205 + path: path.as_ref().into(), 206 + }]); 207 + 208 + self 209 + } 210 + 211 + /// Links the Swift runtime, then builds and links the provided packages. 212 + /// This does not (yet) automatically rebuild your Swift files when they are modified, 213 + /// you'll need to modify/save your `build.rs` file for that. 214 + pub fn link(self) { 215 + let swift_env = SwiftEnv::new(&self.macos_min_version, self.ios_min_version.as_deref()); 216 + 217 + #[allow(clippy::uninlined_format_args)] 218 + for path in swift_env.paths.runtime_library_paths { 219 + println!("cargo:rustc-link-search=native={path}"); 220 + } 221 + 222 + let debug = env::var("DEBUG").unwrap() == "true"; 223 + let configuration = if debug { "debug" } else { "release" }; 224 + let rust_target = RustTarget::from_env(); 225 + 226 + link_clang_rt(&rust_target); 227 + 228 + for package in self.packages { 229 + let package_path = 230 + Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join(&package.path); 231 + let out_path = Path::new(&env::var("OUT_DIR").unwrap()) 232 + .join("swift-rs") 233 + .join(&package.name); 234 + 235 + let sdk_path_output = Command::new("xcrun") 236 + .args(["--sdk", &rust_target.sdk.to_string(), "--show-sdk-path"]) 237 + .output() 238 + .unwrap(); 239 + if !sdk_path_output.status.success() { 240 + panic!( 241 + "Failed to get SDK path with `xcrun --sdk {} --show-sdk-path`", 242 + rust_target.sdk 243 + ); 244 + } 245 + 246 + let sdk_path = String::from_utf8_lossy(&sdk_path_output.stdout); 247 + 248 + let mut command = Command::new("swift"); 249 + command.current_dir(&package.path); 250 + 251 + let arch = match std::env::consts::ARCH { 252 + "aarch64" => "arm64", 253 + arch => arch, 254 + }; 255 + 256 + let swift_target_triple = rust_target 257 + .swift_target_triple(&self.macos_min_version, self.ios_min_version.as_deref()); 258 + 259 + command 260 + // Build the package (duh) 261 + .arg("build") 262 + // On macOS 26 (Tahoe), sandbox_apply() returns EPERM when SPM tries to 263 + // sandbox manifest compilation. Disable the sandbox to allow the build. 264 + .arg("--disable-sandbox") 265 + // SDK path for regular compilation (idk) 266 + .args(["--sdk", sdk_path.trim()]) 267 + // Release/Debug configuration 268 + .args(["-c", configuration]) 269 + .args(["--arch", arch]) 270 + // Where the artifacts will be generated to 271 + .args(["--build-path", &out_path.display().to_string()]) 272 + // Override SDK path for each swiftc instance. 273 + // Necessary for iOS compilation. 274 + .args(["-Xswiftc", "-sdk"]) 275 + .args(["-Xswiftc", sdk_path.trim()]) 276 + // Override target triple for each swiftc instance. 277 + // Necessary for iOS compilation. 278 + .args(["-Xswiftc", "-target"]) 279 + .args(["-Xswiftc", &swift_target_triple]) 280 + .args(["-Xcc", &format!("--target={swift_target_triple}")]) 281 + .args(["-Xcxx", &format!("--target={swift_target_triple}")]); 282 + 283 + if !command.status().unwrap().success() { 284 + panic!("Failed to compile swift package {}", package.name); 285 + } 286 + 287 + let search_path = out_path 288 + // swift build uses this output folder no matter what is the target 289 + .join(format!("{}-apple-macosx", arch)) 290 + .join(configuration); 291 + 292 + println!("cargo:rerun-if-changed={}", package_path.display()); 293 + println!("cargo:rustc-link-search=native={}", search_path.display()); 294 + println!("cargo:rustc-link-lib=static={}", package.name); 295 + } 296 + } 297 + } 298 + 299 + fn link_clang_rt(rust_target: &RustTarget) { 300 + println!( 301 + "cargo:rustc-link-lib=clang_rt.{}", 302 + rust_target.sdk.clang_lib_extension() 303 + ); 304 + println!("cargo:rustc-link-search={}", clang_link_search_path()); 305 + } 306 + 307 + fn clang_link_search_path() -> String { 308 + let output = std::process::Command::new( 309 + std::env::var("SWIFT_RS_CLANG").unwrap_or_else(|_| "/usr/bin/clang".to_string()), 310 + ) 311 + .arg("--print-search-dirs") 312 + .output() 313 + .unwrap(); 314 + if !output.status.success() { 315 + panic!("Can't get search paths from clang"); 316 + } 317 + let stdout = String::from_utf8_lossy(&output.stdout); 318 + for line in stdout.lines() { 319 + if line.contains("libraries: =") { 320 + let path = line.split('=').nth(1).unwrap(); 321 + return format!("{}/lib/darwin", path); 322 + } 323 + } 324 + panic!("clang is missing search paths"); 325 + }
+90
apps/identity-wallet/swift-rs-patch/src-rs/dark_magic.rs
··· 1 + /// This retain-balancing algorithm is cool but likely isn't required. 2 + /// I'm keeping it around in case it's necessary one day. 3 + 4 + // #[derive(Clone, Copy, Debug)] 5 + // enum ValueArity { 6 + // Reference, 7 + // Value, 8 + // } 9 + 10 + // pub unsafe fn balance_ptrs(args: Vec<(*const c_void, bool)>, ret: Vec<(*const c_void, bool)>) { 11 + // fn collect_references( 12 + // v: Vec<(*const c_void, bool)>, 13 + // ) -> BTreeMap<*const c_void, Vec<ValueArity>> { 14 + // v.into_iter().fold( 15 + // BTreeMap::<_, Vec<ValueArity>>::new(), 16 + // |mut map, (ptr, is_ref)| { 17 + // map.entry(ptr).or_default().push(if is_ref { 18 + // ValueArity::Reference 19 + // } else { 20 + // ValueArity::Value 21 + // }); 22 + // map 23 + // }, 24 + // ) 25 + // } 26 + 27 + // let mut args = collect_references(args); 28 + // let mut ret = collect_references(ret); 29 + 30 + // let both_counts = args 31 + // .clone() 32 + // .into_iter() 33 + // .flat_map(|(arg, values)| { 34 + // ret.remove(&arg).map(|ret| { 35 + // args.remove(&arg); 36 + 37 + // let ret_values = ret 38 + // .iter() 39 + // .filter(|v| matches!(v, ValueArity::Value)) 40 + // .count() as isize; 41 + 42 + // let arg_references = values 43 + // .iter() 44 + // .filter(|v| matches!(v, ValueArity::Reference)) 45 + // .count() as isize; 46 + 47 + // let ref_in_value_out_retains = min(ret_values, arg_references); 48 + 49 + // (arg, ref_in_value_out_retains) 50 + // }) 51 + // }) 52 + // .collect::<Vec<_>>(); 53 + 54 + // let arg_counts = args.into_iter().map(|(ptr, values)| { 55 + // let count = values 56 + // .into_iter() 57 + // .filter(|v| matches!(v, ValueArity::Value)) 58 + // .count() as isize; 59 + // (ptr, count) 60 + // }); 61 + 62 + // let ret_counts = ret 63 + // .into_iter() 64 + // .map(|(ptr, values)| { 65 + // let count = values 66 + // .into_iter() 67 + // .filter(|v| matches!(v, ValueArity::Value)) 68 + // .count() as isize; 69 + // (ptr, count) 70 + // }) 71 + // .collect::<Vec<_>>(); 72 + 73 + // both_counts 74 + // .into_iter() 75 + // .chain(arg_counts) 76 + // .chain(ret_counts) 77 + // .for_each(|(ptr, count)| match count { 78 + // 0 => {} 79 + // n if n > 0 => { 80 + // for _ in 0..n { 81 + // retain_object(ptr) 82 + // } 83 + // } 84 + // n => { 85 + // for _ in n..0 { 86 + // release_object(ptr) 87 + // } 88 + // } 89 + // }); 90 + // }
+20
apps/identity-wallet/swift-rs-patch/src-rs/lib.rs
··· 1 + //! Call Swift functions from Rust with ease! 2 + #![cfg_attr(docsrs, feature(doc_cfg))] 3 + 4 + mod autorelease; 5 + mod swift; 6 + mod swift_arg; 7 + mod swift_ret; 8 + mod types; 9 + 10 + pub use autorelease::*; 11 + pub use swift::*; 12 + pub use swift_arg::*; 13 + pub use swift_ret::*; 14 + pub use types::*; 15 + 16 + #[cfg(feature = "build")] 17 + #[cfg_attr(docsrs, doc(cfg(feature = "build")))] 18 + mod build; 19 + #[cfg(feature = "build")] 20 + pub use build::*;
+101
apps/identity-wallet/swift-rs-patch/src-rs/swift.rs
··· 1 + use std::ffi::c_void; 2 + 3 + use crate::*; 4 + 5 + /// Reference to an `NSObject` for internal use by [`swift!`]. 6 + #[must_use = "A Ref MUST be sent over to the Swift side"] 7 + #[repr(transparent)] 8 + pub struct SwiftRef<'a, T: SwiftObject>(&'a SRObjectImpl<T::Shape>); 9 + 10 + impl<'a, T: SwiftObject> SwiftRef<'a, T> { 11 + pub(crate) unsafe fn retain(&self) { 12 + retain_object(self.0 as *const _ as *const c_void) 13 + } 14 + } 15 + 16 + /// A type that is represented as an `NSObject` in Swift. 17 + pub trait SwiftObject { 18 + type Shape; 19 + 20 + /// Gets a reference to the `SRObject` at the root of a `SwiftObject` 21 + fn get_object(&self) -> &SRObject<Self::Shape>; 22 + 23 + /// Creates a [`SwiftRef`] for an object which can be used when calling a Swift function. 24 + /// This function should never be called manually, 25 + /// instead you should rely on the [`swift!`] macro to call it for you. 26 + /// 27 + /// # Safety 28 + /// This function converts the [`NonNull`](std::ptr::NonNull) 29 + /// inside an [`SRObject`] into a reference, 30 + /// implicitly assuming that the pointer is still valid. 31 + /// The inner pointer is private, 32 + /// and the returned [`SwiftRef`] is bound to the lifetime of the original [`SRObject`], 33 + /// so if you use `swift-rs` as normal this function should be safe. 34 + unsafe fn swift_ref(&self) -> SwiftRef<Self> 35 + where 36 + Self: Sized, 37 + { 38 + SwiftRef(self.get_object().0.as_ref()) 39 + } 40 + 41 + /// Adds a retain to an object. 42 + /// 43 + /// # Safety 44 + /// Just don't call this, let [`swift!`] handle it for you. 45 + unsafe fn retain(&self) 46 + where 47 + Self: Sized, 48 + { 49 + self.swift_ref().retain() 50 + } 51 + } 52 + 53 + swift!(pub(crate) fn retain_object(obj: *const c_void)); 54 + swift!(pub(crate) fn release_object(obj: *const c_void)); 55 + swift!(pub(crate) fn data_from_bytes(data: *const u8, size: Int) -> SRData); 56 + swift!(pub(crate) fn string_from_bytes(data: *const u8, size: Int) -> SRString); 57 + 58 + /// Declares a function defined in a swift library. 59 + /// As long as this macro is used, retain counts of arguments 60 + /// and return values will be correct. 61 + /// 62 + /// Use this macro as if the contents were going directly 63 + /// into an `extern "C"` block. 64 + /// 65 + /// ``` 66 + /// use swift_rs::*; 67 + /// 68 + /// swift!(fn echo(string: &SRString) -> SRString); 69 + /// 70 + /// let string: SRString = "test".into(); 71 + /// let result = unsafe { echo(&string) }; 72 + /// 73 + /// assert_eq!(result.as_str(), string.as_str()) 74 + /// ``` 75 + /// 76 + /// # Details 77 + /// 78 + /// Internally this macro creates a wrapping function around an `extern "C"` block 79 + /// that represents the actual Swift function. This is done in order to restrict the types 80 + /// that can be used as arguments and return types, and to ensure that retain counts of returned 81 + /// values are appropriately balanced. 82 + #[macro_export] 83 + macro_rules! swift { 84 + ($vis:vis fn $name:ident $(<$($lt:lifetime),+>)? ($($arg:ident: $arg_ty:ty),*) $(-> $ret:ty)?) => { 85 + $vis unsafe fn $name $(<$($lt),*>)? ($($arg: $arg_ty),*) $(-> $ret)? { 86 + extern "C" { 87 + fn $name $(<$($lt),*>)? ($($arg: <$arg_ty as $crate::SwiftArg>::ArgType),*) $(-> $ret)?; 88 + } 89 + 90 + let res = { 91 + $(let $arg = $crate::SwiftArg::as_arg(&$arg);)* 92 + 93 + $name($($arg),*) 94 + }; 95 + 96 + $crate::SwiftRet::retain(&res); 97 + 98 + res 99 + } 100 + }; 101 + }
+75
apps/identity-wallet/swift-rs-patch/src-rs/swift_arg.rs
··· 1 + use std::ffi::c_void; 2 + 3 + use crate::{swift::SwiftObject, *}; 4 + 5 + /// Identifies a type as being a valid argument in a Swift function. 6 + pub trait SwiftArg<'a> { 7 + type ArgType; 8 + 9 + /// Creates a swift-compatible version of the argument. 10 + /// For primitives this just returns `self`, 11 + /// but for [`SwiftObject`] types it wraps them in [`SwiftRef`]. 12 + /// 13 + /// This function is called within the [`swift!`] macro. 14 + /// 15 + /// # Safety 16 + /// 17 + /// Creating a [`SwiftRef`] is inherently unsafe, 18 + /// but is reliable if using the [`swift!`] macro, 19 + /// so it is not advised to call this function manually. 20 + unsafe fn as_arg(&'a self) -> Self::ArgType; 21 + } 22 + 23 + macro_rules! primitive_impl { 24 + ($($t:ty),+) => { 25 + $(impl<'a> SwiftArg<'a> for $t { 26 + type ArgType = $t; 27 + 28 + unsafe fn as_arg(&'a self) -> Self::ArgType { 29 + *self 30 + } 31 + })+ 32 + }; 33 + } 34 + 35 + primitive_impl!( 36 + Bool, 37 + Int, 38 + Int8, 39 + Int16, 40 + Int32, 41 + Int64, 42 + UInt, 43 + UInt8, 44 + UInt16, 45 + UInt32, 46 + UInt64, 47 + Float32, 48 + Float64, 49 + *const c_void, 50 + *mut c_void, 51 + *const u8, 52 + () 53 + ); 54 + 55 + macro_rules! ref_impl { 56 + ($($t:ident $(<$($gen:ident),+>)?),+) => { 57 + $(impl<'a $($(, $gen: 'a),+)?> SwiftArg<'a> for $t$(<$($gen),+>)? { 58 + type ArgType = SwiftRef<'a, $t$(<$($gen),+>)?>; 59 + 60 + unsafe fn as_arg(&'a self) -> Self::ArgType { 61 + self.swift_ref() 62 + } 63 + })+ 64 + }; 65 + } 66 + 67 + ref_impl!(SRObject<T>, SRArray<T>, SRData, SRString); 68 + 69 + impl<'a, T: SwiftArg<'a>> SwiftArg<'a> for &T { 70 + type ArgType = T::ArgType; 71 + 72 + unsafe fn as_arg(&'a self) -> Self::ArgType { 73 + (*self).as_arg() 74 + } 75 + }
+55
apps/identity-wallet/swift-rs-patch/src-rs/swift_ret.rs
··· 1 + use crate::{swift::SwiftObject, *}; 2 + use std::ffi::c_void; 3 + 4 + /// Identifies a type as being a valid return type from a Swift function. 5 + /// For types that are objects which need extra retains, 6 + /// the [`retain`](SwiftRet::retain) function will be re-implemented. 7 + pub trait SwiftRet { 8 + /// Adds a retain to the value if possible 9 + /// 10 + /// # Safety 11 + /// Just don't use this. 12 + /// Let [`swift!`] handle it. 13 + unsafe fn retain(&self) {} 14 + } 15 + 16 + macro_rules! primitive_impl { 17 + ($($t:ty),+) => { 18 + $(impl SwiftRet for $t { 19 + })+ 20 + }; 21 + } 22 + 23 + primitive_impl!( 24 + Bool, 25 + Int, 26 + Int8, 27 + Int16, 28 + Int32, 29 + Int64, 30 + UInt, 31 + UInt8, 32 + UInt16, 33 + UInt32, 34 + UInt64, 35 + Float32, 36 + Float64, 37 + *const c_void, 38 + *mut c_void, 39 + *const u8, 40 + () 41 + ); 42 + 43 + impl<T: SwiftObject> SwiftRet for Option<T> { 44 + unsafe fn retain(&self) { 45 + if let Some(v) = self { 46 + v.retain() 47 + } 48 + } 49 + } 50 + 51 + impl<T: SwiftObject> SwiftRet for T { 52 + unsafe fn retain(&self) { 53 + (*self).retain() 54 + } 55 + }
+20
apps/identity-wallet/swift-rs-patch/src-rs/test-build.rs
··· 1 + //! Build script for swift-rs that is a no-op for normal builds, but can be enabled 2 + //! to include test swift library based on env var `TEST_SWIFT_RS=true` with the 3 + //! `build` feature being enabled. 4 + 5 + #[cfg(feature = "build")] 6 + mod build; 7 + 8 + fn main() { 9 + println!("cargo:rerun-if-env-changed=TEST_SWIFT_RS"); 10 + 11 + #[cfg(feature = "build")] 12 + if std::env::var("TEST_SWIFT_RS").unwrap_or_else(|_| "false".into()) == "true" { 13 + use build::SwiftLinker; 14 + 15 + SwiftLinker::new("10.15") 16 + .with_ios("11") 17 + .with_package("test-swift", "tests/swift-pkg") 18 + .link(); 19 + } 20 + }
+110
apps/identity-wallet/swift-rs-patch/src-rs/types/array.rs
··· 1 + use std::{ops::Deref, ptr::NonNull}; 2 + 3 + use crate::swift::SwiftObject; 4 + 5 + use super::SRObject; 6 + 7 + /// Wrapper of [`SRArray`] exclusively for arrays of objects. 8 + /// Equivalent to `SRObjectArray` in Swift. 9 + // SRArray is wrapped in SRObject since the Swift implementation extends NSObject 10 + pub type SRObjectArray<T> = SRObject<SRArray<SRObject<T>>>; 11 + 12 + #[doc(hidden)] 13 + #[repr(C)] 14 + pub struct SRArrayImpl<T> { 15 + data: NonNull<T>, 16 + length: usize, 17 + } 18 + 19 + /// General array type for objects and scalars. 20 + /// 21 + /// ## Returning Directly 22 + /// 23 + /// When returning an `SRArray` from a Swift function, 24 + /// you will need to wrap it in an `NSObject` class since 25 + /// Swift doesn't permit returning generic types from `@_cdecl` functions. 26 + /// To account for the wrapping `NSObject`, the array must be wrapped 27 + /// in `SRObject` on the Rust side. 28 + /// 29 + /// ```rust 30 + /// use swift_rs::{swift, SRArray, SRObject, Int}; 31 + /// 32 + /// swift!(fn get_int_array() -> SRObject<SRArray<Int>>); 33 + /// 34 + /// let array = unsafe { get_int_array() }; 35 + /// 36 + /// assert_eq!(array.as_slice(), &[1, 2, 3]) 37 + /// ``` 38 + /// [_corresponding Swift code_](https://github.com/Brendonovich/swift-rs/blob/07269e511f1afb71e2fcfa89ca5d7338bceb20e8/tests/swift-pkg/doctests.swift#L19) 39 + /// 40 + /// ## Returning in a Struct fIeld 41 + /// 42 + /// When returning an `SRArray` from a custom struct that is itself an `NSObject`, 43 + /// the above work is already done for you. 44 + /// Assuming your custom struct is already wrapped in `SRObject` in Rust, 45 + /// `SRArray` will work normally. 46 + /// 47 + /// ```rust 48 + /// use swift_rs::{swift, SRArray, SRObject, Int}; 49 + /// 50 + /// #[repr(C)] 51 + /// struct ArrayStruct { 52 + /// array: SRArray<Int> 53 + /// } 54 + /// 55 + /// swift!(fn get_array_struct() -> SRObject<ArrayStruct>); 56 + /// 57 + /// let data = unsafe { get_array_struct() }; 58 + /// 59 + /// assert_eq!(data.array.as_slice(), &[4, 5, 6]); 60 + /// ``` 61 + /// [_corresponding Swift code_](https://github.com/Brendonovich/swift-rs/blob/07269e511f1afb71e2fcfa89ca5d7338bceb20e8/tests/swift-pkg/doctests.swift#L32) 62 + #[repr(transparent)] 63 + pub struct SRArray<T>(SRObject<SRArrayImpl<T>>); 64 + 65 + impl<T> SRArray<T> { 66 + pub fn as_slice(&self) -> &[T] { 67 + self.0.as_slice() 68 + } 69 + } 70 + 71 + impl<T> SwiftObject for SRArray<T> { 72 + type Shape = SRArrayImpl<T>; 73 + 74 + fn get_object(&self) -> &SRObject<Self::Shape> { 75 + &self.0 76 + } 77 + } 78 + 79 + impl<T> Deref for SRArray<T> { 80 + type Target = [T]; 81 + 82 + fn deref(&self) -> &Self::Target { 83 + self.0.as_slice() 84 + } 85 + } 86 + 87 + impl<T> SRArrayImpl<T> { 88 + pub fn as_slice(&self) -> &[T] { 89 + unsafe { std::slice::from_raw_parts(self.data.as_ref(), self.length) } 90 + } 91 + } 92 + 93 + #[cfg(feature = "serde")] 94 + impl<T> serde::Serialize for SRArray<T> 95 + where 96 + T: serde::Serialize, 97 + { 98 + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 99 + where 100 + S: serde::Serializer, 101 + { 102 + use serde::ser::SerializeSeq; 103 + 104 + let mut seq = serializer.serialize_seq(Some(self.len()))?; 105 + for item in self.iter() { 106 + seq.serialize_element(item)?; 107 + } 108 + seq.end() 109 + } 110 + }
+74
apps/identity-wallet/swift-rs-patch/src-rs/types/data.rs
··· 1 + use crate::{ 2 + swift::{self, SwiftObject}, 3 + Int, 4 + }; 5 + 6 + use super::{array::SRArray, SRObject}; 7 + 8 + use std::ops::Deref; 9 + 10 + type Data = SRArray<u8>; 11 + 12 + /// Convenience type for working with byte buffers, 13 + /// analagous to `SRData` in Swift. 14 + /// 15 + /// ```rust 16 + /// use swift_rs::{swift, SRData}; 17 + /// 18 + /// swift!(fn get_data() -> SRData); 19 + /// 20 + /// let data = unsafe { get_data() }; 21 + /// 22 + /// assert_eq!(data.as_ref(), &[1, 2, 3]) 23 + /// ``` 24 + /// [_corresponding Swift code_](https://github.com/Brendonovich/swift-rs/blob/07269e511f1afb71e2fcfa89ca5d7338bceb20e8/tests/swift-pkg/doctests.swift#L68) 25 + #[repr(transparent)] 26 + pub struct SRData(SRObject<Data>); 27 + 28 + impl SRData { 29 + pub fn as_slice(&self) -> &[u8] { 30 + self 31 + } 32 + 33 + pub fn to_vec(&self) -> Vec<u8> { 34 + self.as_slice().to_vec() 35 + } 36 + } 37 + 38 + impl SwiftObject for SRData { 39 + type Shape = Data; 40 + 41 + fn get_object(&self) -> &SRObject<Self::Shape> { 42 + &self.0 43 + } 44 + } 45 + 46 + impl Deref for SRData { 47 + type Target = [u8]; 48 + 49 + fn deref(&self) -> &Self::Target { 50 + &self.0 51 + } 52 + } 53 + 54 + impl AsRef<[u8]> for SRData { 55 + fn as_ref(&self) -> &[u8] { 56 + self 57 + } 58 + } 59 + 60 + impl From<&[u8]> for SRData { 61 + fn from(value: &[u8]) -> Self { 62 + unsafe { swift::data_from_bytes(value.as_ptr(), value.len() as Int) } 63 + } 64 + } 65 + 66 + #[cfg(feature = "serde")] 67 + impl serde::Serialize for SRData { 68 + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 69 + where 70 + S: serde::Serializer, 71 + { 72 + serializer.serialize_bytes(self) 73 + } 74 + }
+11
apps/identity-wallet/swift-rs-patch/src-rs/types/mod.rs
··· 1 + mod array; 2 + mod data; 3 + mod object; 4 + mod scalars; 5 + mod string; 6 + 7 + pub use array::*; 8 + pub use data::*; 9 + pub use object::*; 10 + pub use scalars::*; 11 + pub use string::*;
+75
apps/identity-wallet/swift-rs-patch/src-rs/types/object.rs
··· 1 + use crate::swift::{self, SwiftObject}; 2 + use std::{ffi::c_void, ops::Deref, ptr::NonNull}; 3 + 4 + #[doc(hidden)] 5 + #[repr(C)] 6 + pub struct SRObjectImpl<T> { 7 + _nsobject_offset: u8, 8 + data: T, 9 + } 10 + 11 + /// Wrapper for arbitrary `NSObject` types. 12 + /// 13 + /// When returning an `NSObject`, its Rust type must be wrapped in `SRObject`. 14 + /// The type must also be annotated with `#[repr(C)]` to ensure its memory layout 15 + /// is identical to its Swift counterpart's. 16 + /// 17 + /// ```rust 18 + /// use swift_rs::{swift, SRObject, Int, Bool}; 19 + /// 20 + /// #[repr(C)] 21 + /// struct CustomObject { 22 + /// a: Int, 23 + /// b: Bool 24 + /// } 25 + /// 26 + /// swift!(fn get_custom_object() -> SRObject<CustomObject>); 27 + /// 28 + /// let value = unsafe { get_custom_object() }; 29 + /// 30 + /// let reference: &CustomObject = value.as_ref(); 31 + /// ``` 32 + /// [_corresponding Swift code_](https://github.com/Brendonovich/swift-rs/blob/07269e511f1afb71e2fcfa89ca5d7338bceb20e8/tests/swift-pkg/doctests.swift#L49) 33 + #[repr(transparent)] 34 + pub struct SRObject<T>(pub(crate) NonNull<SRObjectImpl<T>>); 35 + 36 + impl<T> SwiftObject for SRObject<T> { 37 + type Shape = T; 38 + 39 + fn get_object(&self) -> &SRObject<Self::Shape> { 40 + self 41 + } 42 + } 43 + 44 + impl<T> Deref for SRObject<T> { 45 + type Target = T; 46 + 47 + fn deref(&self) -> &T { 48 + unsafe { &self.0.as_ref().data } 49 + } 50 + } 51 + 52 + impl<T> AsRef<T> for SRObject<T> { 53 + fn as_ref(&self) -> &T { 54 + self 55 + } 56 + } 57 + 58 + impl<T> Drop for SRObject<T> { 59 + fn drop(&mut self) { 60 + unsafe { swift::release_object(self.0.as_ref() as *const _ as *const c_void) } 61 + } 62 + } 63 + 64 + #[cfg(feature = "serde")] 65 + impl<T> serde::Serialize for SRObject<T> 66 + where 67 + T: serde::Serialize, 68 + { 69 + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 70 + where 71 + S: serde::Serializer, 72 + { 73 + self.deref().serialize(serializer) 74 + } 75 + }
+34
apps/identity-wallet/swift-rs-patch/src-rs/types/scalars.rs
··· 1 + /// Swift's [`Bool`](https://developer.apple.com/documentation/swift/bool) type 2 + pub type Bool = bool; 3 + 4 + /// Swift's [`Int`](https://developer.apple.com/documentation/swift/int) type 5 + pub type Int = isize; 6 + /// Swift's [`Int8`](https://developer.apple.com/documentation/swift/int8) type 7 + pub type Int8 = i8; 8 + /// Swift's [`Int16`](https://developer.apple.com/documentation/swift/int16) type 9 + pub type Int16 = i16; 10 + /// Swift's [`Int32`](https://developer.apple.com/documentation/swift/int32) type 11 + pub type Int32 = i32; 12 + /// Swift's [`Int64`](https://developer.apple.com/documentation/swift/int64) type 13 + pub type Int64 = i64; 14 + 15 + /// Swift's [`UInt`](https://developer.apple.com/documentation/swift/uint) type 16 + pub type UInt = usize; 17 + /// Swift's [`UInt8`](https://developer.apple.com/documentation/swift/uint8) type 18 + pub type UInt8 = u8; 19 + /// Swift's [`UInt16`](https://developer.apple.com/documentation/swift/uint16) type 20 + pub type UInt16 = u16; 21 + /// Swift's [`UInt32`](https://developer.apple.com/documentation/swift/uint32) type 22 + pub type UInt32 = u32; 23 + /// Swift's [`UInt64`](https://developer.apple.com/documentation/swift/uint64) type 24 + pub type UInt64 = u64; 25 + 26 + /// Swift's [`Float`](https://developer.apple.com/documentation/swift/float) type 27 + pub type Float = f32; 28 + /// Swift's [`Double`](https://developer.apple.com/documentation/swift/double) type 29 + pub type Double = f64; 30 + 31 + /// Swift's [`Float32`](https://developer.apple.com/documentation/swift/float32) type 32 + pub type Float32 = f32; 33 + /// Swift's [`Float64`](https://developer.apple.com/documentation/swift/float64) type 34 + pub type Float64 = f64;
+84
apps/identity-wallet/swift-rs-patch/src-rs/types/string.rs
··· 1 + use std::{ 2 + fmt::{Display, Error, Formatter}, 3 + ops::Deref, 4 + }; 5 + 6 + use crate::{ 7 + swift::{self, SwiftObject}, 8 + Int, SRData, SRObject, 9 + }; 10 + 11 + /// String type that can be shared between Swift and Rust. 12 + /// 13 + /// ```rust 14 + /// use swift_rs::{swift, SRString}; 15 + /// 16 + /// swift!(fn get_greeting(name: &SRString) -> SRString); 17 + /// 18 + /// let greeting = unsafe { get_greeting(&"Brendan".into()) }; 19 + /// 20 + /// assert_eq!(greeting.as_str(), "Hello Brendan!"); 21 + /// ``` 22 + /// [_corresponding Swift code_](https://github.com/Brendonovich/swift-rs/blob/07269e511f1afb71e2fcfa89ca5d7338bceb20e8/tests/swift-pkg/doctests.swift#L56) 23 + #[repr(transparent)] 24 + pub struct SRString(SRData); 25 + 26 + impl SRString { 27 + pub fn as_str(&self) -> &str { 28 + unsafe { std::str::from_utf8_unchecked(&self.0) } 29 + } 30 + } 31 + 32 + impl SwiftObject for SRString { 33 + type Shape = <SRData as SwiftObject>::Shape; 34 + 35 + fn get_object(&self) -> &SRObject<Self::Shape> { 36 + self.0.get_object() 37 + } 38 + } 39 + 40 + impl Deref for SRString { 41 + type Target = str; 42 + 43 + fn deref(&self) -> &Self::Target { 44 + self.as_str() 45 + } 46 + } 47 + 48 + impl AsRef<[u8]> for SRString { 49 + fn as_ref(&self) -> &[u8] { 50 + self.0.as_ref() 51 + } 52 + } 53 + 54 + impl From<&str> for SRString { 55 + fn from(string: &str) -> Self { 56 + unsafe { swift::string_from_bytes(string.as_ptr(), string.len() as Int) } 57 + } 58 + } 59 + 60 + impl Display for SRString { 61 + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { 62 + self.as_str().fmt(f) 63 + } 64 + } 65 + 66 + #[cfg(feature = "serde")] 67 + impl serde::Serialize for SRString { 68 + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 69 + where 70 + S: serde::Serializer, 71 + { 72 + serializer.serialize_str(self.as_str()) 73 + } 74 + } 75 + #[cfg(feature = "serde")] 76 + impl<'a> serde::Deserialize<'a> for SRString { 77 + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 78 + where 79 + D: serde::Deserializer<'a>, 80 + { 81 + let string = String::deserialize(deserializer)?; 82 + Ok(SRString::from(string.as_str())) 83 + } 84 + }
+150
apps/identity-wallet/swift-rs-patch/tests/test_bindings.rs
··· 1 + //! Test for swift-rs bindings 2 + //! 3 + //! Needs to be run with the env var `TEST_SWIFT_RS=true`, to allow for 4 + //! the test swift code to be linked. 5 + 6 + use serial_test::serial; 7 + use std::{env, process::Command}; 8 + use swift_rs::*; 9 + 10 + macro_rules! test_with_leaks { 11 + ( $op:expr ) => {{ 12 + let leaks_env_var = "TEST_RUNNING_UNDER_LEAKS"; 13 + if env::var(leaks_env_var).unwrap_or_else(|_| "false".into()) == "true" { 14 + let _ = $op(); 15 + } else { 16 + // we run $op directly in the current process first, as leaks will not give 17 + // us the exit code of $op, but only if memory leaks happened or not 18 + $op(); 19 + 20 + // and now we run the above codepath under leaks monitoring 21 + let exe = env::current_exe().unwrap(); 22 + 23 + // codesign the binary first, so that leaks can be run 24 + let debug_plist = exe.parent().unwrap().join("debug.plist"); 25 + let plist_path = &debug_plist.to_string_lossy(); 26 + std::fs::write(&debug_plist, DEBUG_PLIST_XML.as_bytes()).unwrap(); 27 + let status = Command::new("codesign") 28 + .args([ 29 + "-s", 30 + "-", 31 + "-v", 32 + "-f", 33 + "--entitlements", 34 + plist_path, 35 + &exe.to_string_lossy(), 36 + ]) 37 + .status() 38 + .expect("cmd failure"); 39 + assert!(status.success(), "failed to codesign"); 40 + 41 + // run leaks command to detect memory leaks 42 + let status = Command::new("leaks") 43 + .args(["-atExit", "--", &exe.to_string_lossy(), "--nocapture"]) 44 + .env(leaks_env_var, "true") 45 + .status() 46 + .expect("cmd failure"); 47 + assert!(status.success(), "leaks detected in memory pressure test"); 48 + } 49 + }}; 50 + } 51 + 52 + swift!(fn echo(string: &SRString) -> SRString); 53 + 54 + #[test] 55 + #[serial] 56 + fn test_reflection() { 57 + test_with_leaks!(|| { 58 + // create memory pressure 59 + let name: SRString = "Brendan".into(); 60 + for _ in 0..10_000 { 61 + let reflected = unsafe { echo(&name) }; 62 + assert_eq!(name.as_str(), reflected.as_str()); 63 + } 64 + }); 65 + } 66 + 67 + swift!(fn get_greeting(name: &SRString) -> SRString); 68 + 69 + #[test] 70 + #[serial] 71 + fn test_string() { 72 + test_with_leaks!(|| { 73 + let name: SRString = "Brendan".into(); 74 + let greeting = unsafe { get_greeting(&name) }; 75 + assert_eq!(greeting.as_str(), "Hello Brendan!"); 76 + }); 77 + } 78 + 79 + #[test] 80 + #[serial] 81 + fn test_memory_pressure() { 82 + test_with_leaks!(|| { 83 + // create memory pressure 84 + let name: SRString = "Brendan".into(); 85 + for _ in 0..10_000 { 86 + let greeting = unsafe { get_greeting(&name) }; 87 + assert_eq!(greeting.as_str(), "Hello Brendan!"); 88 + } 89 + }); 90 + } 91 + 92 + #[test] 93 + #[serial] 94 + fn test_autoreleasepool() { 95 + test_with_leaks!(|| { 96 + // create memory pressure 97 + let name: SRString = "Brendan".into(); 98 + for _ in 0..10_000 { 99 + autoreleasepool!({ 100 + let greeting = unsafe { get_greeting(&name) }; 101 + assert_eq!(greeting.as_str(), "Hello Brendan!"); 102 + }); 103 + } 104 + }); 105 + } 106 + 107 + #[repr(C)] 108 + struct Complex { 109 + a: SRString, 110 + b: Int, 111 + c: Bool, 112 + } 113 + 114 + swift!(fn complex_data() -> SRObjectArray<Complex>); 115 + 116 + #[test] 117 + #[serial] 118 + fn test_complex() { 119 + test_with_leaks!(|| { 120 + let mut v = vec![]; 121 + 122 + for _ in 0..10_000 { 123 + let data = unsafe { complex_data() }; 124 + assert_eq!(data[0].a.as_str(), "Brendan"); 125 + v.push(data); 126 + } 127 + }); 128 + } 129 + 130 + swift!(fn echo_data(data: &SRData) -> SRData); 131 + 132 + #[test] 133 + #[serial] 134 + fn test_data() { 135 + test_with_leaks!(|| { 136 + let str: &str = "hello"; 137 + let bytes = str.as_bytes(); 138 + for _ in 0..10_000 { 139 + let data = unsafe { echo_data(&bytes.into()) }; 140 + assert_eq!(data.as_slice(), bytes); 141 + } 142 + }); 143 + } 144 + 145 + const DEBUG_PLIST_XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?> 146 + <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"> 147 + <plist version="1.0"> 148 + <dict><key>com.apple.security.get-task-allow</key><true/></dict> 149 + </plist> 150 + "#;