From 4e3a055bb5bdecd2aee70be37b739b72463797f4 Mon Sep 17 00:00:00 2001 From: jackpooleyml <186731786+jackpooleyml@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:17:59 +0100 Subject: [PATCH] feat(swiftsdk): swift sdk scaffolding --- .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/zksyncsso.xcscheme | 92 +++ .github/workflows/ci-swift.yml | 45 ++ .github/workflows/ci.yml | 1 - .gitignore | 16 + .../contents.xcworkspacedata | 7 + platforms/shared/zksync-sso/Cargo.toml | 11 + .../shared/zksync-sso/crates/cli/Cargo.toml | 9 + .../shared/zksync-sso/crates/cli/src/main.rs | 3 + .../shared/zksync-sso/crates/ffi/Cargo.toml | 16 + .../crates/ffi/build-swift-framework.sh | 136 ++++ .../crates/ffi/src/bin/uniffi-bindgen.rs | 3 + .../shared/zksync-sso/crates/ffi/src/lib.rs | 30 + .../shared/zksync-sso/crates/sdk/Cargo.toml | 9 + .../shared/zksync-sso/crates/sdk/src/lib.rs | 14 + platforms/shared/zksync-sso/rustfmt.toml | 7 + platforms/swift/ZKsyncSSO/.gitignore | 8 + .../Example/Example.xcodeproj/project.pbxproj | 580 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 35 ++ .../Example/Assets.xcassets/Contents.json | 6 + .../Example/Example/ContentView.swift | 18 + .../Examples/Example/Example/ExampleApp.swift | 10 + .../Preview Assets.xcassets/Contents.json | 6 + .../Example/ExampleTests/ExampleTests.swift | 10 + .../ExampleUITests/ExampleUITests.swift | 36 ++ .../ExampleUITestsLaunchTests.swift | 26 + platforms/swift/ZKsyncSSO/Package.swift | 29 + .../Sources/ZKsyncSSO/ZKsyncSSO.swift | 9 + .../ZKsyncSSO/Sources/ZKsyncSSOFFI/ffi.swift | 512 ++++++++++++++++ .../Tests/ZKsyncSSOTests/ZKsyncSSOTests.swift | 10 + 33 files changed, 1726 insertions(+), 1 deletion(-) create mode 100644 .github/package.xcworkspace/contents.xcworkspacedata create mode 100644 .github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 .github/package.xcworkspace/xcshareddata/xcschemes/zksyncsso.xcscheme create mode 100644 .github/workflows/ci-swift.yml create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata create mode 100644 platforms/shared/zksync-sso/Cargo.toml create mode 100644 platforms/shared/zksync-sso/crates/cli/Cargo.toml create mode 100644 platforms/shared/zksync-sso/crates/cli/src/main.rs create mode 100644 platforms/shared/zksync-sso/crates/ffi/Cargo.toml create mode 100644 platforms/shared/zksync-sso/crates/ffi/build-swift-framework.sh create mode 100644 platforms/shared/zksync-sso/crates/ffi/src/bin/uniffi-bindgen.rs create mode 100644 platforms/shared/zksync-sso/crates/ffi/src/lib.rs create mode 100644 platforms/shared/zksync-sso/crates/sdk/Cargo.toml create mode 100644 platforms/shared/zksync-sso/crates/sdk/src/lib.rs create mode 100644 platforms/shared/zksync-sso/rustfmt.toml create mode 100644 platforms/swift/ZKsyncSSO/.gitignore create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.pbxproj create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/Contents.json create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example/ContentView.swift create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example/ExampleApp.swift create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/Example/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/ExampleTests/ExampleTests.swift create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITests.swift create mode 100644 platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITestsLaunchTests.swift create mode 100644 platforms/swift/ZKsyncSSO/Package.swift create mode 100644 platforms/swift/ZKsyncSSO/Sources/ZKsyncSSO/ZKsyncSSO.swift create mode 100644 platforms/swift/ZKsyncSSO/Sources/ZKsyncSSOFFI/ffi.swift create mode 100644 platforms/swift/ZKsyncSSO/Tests/ZKsyncSSOTests/ZKsyncSSOTests.swift diff --git a/.github/package.xcworkspace/contents.xcworkspacedata b/.github/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..7cb2e47 --- /dev/null +++ b/.github/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/.github/package.xcworkspace/xcshareddata/xcschemes/zksyncsso.xcscheme b/.github/package.xcworkspace/xcshareddata/xcschemes/zksyncsso.xcscheme new file mode 100644 index 0000000..65f0108 --- /dev/null +++ b/.github/package.xcworkspace/xcshareddata/xcschemes/zksyncsso.xcscheme @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/workflows/ci-swift.yml b/.github/workflows/ci-swift.yml new file mode 100644 index 0000000..ba3481b --- /dev/null +++ b/.github/workflows/ci-swift.yml @@ -0,0 +1,45 @@ +name: Swift CI + +on: + push: + paths: + - 'platforms/**' + +jobs: + swift-sdk: + name: Swift Package - latest + runs-on: macos-15 + strategy: + matrix: + config: + - debug + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.4 + - run: rustup update stable && rustup default stable + - name: Select Xcode 16.1 + run: sudo xcode-select -s /Applications/Xcode_16.1.app + - name: Select Simulator + run: | + UDID=$(xcrun simctl list devices | awk '/-- iOS 18.1 --/{flag=1; next} /--/{flag=0} flag' | grep "iPhone 16 Pro" | awk -F '[()]' '{print $2}' | head -1) + if [ -z "$UDID" ]; then + echo "Simulator not found!" >&2 + exit 1 + fi + echo "Simulator UDID: $UDID" + echo "SIMULATOR_UDID=$UDID" >> $GITHUB_ENV + - name: Install swiftformat + run: brew install swiftformat + - name: Build bindings + run: sh platforms/shared/zksync-sso/crates/ffi/build-swift-framework.sh + - name: Build & test Swift SDK + run: | + xcodebuild test \ + -skipMacroValidation \ + -configuration debug \ + -workspace .github/package.xcworkspace \ + -scheme zksyncsso \ + -destination "platform=iOS Simulator,id=${{ env.SIMULATOR_UDID }}" || exit 1 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0225e7c..9ef5030 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,4 +166,3 @@ jobs: - name: Run contract test run: pnpm test working-directory: packages/contracts - diff --git a/.gitignore b/.gitignore index c8436fb..1411f3c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,19 @@ playwright/.cache/ .DS_Store dist + +# Rust +debug/ +target/ +Cargo.lock + +# Swift +xcuserdata/ +*.hmap +*.ipa +*.dSYM.zip +*.dSYM +timeline.xctimeline +playground.xcworkspace +.build/ +out/ \ No newline at end of file diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/platforms/shared/zksync-sso/Cargo.toml b/platforms/shared/zksync-sso/Cargo.toml new file mode 100644 index 0000000..977d595 --- /dev/null +++ b/platforms/shared/zksync-sso/Cargo.toml @@ -0,0 +1,11 @@ +[workspace] +members = ["crates/*"] +resolver = "2" + +[workspace.package] +version = "0.1.0" +edition = "2021" +rust-version = "1.83" +license = "Apache-2.0" + +[workspace.dependencies] diff --git a/platforms/shared/zksync-sso/crates/cli/Cargo.toml b/platforms/shared/zksync-sso/crates/cli/Cargo.toml new file mode 100644 index 0000000..a909783 --- /dev/null +++ b/platforms/shared/zksync-sso/crates/cli/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cli" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +[dependencies] +sdk = { path = "../sdk" } diff --git a/platforms/shared/zksync-sso/crates/cli/src/main.rs b/platforms/shared/zksync-sso/crates/cli/src/main.rs new file mode 100644 index 0000000..7d11134 --- /dev/null +++ b/platforms/shared/zksync-sso/crates/cli/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("{}", format!("{}", sdk::add(1, 1))); +} diff --git a/platforms/shared/zksync-sso/crates/ffi/Cargo.toml b/platforms/shared/zksync-sso/crates/ffi/Cargo.toml new file mode 100644 index 0000000..bcba491 --- /dev/null +++ b/platforms/shared/zksync-sso/crates/ffi/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ffi" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +[lib] +crate-type = ["staticlib"] + +[dependencies] +uniffi = { version = "0.28.3", features = ["cli"] } +sdk = { path = "../sdk" } + +[build-dependencies] +uniffi = { version = "0.28.3", features = ["build", "cli"] } diff --git a/platforms/shared/zksync-sso/crates/ffi/build-swift-framework.sh b/platforms/shared/zksync-sso/crates/ffi/build-swift-framework.sh new file mode 100644 index 0000000..c52f3e8 --- /dev/null +++ b/platforms/shared/zksync-sso/crates/ffi/build-swift-framework.sh @@ -0,0 +1,136 @@ +#!/bin/sh + +set -eo pipefail + +pushd `dirname $0` +trap popd EXIT + +NAME="ffi" +VERSION=${1:-"1.0"} # first arg or "1.0" +REVERSE_DOMAIN="dev.matterlabs" +BUNDLE_IDENTIFIER="$REVERSE_DOMAIN.$NAME" +LIBRARY_NAME="lib$NAME.a" +FRAMEWORK_LIBRARY_NAME=${NAME}FFI +FRAMEWORK_NAME="$FRAMEWORK_LIBRARY_NAME.framework" +XC_FRAMEWORK_NAME="$FRAMEWORK_LIBRARY_NAME.xcframework" +HEADER_NAME="${NAME}FFI.h" +OUT_PATH="out" +MIN_IOS_VERSION="18.0" +WRAPPER_PATH="../../../../swift/ZKsyncSSO/Sources/ZKsyncSSOFFI" +TARGET_PATH="../../target" +BUILD_TYPE="debug" # use debug during development + +AARCH64_APPLE_IOS_PATH="$TARGET_PATH/aarch64-apple-ios/$BUILD_TYPE" +AARCH64_APPLE_IOS_SIM_PATH="$TARGET_PATH/aarch64-apple-ios-sim/$BUILD_TYPE" +X86_64_APPLE_IOS_PATH="$TARGET_PATH/x86_64-apple-ios/$BUILD_TYPE" +AARCH64_APPLE_DARWIN_PATH="$TARGET_PATH/aarch64-apple-darwin/$BUILD_TYPE" +X86_64_APPLE_DARWIN_PATH="$TARGET_PATH/x86_64-apple-darwin/$BUILD_TYPE" + +targets=("aarch64-apple-ios" "aarch64-apple-ios-sim" "x86_64-apple-ios" "aarch64-apple-darwin" "x86_64-apple-darwin") + +# Build for all targets +for target in "${targets[@]}"; do + echo "Building for $target..." + rustup target add $target + + if [ "$BUILD_TYPE" = "debug" ]; then + echo "Building debug for $target" + cargo build --target $target + else + echo "Building release for $target" + cargo build --release --target $target + fi +done + +# Generate swift wrapper +echo "Generating swift wrapper..." +mkdir -p $OUT_PATH +mkdir -p $WRAPPER_PATH +CURRENT_ARCH=$(rustc --version --verbose | grep host | cut -f2 -d' ') +cargo run --features=uniffi/cli --bin uniffi-bindgen generate --library $TARGET_PATH/$CURRENT_ARCH/$BUILD_TYPE/$LIBRARY_NAME --language swift --out-dir $OUT_PATH + +# Merge libraries with lipo +echo "Merging libraries with lipo..." +lipo -create $AARCH64_APPLE_IOS_SIM_PATH/$LIBRARY_NAME \ + $X86_64_APPLE_IOS_PATH/$LIBRARY_NAME \ + -output $OUT_PATH/sim-$LIBRARY_NAME +lipo -create $AARCH64_APPLE_DARWIN_PATH/$LIBRARY_NAME \ + $X86_64_APPLE_DARWIN_PATH/$LIBRARY_NAME \ + -output $OUT_PATH/macos-$LIBRARY_NAME + +# Create framework template +rm -rf $OUT_PATH/$FRAMEWORK_NAME +mkdir -p $OUT_PATH/$FRAMEWORK_NAME/Headers +mkdir -p $OUT_PATH/$FRAMEWORK_NAME/Modules +cp $OUT_PATH/$HEADER_NAME $OUT_PATH/$FRAMEWORK_NAME/Headers +cat < $OUT_PATH/$FRAMEWORK_NAME/Modules/module.modulemap +framework module $FRAMEWORK_LIBRARY_NAME { + umbrella header "$HEADER_NAME" + + export * + module * { export * } +} +EOT + +cat < $OUT_PATH/$FRAMEWORK_NAME/Info.plist + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $FRAMEWORK_LIBRARY_NAME + CFBundleIdentifier + $BUNDLE_IDENTIFIER + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $FRAMEWORK_LIBRARY_NAME + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $VERSION + NSPrincipalClass + + MinimumOSVersion + $MIN_IOS_VERSION + + +EOT + +# Prepare frameworks for each platform +rm -rf $OUT_PATH/frameworks +mkdir -p $OUT_PATH/frameworks/sim +mkdir -p $OUT_PATH/frameworks/ios +mkdir -p $OUT_PATH/frameworks/macos +cp -r $OUT_PATH/$FRAMEWORK_NAME $OUT_PATH/frameworks/sim/ +cp -r $OUT_PATH/$FRAMEWORK_NAME $OUT_PATH/frameworks/ios/ +cp -r $OUT_PATH/$FRAMEWORK_NAME $OUT_PATH/frameworks/macos/ +mv $OUT_PATH/sim-$LIBRARY_NAME $OUT_PATH/frameworks/sim/$FRAMEWORK_NAME/$FRAMEWORK_LIBRARY_NAME +mv $OUT_PATH/macos-$LIBRARY_NAME $OUT_PATH/frameworks/macos/$FRAMEWORK_NAME/$FRAMEWORK_LIBRARY_NAME +cp $AARCH64_APPLE_IOS_PATH/$LIBRARY_NAME $OUT_PATH/frameworks/ios/$FRAMEWORK_NAME/$FRAMEWORK_LIBRARY_NAME + +# Create xcframework +echo "Creating xcframework..." +rm -rf $OUT_PATH/$XC_FRAMEWORK_NAME +xcodebuild -create-xcframework \ + -framework $OUT_PATH/frameworks/sim/$FRAMEWORK_NAME \ + -framework $OUT_PATH/frameworks/ios/$FRAMEWORK_NAME \ + -framework $OUT_PATH/frameworks/macos/$FRAMEWORK_NAME \ + -output $OUT_PATH/$XC_FRAMEWORK_NAME + +# Copy swift wrapper +# Need some temporary workarounds to compile swift wrapper +# https://github.com/rust-lang/cargo/issues/11953 +cat < $OUT_PATH/import.txt +#if os(macOS) +import SystemConfiguration +#endif +EOT +cat $OUT_PATH/import.txt $OUT_PATH/$NAME.swift > $WRAPPER_PATH/$NAME.swift + +# Fix initializationResult compilation error +sed -i '' 's/private var initializationResult: InitializationResult = {/private let initializationResult: InitializationResult = {/' "$WRAPPER_PATH/$NAME.swift" \ No newline at end of file diff --git a/platforms/shared/zksync-sso/crates/ffi/src/bin/uniffi-bindgen.rs b/platforms/shared/zksync-sso/crates/ffi/src/bin/uniffi-bindgen.rs new file mode 100644 index 0000000..f6cff6c --- /dev/null +++ b/platforms/shared/zksync-sso/crates/ffi/src/bin/uniffi-bindgen.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/platforms/shared/zksync-sso/crates/ffi/src/lib.rs b/platforms/shared/zksync-sso/crates/ffi/src/lib.rs new file mode 100644 index 0000000..c424cca --- /dev/null +++ b/platforms/shared/zksync-sso/crates/ffi/src/lib.rs @@ -0,0 +1,30 @@ +use uniffi; + +uniffi::setup_scaffolding!(); + +#[uniffi::export] +fn greet(name: &str) -> String { + format!("Hello, {}", name) +} + +#[uniffi::export] +fn add(left: u64, right: u64) -> u64 { + sdk::add(left, right) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } + + #[test] + fn greeting_works() { + let greeting = greet("Rust"); + assert_eq!("Hello, Rust", greeting); + } +} diff --git a/platforms/shared/zksync-sso/crates/sdk/Cargo.toml b/platforms/shared/zksync-sso/crates/sdk/Cargo.toml new file mode 100644 index 0000000..30a54bf --- /dev/null +++ b/platforms/shared/zksync-sso/crates/sdk/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "sdk" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +[dependencies] +alloy-zksync = { version = "0.5.0" } diff --git a/platforms/shared/zksync-sso/crates/sdk/src/lib.rs b/platforms/shared/zksync-sso/crates/sdk/src/lib.rs new file mode 100644 index 0000000..b801279 --- /dev/null +++ b/platforms/shared/zksync-sso/crates/sdk/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/platforms/shared/zksync-sso/rustfmt.toml b/platforms/shared/zksync-sso/rustfmt.toml new file mode 100644 index 0000000..00d2e7e --- /dev/null +++ b/platforms/shared/zksync-sso/rustfmt.toml @@ -0,0 +1,7 @@ +max_width = 80 +use_small_heuristics = "Max" +comment_width = 100 +format_code_in_doc_comments = true +doc_comment_code_block_width = 100 +group_imports = "One" +imports_granularity = "One" diff --git a/platforms/swift/ZKsyncSSO/.gitignore b/platforms/swift/ZKsyncSSO/.gitignore new file mode 100644 index 0000000..0023a53 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.pbxproj b/platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c8f91e2 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.pbxproj @@ -0,0 +1,580 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + D252DD3E2D099CD4006D9A43 /* ZKsyncSSO in Frameworks */ = {isa = PBXBuildFile; productRef = D252DD3D2D099CD4006D9A43 /* ZKsyncSSO */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + D252DD202D099C9C006D9A43 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D252DD072D099C9A006D9A43 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D252DD0E2D099C9A006D9A43; + remoteInfo = Example; + }; + D252DD2A2D099C9C006D9A43 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D252DD072D099C9A006D9A43 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D252DD0E2D099C9A006D9A43; + remoteInfo = Example; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + D252DD0F2D099C9A006D9A43 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D252DD1F2D099C9C006D9A43 /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D252DD292D099C9C006D9A43 /* ExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + D252DD112D099C9A006D9A43 /* Example */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = Example; + sourceTree = ""; + }; + D252DD222D099C9C006D9A43 /* ExampleTests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = ExampleTests; + sourceTree = ""; + }; + D252DD2C2D099C9C006D9A43 /* ExampleUITests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = ExampleUITests; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + D252DD0C2D099C9A006D9A43 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D252DD3E2D099CD4006D9A43 /* ZKsyncSSO in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D252DD1C2D099C9C006D9A43 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D252DD262D099C9C006D9A43 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D252DD062D099C9A006D9A43 = { + isa = PBXGroup; + children = ( + D252DD112D099C9A006D9A43 /* Example */, + D252DD222D099C9C006D9A43 /* ExampleTests */, + D252DD2C2D099C9C006D9A43 /* ExampleUITests */, + D252DD102D099C9A006D9A43 /* Products */, + ); + sourceTree = ""; + }; + D252DD102D099C9A006D9A43 /* Products */ = { + isa = PBXGroup; + children = ( + D252DD0F2D099C9A006D9A43 /* Example.app */, + D252DD1F2D099C9C006D9A43 /* ExampleTests.xctest */, + D252DD292D099C9C006D9A43 /* ExampleUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D252DD0E2D099C9A006D9A43 /* Example */ = { + isa = PBXNativeTarget; + buildConfigurationList = D252DD332D099C9C006D9A43 /* Build configuration list for PBXNativeTarget "Example" */; + buildPhases = ( + D252DD0B2D099C9A006D9A43 /* Sources */, + D252DD0C2D099C9A006D9A43 /* Frameworks */, + D252DD0D2D099C9A006D9A43 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + D252DD112D099C9A006D9A43 /* Example */, + ); + name = Example; + packageProductDependencies = ( + D252DD3D2D099CD4006D9A43 /* ZKsyncSSO */, + ); + productName = Example; + productReference = D252DD0F2D099C9A006D9A43 /* Example.app */; + productType = "com.apple.product-type.application"; + }; + D252DD1E2D099C9C006D9A43 /* ExampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D252DD362D099C9C006D9A43 /* Build configuration list for PBXNativeTarget "ExampleTests" */; + buildPhases = ( + D252DD1B2D099C9C006D9A43 /* Sources */, + D252DD1C2D099C9C006D9A43 /* Frameworks */, + D252DD1D2D099C9C006D9A43 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D252DD212D099C9C006D9A43 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + D252DD222D099C9C006D9A43 /* ExampleTests */, + ); + name = ExampleTests; + packageProductDependencies = ( + ); + productName = ExampleTests; + productReference = D252DD1F2D099C9C006D9A43 /* ExampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + D252DD282D099C9C006D9A43 /* ExampleUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D252DD392D099C9C006D9A43 /* Build configuration list for PBXNativeTarget "ExampleUITests" */; + buildPhases = ( + D252DD252D099C9C006D9A43 /* Sources */, + D252DD262D099C9C006D9A43 /* Frameworks */, + D252DD272D099C9C006D9A43 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D252DD2B2D099C9C006D9A43 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + D252DD2C2D099C9C006D9A43 /* ExampleUITests */, + ); + name = ExampleUITests; + packageProductDependencies = ( + ); + productName = ExampleUITests; + productReference = D252DD292D099C9C006D9A43 /* ExampleUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D252DD072D099C9A006D9A43 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1610; + LastUpgradeCheck = 1610; + TargetAttributes = { + D252DD0E2D099C9A006D9A43 = { + CreatedOnToolsVersion = 16.1; + }; + D252DD1E2D099C9C006D9A43 = { + CreatedOnToolsVersion = 16.1; + TestTargetID = D252DD0E2D099C9A006D9A43; + }; + D252DD282D099C9C006D9A43 = { + CreatedOnToolsVersion = 16.1; + TestTargetID = D252DD0E2D099C9A006D9A43; + }; + }; + }; + buildConfigurationList = D252DD0A2D099C9A006D9A43 /* Build configuration list for PBXProject "Example" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = D252DD062D099C9A006D9A43; + minimizedProjectReferenceProxies = 1; + packageReferences = ( + D252DD3C2D099CD4006D9A43 /* XCLocalSwiftPackageReference "../../../ZKsyncSSO" */, + ); + preferredProjectObjectVersion = 77; + productRefGroup = D252DD102D099C9A006D9A43 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D252DD0E2D099C9A006D9A43 /* Example */, + D252DD1E2D099C9C006D9A43 /* ExampleTests */, + D252DD282D099C9C006D9A43 /* ExampleUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D252DD0D2D099C9A006D9A43 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D252DD1D2D099C9C006D9A43 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D252DD272D099C9C006D9A43 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D252DD0B2D099C9A006D9A43 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D252DD1B2D099C9C006D9A43 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D252DD252D099C9C006D9A43 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + D252DD212D099C9C006D9A43 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D252DD0E2D099C9A006D9A43 /* Example */; + targetProxy = D252DD202D099C9C006D9A43 /* PBXContainerItemProxy */; + }; + D252DD2B2D099C9C006D9A43 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D252DD0E2D099C9A006D9A43 /* Example */; + targetProxy = D252DD2A2D099C9C006D9A43 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + D252DD312D099C9C006D9A43 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + D252DD322D099C9C006D9A43 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + D252DD342D099C9C006D9A43 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.matterlabs.Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + D252DD352D099C9C006D9A43 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.matterlabs.Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + D252DD372D099C9C006D9A43 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.matterlabs.ExampleTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Example"; + }; + name = Debug; + }; + D252DD382D099C9C006D9A43 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.matterlabs.ExampleTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Example"; + }; + name = Release; + }; + D252DD3A2D099C9C006D9A43 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.matterlabs.ExampleUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Example; + }; + name = Debug; + }; + D252DD3B2D099C9C006D9A43 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.matterlabs.ExampleUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Example; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D252DD0A2D099C9A006D9A43 /* Build configuration list for PBXProject "Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D252DD312D099C9C006D9A43 /* Debug */, + D252DD322D099C9C006D9A43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D252DD332D099C9C006D9A43 /* Build configuration list for PBXNativeTarget "Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D252DD342D099C9C006D9A43 /* Debug */, + D252DD352D099C9C006D9A43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D252DD362D099C9C006D9A43 /* Build configuration list for PBXNativeTarget "ExampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D252DD372D099C9C006D9A43 /* Debug */, + D252DD382D099C9C006D9A43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D252DD392D099C9C006D9A43 /* Build configuration list for PBXNativeTarget "ExampleUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D252DD3A2D099C9C006D9A43 /* Debug */, + D252DD3B2D099C9C006D9A43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + D252DD3C2D099CD4006D9A43 /* XCLocalSwiftPackageReference "../../../ZKsyncSSO" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../../../ZKsyncSSO; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + D252DD3D2D099CD4006D9A43 /* ZKsyncSSO */ = { + isa = XCSwiftPackageProductDependency; + productName = ZKsyncSSO; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = D252DD072D099C9A006D9A43 /* Project object */; +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AccentColor.colorset/Contents.json b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2305880 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,35 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/Contents.json b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example/ContentView.swift b/platforms/swift/ZKsyncSSO/Examples/Example/Example/ContentView.swift new file mode 100644 index 0000000..d60821e --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example/ContentView.swift @@ -0,0 +1,18 @@ +import SwiftUI +import ZKsyncSSO + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundStyle(.tint) + Text(greetRust(name: "Rust")) + } + .padding() + } +} + +#Preview { + ContentView() +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example/ExampleApp.swift b/platforms/swift/ZKsyncSSO/Examples/Example/Example/ExampleApp.swift new file mode 100644 index 0000000..7e69ce8 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example/ExampleApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct ExampleApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/Example/Preview Content/Preview Assets.xcassets/Contents.json b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/Example/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/ExampleTests/ExampleTests.swift b/platforms/swift/ZKsyncSSO/Examples/Example/ExampleTests/ExampleTests.swift new file mode 100644 index 0000000..9498955 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/ExampleTests/ExampleTests.swift @@ -0,0 +1,10 @@ +import Testing +@testable import Example + +struct ExampleTests { + + @Test func example() async throws { + // Write your test here and use APIs like `#expect(...)` to check expected conditions. + } + +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITests.swift b/platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITests.swift new file mode 100644 index 0000000..0b199fd --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITests.swift @@ -0,0 +1,36 @@ +import XCTest + +final class ExampleUITests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + @MainActor + func testExample() throws { + // UI tests must launch the application that they test. + let app = XCUIApplication() + app.launch() + + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + @MainActor + func testLaunchPerformance() throws { + if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { + // This measures how long it takes to launch your application. + measure(metrics: [XCTApplicationLaunchMetric()]) { + XCUIApplication().launch() + } + } + } +} diff --git a/platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITestsLaunchTests.swift b/platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITestsLaunchTests.swift new file mode 100644 index 0000000..2910808 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Examples/Example/ExampleUITests/ExampleUITestsLaunchTests.swift @@ -0,0 +1,26 @@ +import XCTest + +final class ExampleUITestsLaunchTests: XCTestCase { + + override class var runsForEachTargetApplicationUIConfiguration: Bool { + true + } + + override func setUpWithError() throws { + continueAfterFailure = false + } + + @MainActor + func testLaunch() throws { + let app = XCUIApplication() + app.launch() + + // Insert steps here to perform after app launch but before taking a screenshot, + // such as logging into a test account or navigating somewhere in the app + + let attachment = XCTAttachment(screenshot: app.screenshot()) + attachment.name = "Launch Screen" + attachment.lifetime = .keepAlways + add(attachment) + } +} diff --git a/platforms/swift/ZKsyncSSO/Package.swift b/platforms/swift/ZKsyncSSO/Package.swift new file mode 100644 index 0000000..8ea9060 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Package.swift @@ -0,0 +1,29 @@ +// swift-tools-version: 6.0 +import PackageDescription + +let package = Package( + name: "ZKsyncSSO", + platforms: [ + .iOS(.v18), + .macOS(.v15) + ], + products: [ + .library( + name: "ZKsyncSSO", + targets: ["ZKsyncSSO"]), + ], + targets: [ + .target( + name: "ZKsyncSSO", + dependencies: ["ZKsyncSSOFFI"]), + .target( + name: "ZKsyncSSOFFI", + dependencies: ["ffiFFI"]), + .binaryTarget( + name: "ffiFFI", + path: "../../shared/zksync-sso/crates/ffi/out/ffiFFI.xcframework"), + .testTarget( + name: "ZKsyncSSOTests", + dependencies: ["ZKsyncSSO"]), + ] +) diff --git a/platforms/swift/ZKsyncSSO/Sources/ZKsyncSSO/ZKsyncSSO.swift b/platforms/swift/ZKsyncSSO/Sources/ZKsyncSSO/ZKsyncSSO.swift new file mode 100644 index 0000000..e11a6d0 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Sources/ZKsyncSSO/ZKsyncSSO.swift @@ -0,0 +1,9 @@ +import ZKsyncSSOFFI + +public func greetRust(name: String) -> String { + greet(name: name) +} + +public func addRust(left: UInt64, right: UInt64) -> UInt64 { + add(left: left, right: right) +} diff --git a/platforms/swift/ZKsyncSSO/Sources/ZKsyncSSOFFI/ffi.swift b/platforms/swift/ZKsyncSSO/Sources/ZKsyncSSOFFI/ffi.swift new file mode 100644 index 0000000..2324a18 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Sources/ZKsyncSSOFFI/ffi.swift @@ -0,0 +1,512 @@ +#if os(macOS) +import SystemConfiguration +#endif +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +// swiftlint:disable all +import Foundation + +// Depending on the consumer's build setup, the low-level FFI code +// might be in a separate module, or it might be compiled inline into +// this module. This is a bit of light hackery to work with both. +#if canImport(ffiFFI) + import ffiFFI +#endif + +private extension RustBuffer { + // Allocate a new buffer, copying the contents of a `UInt8` array. + init(bytes: [UInt8]) { + let rbuf = bytes.withUnsafeBufferPointer { ptr in + RustBuffer.from(ptr) + } + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) + } + + static func empty() -> RustBuffer { + RustBuffer(capacity: 0, len: 0, data: nil) + } + + static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { + try! rustCall { ffi_ffi_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) } + } + + // Frees the buffer in place. + // The buffer must not be used after this is called. + func deallocate() { + try! rustCall { ffi_ffi_rustbuffer_free(self, $0) } + } +} + +private extension ForeignBytes { + init(bufferPointer: UnsafeBufferPointer) { + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress) + } +} + +// For every type used in the interface, we provide helper methods for conveniently +// lifting and lowering that type from C-compatible data, and for reading and writing +// values of that type in a buffer. + +// Helper classes/extensions that don't change. +// Someday, this will be in a library of its own. + +private extension Data { + init(rustBuffer: RustBuffer) { + self.init( + bytesNoCopy: rustBuffer.data!, + count: Int(rustBuffer.len), + deallocator: .none + ) + } +} + +// Define reader functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. +// +// With external types, one swift source file needs to be able to call the read +// method on another source file's FfiConverter, but then what visibility +// should Reader have? +// - If Reader is fileprivate, then this means the read() must also +// be fileprivate, which doesn't work with external types. +// - If Reader is internal/public, we'll get compile errors since both source +// files will try define the same type. +// +// Instead, the read() method and these helper functions input a tuple of data + +private func createReader(data: Data) -> (data: Data, offset: Data.Index) { + (data: data, offset: 0) +} + +// Reads an integer at the current offset, in big-endian order, and advances +// the offset on success. Throws if reading the integer would move the +// offset past the end of the buffer. +private func readInt(_ reader: inout (data: Data, offset: Data.Index)) throws -> T { + let range = reader.offset ..< reader.offset + MemoryLayout.size + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + if T.self == UInt8.self { + let value = reader.data[reader.offset] + reader.offset += 1 + return value as! T + } + var value: T = 0 + let _ = withUnsafeMutableBytes(of: &value) { reader.data.copyBytes(to: $0, from: range) } + reader.offset = range.upperBound + return value.bigEndian +} + +// Reads an arbitrary number of bytes, to be used to read +// raw bytes, this is useful when lifting strings +private func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> [UInt8] { + let range = reader.offset ..< (reader.offset + count) + guard reader.data.count >= range.upperBound else { + throw UniffiInternalError.bufferOverflow + } + var value = [UInt8](repeating: 0, count: count) + value.withUnsafeMutableBufferPointer { buffer in + reader.data.copyBytes(to: buffer, from: range) + } + reader.offset = range.upperBound + return value +} + +// Reads a float at the current offset. +private func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float { + return try Float(bitPattern: readInt(&reader)) +} + +// Reads a float at the current offset. +private func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double { + return try Double(bitPattern: readInt(&reader)) +} + +// Indicates if the offset has reached the end of the buffer. +private func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool { + return reader.offset < reader.data.count +} + +// Define writer functionality. Normally this would be defined in a class or +// struct, but we use standalone functions instead in order to make external +// types work. See the above discussion on Readers for details. + +private func createWriter() -> [UInt8] { + return [] +} + +private func writeBytes(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 { + writer.append(contentsOf: byteArr) +} + +// Writes an integer in big-endian order. +// +// Warning: make sure what you are trying to write +// is in the correct type! +private func writeInt(_ writer: inout [UInt8], _ value: T) { + var value = value.bigEndian + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) } +} + +private func writeFloat(_ writer: inout [UInt8], _ value: Float) { + writeInt(&writer, value.bitPattern) +} + +private func writeDouble(_ writer: inout [UInt8], _ value: Double) { + writeInt(&writer, value.bitPattern) +} + +// Protocol for types that transfer other types across the FFI. This is +// analogous to the Rust trait of the same name. +private protocol FfiConverter { + associatedtype FfiType + associatedtype SwiftType + + static func lift(_ value: FfiType) throws -> SwiftType + static func lower(_ value: SwiftType) -> FfiType + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType + static func write(_ value: SwiftType, into buf: inout [UInt8]) +} + +// Types conforming to `Primitive` pass themselves directly over the FFI. +private protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType {} + +extension FfiConverterPrimitive { + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public static func lift(_ value: FfiType) throws -> SwiftType { + return value + } + + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public static func lower(_ value: SwiftType) -> FfiType { + return value + } +} + +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`. +// Used for complex types where it's hard to write a custom lift/lower. +private protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {} + +extension FfiConverterRustBuffer { + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public static func lift(_ buf: RustBuffer) throws -> SwiftType { + var reader = createReader(data: Data(rustBuffer: buf)) + let value = try read(from: &reader) + if hasRemaining(reader) { + throw UniffiInternalError.incompleteData + } + buf.deallocate() + return value + } + + #if swift(>=5.8) + @_documentation(visibility: private) + #endif + public static func lower(_ value: SwiftType) -> RustBuffer { + var writer = createWriter() + write(value, into: &writer) + return RustBuffer(bytes: writer) + } +} + +// An error type for FFI errors. These errors occur at the UniFFI level, not +// the library level. +private enum UniffiInternalError: LocalizedError { + case bufferOverflow + case incompleteData + case unexpectedOptionalTag + case unexpectedEnumCase + case unexpectedNullPointer + case unexpectedRustCallStatusCode + case unexpectedRustCallError + case unexpectedStaleHandle + case rustPanic(_ message: String) + + public var errorDescription: String? { + switch self { + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer" + case .incompleteData: return "The buffer still has data after lifting its containing value" + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1" + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases" + case .unexpectedNullPointer: return "Raw pointer value was null" + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code" + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified" + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already" + case let .rustPanic(message): return message + } + } +} + +private extension NSLock { + func withLock(f: () throws -> T) rethrows -> T { + lock() + defer { self.unlock() } + return try f() + } +} + +private let CALL_SUCCESS: Int8 = 0 +private let CALL_ERROR: Int8 = 1 +private let CALL_UNEXPECTED_ERROR: Int8 = 2 +private let CALL_CANCELLED: Int8 = 3 + +private extension RustCallStatus { + init() { + self.init( + code: CALL_SUCCESS, + errorBuf: RustBuffer( + capacity: 0, + len: 0, + data: nil + ) + ) + } +} + +private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T { + let neverThrow: ((RustBuffer) throws -> Never)? = nil + return try makeRustCall(callback, errorHandler: neverThrow) +} + +private func rustCallWithError( + _ errorHandler: @escaping (RustBuffer) throws -> E, + _ callback: (UnsafeMutablePointer) -> T +) throws -> T { + try makeRustCall(callback, errorHandler: errorHandler) +} + +private func makeRustCall( + _ callback: (UnsafeMutablePointer) -> T, + errorHandler: ((RustBuffer) throws -> E)? +) throws -> T { + uniffiEnsureInitialized() + var callStatus = RustCallStatus() + let returnedVal = callback(&callStatus) + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler) + return returnedVal +} + +private func uniffiCheckCallStatus( + callStatus: RustCallStatus, + errorHandler: ((RustBuffer) throws -> E)? +) throws { + switch callStatus.code { + case CALL_SUCCESS: + return + + case CALL_ERROR: + if let errorHandler = errorHandler { + throw try errorHandler(callStatus.errorBuf) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.unexpectedRustCallError + } + + case CALL_UNEXPECTED_ERROR: + // When the rust code sees a panic, it tries to construct a RustBuffer + // with the message. But if that code panics, then it just sends back + // an empty buffer. + if callStatus.errorBuf.len > 0 { + throw try UniffiInternalError.rustPanic(FfiConverterString.lift(callStatus.errorBuf)) + } else { + callStatus.errorBuf.deallocate() + throw UniffiInternalError.rustPanic("Rust panic") + } + + case CALL_CANCELLED: + fatalError("Cancellation not supported yet") + + default: + throw UniffiInternalError.unexpectedRustCallStatusCode + } +} + +private func uniffiTraitInterfaceCall( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> Void +) { + do { + try writeReturn(makeCall()) + } catch { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} + +private func uniffiTraitInterfaceCallWithError( + callStatus: UnsafeMutablePointer, + makeCall: () throws -> T, + writeReturn: (T) -> Void, + lowerError: (E) -> RustBuffer +) { + do { + try writeReturn(makeCall()) + } catch let error as E { + callStatus.pointee.code = CALL_ERROR + callStatus.pointee.errorBuf = lowerError(error) + } catch { + callStatus.pointee.code = CALL_UNEXPECTED_ERROR + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error)) + } +} + +private class UniffiHandleMap { + private var map: [UInt64: T] = [:] + private let lock = NSLock() + private var currentHandle: UInt64 = 1 + + func insert(obj: T) -> UInt64 { + lock.withLock { + let handle = currentHandle + currentHandle += 1 + map[handle] = obj + return handle + } + } + + func get(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map[handle] else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + @discardableResult + func remove(handle: UInt64) throws -> T { + try lock.withLock { + guard let obj = map.removeValue(forKey: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return obj + } + } + + var count: Int { + map.count + } +} + +// Public interface members begin here. + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterUInt64: FfiConverterPrimitive { + typealias FfiType = UInt64 + typealias SwiftType = UInt64 + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt64 { + return try lift(readInt(&buf)) + } + + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + writeInt(&buf, lower(value)) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterString: FfiConverter { + typealias SwiftType = String + typealias FfiType = RustBuffer + + public static func lift(_ value: RustBuffer) throws -> String { + defer { + value.deallocate() + } + if value.data == nil { + return String() + } + let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len)) + return String(bytes: bytes, encoding: String.Encoding.utf8)! + } + + public static func lower(_ value: String) -> RustBuffer { + return value.utf8CString.withUnsafeBufferPointer { ptr in + // The swift string gives us int8_t, we want uint8_t. + ptr.withMemoryRebound(to: UInt8.self) { ptr in + // The swift string gives us a trailing null byte, we don't want it. + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1)) + return RustBuffer.from(buf) + } + } + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String { + let len: Int32 = try readInt(&buf) + return try String(bytes: readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)! + } + + public static func write(_ value: String, into buf: inout [UInt8]) { + let len = Int32(value.utf8.count) + writeInt(&buf, len) + writeBytes(&buf, value.utf8) + } +} + +public func add(left: UInt64, right: UInt64) -> UInt64 { + return try! FfiConverterUInt64.lift(try! rustCall { + uniffi_ffi_fn_func_add( + FfiConverterUInt64.lower(left), + FfiConverterUInt64.lower(right), $0 + ) + }) +} + +public func greet(name: String) -> String { + return try! FfiConverterString.lift(try! rustCall { + uniffi_ffi_fn_func_greet( + FfiConverterString.lower(name), $0 + ) + }) +} + +private enum InitializationResult { + case ok + case contractVersionMismatch + case apiChecksumMismatch +} + +// Use a global variable to perform the versioning checks. Swift ensures that +// the code inside is only computed once. +private let initializationResult: InitializationResult = { + // Get the bindings contract version from our ComponentInterface + let bindings_contract_version = 26 + // Get the scaffolding contract version by calling the into the dylib + let scaffolding_contract_version = ffi_ffi_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version { + return InitializationResult.contractVersionMismatch + } + if uniffi_ffi_checksum_func_add() != 13861 { + return InitializationResult.apiChecksumMismatch + } + if uniffi_ffi_checksum_func_greet() != 9569 { + return InitializationResult.apiChecksumMismatch + } + + return InitializationResult.ok +}() + +private func uniffiEnsureInitialized() { + switch initializationResult { + case .ok: + break + case .contractVersionMismatch: + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + case .apiChecksumMismatch: + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} + +// swiftlint:enable all diff --git a/platforms/swift/ZKsyncSSO/Tests/ZKsyncSSOTests/ZKsyncSSOTests.swift b/platforms/swift/ZKsyncSSO/Tests/ZKsyncSSOTests/ZKsyncSSOTests.swift new file mode 100644 index 0000000..00c1413 --- /dev/null +++ b/platforms/swift/ZKsyncSSO/Tests/ZKsyncSSOTests/ZKsyncSSOTests.swift @@ -0,0 +1,10 @@ +import Testing +@testable import ZKsyncSSO + +@Test func testGreetRust() async throws { + #expect(greetRust(name: "Rust") == "Hello, Rust") +} + +@Test func testAddRust() async throws { + #expect(addRust(left: 2, right: 2) == 4) +}