<p align="left">
	<a href="http://tesseract.one/">
		<img alt="Tesseract" src ="./.github/logo-horiz.svg" height=128/>
	</a>
</p>

# Prerequisites
* Install your Rust nightly environment: https://www.rust-lang.org/tools/install
* Install Xcode from the App Store.
* For Rust we suggest VS Code: https://code.visualstudio.com/

Following rust targets must be installed:
```bash
rustup +nightly target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
```

# Adding Rust to your iOS App

Create a new iOS application or open your existing project.

## Copy build script

Copy Xcode build script from `Examples/Rust/xcode_build_step.sh` into your project (in this guide we assume that it is copied to the sources root folder).

## Modify your target settings in the Xcode

* Add `Run Script` phase to your target
* Move it before `Build Sources` phase
* Change script to `exec bash ${SRCROOT}/xcode_build_step.sh CApp app`. Where `CApp` is a name for the exported Swift module and `app` is a name of the rust library target in the `Cargo.toml`.

## Swift Package

* Add Package Dependency to the project: `https://github.com/tessetact-one/Tesseract.swift`.
* Add `TesseractTransportsClient` library dependency for application target.

## Create a rust library
* `cargo new app --lib`
* Add the dependencies:
```toml
[dependencies]
tesseract-swift = { version = "0.5", features = ["client"] }
tesseract-one = { version = "0.5", features = ["client"] }
tesseract-protocol-test = { version = "0.5", features = ["client"] }

[build-dependencies]
cbindgen = "0.26"
```
* specify the type of library
```toml
[lib]
crate-type = ["staticlib"]
```
* create `build.rs` file for C headers generation
```rust
extern crate cbindgen;

use std::env;
use std::path::Path;

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let profile = env::var("PROFILE").unwrap();
    let name = env::var("CARGO_PKG_NAME").unwrap();
    let header_path = Path::new(&crate_dir)
        .join("target")
        .join(&profile)
        .join("include")
        .join(format!("{}.h", name));

    cbindgen::generate(&crate_dir)
        .expect("Unable to generate bindings")
        .write_to_file(&header_path);
}
```
* Create `cbindgen.toml` file with this contents
```toml
include_version = true
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
tab_width = 2
language = "C"
documentation_style = "doxy"
pragma_once = true
cpp_compat = true
after_includes = "@import CTesseractShared;"

[enum]
prefix_with_name = true

[parse]
parse_deps = true
include = ["tesseract-swift", "tesseract-swift-utils", "tesseract-swift-transport"]

[export]
exclude = [
  "CFutureString", "SyncPtr_Void", "ClientTransport", "Void", 
  "CError", "CString", "CStringRef", "CAnyDropPtr"
]
```

Now you can export C functions, initialize Tesseract and start calling the Wallet.

## Initialize App and Tesseract in Rust

Create application initialization function in Rust. Initialize Tesseract in it
```rust
use tesseract_one;
use tesseract_protocol_test;

use tesseract_swift::error::TesseractSwiftError;
use tesseract_swift::client::transport::*;
use tesseract_swift::utils::{error::CError, ptr::SyncPtr, Void};

use std::mem::ManuallyDrop;
use std::sync::Arc;

// Your application context. Put all needed data here.
// Rust only structure
struct AppContext {
    service: Arc<dyn tesseract_one::client::Service<Protocol = tesseract_protocol_test::Test>>,
}

// Type-erased App Context pointer for Swift.
#[repr(C)]
pub struct AppContextPtr(SyncPtr<Void>);

// Helper methods for pointer
impl AppContextPtr {
    fn new(ctx: AppContext) -> Self {
        Self(SyncPtr::new(ctx).as_void())
    }

    unsafe fn unowned(&self) -> &AppContext {
        self.0.as_typed_ref().unwrap()
    }

    unsafe fn owned(&mut self) -> AppContext {
        self.0.take_typed()
    }
}

// App init method
#[no_mangle]
pub unsafe extern "C" fn app_init(
    alerts: AlertsDelegate, transport: ClientTransport,
    value: &mut ManuallyDrop<AppContextPtr>, 
    error: &mut ManuallyDrop<CError>
) -> bool {
  TesseractSwiftError::context(|| {
        let tesseract = Tesseract::new(TransportDelegate::arc(alerts))
                .transport(transport);

        let service = tesseract.service(tesseract_protocol_test::Test::Protocol);

        let context = AppContext { service };

        Ok(AppContextPtr::new(context))
    }).response(value, error)
}
```

## Call initialization function in Swift
```swift
import TesseractTransportsClient
import CApp

let rustApp = try! TResult<AppContextPtr>.wrap { value, error in
    app_init(alerts.toCore(), IPCTransportIOS().toCore(), value, error)
}.get()
```

## Usage

The rest of Tesseract APIs stay exacly the same everywhere. Please, consider to go through the docs in our [Tesseract shared Core](https://github.com/tesseract-one/Tesseract.rs) repo.

# Adding Rust to your iOS Wallet

1. Create a new iOS application or open your existing project.
2. Add Action Extension target to the project.
3. Configure Action Extension target: [Wallet Docs](./WALLET.MD)

## Copy build script

Copy Xcode build script from `Examples/Rust/xcode_build_step.sh` into your project (in this guide we assume that it is copied to the sources root folder).

## Modify your targets settings in the Xcode

* Add `Run Script` phase to your Wallet and Extension targets
* Move it before `Build Sources` phase
* Change script to `exec bash ${SRCROOT}/xcode_build_step.sh CWallet wallet`. Where `CWallet` is a name for the exported Swift module and `wallet` is a name of the rust library target in the `Cargo.toml`.

## Swift Package

* Add Package Dependency to the project: `https://github.com/tessetact-one/Tesseract.swift`.
* Add `TesseractTransportsService` library dependency for Extension target.

## Create a rust library
* `cargo new wallet --lib`
* Add the dependencies:
```toml
[dependencies]
tesseract-swift = { version = "0.5", features = ["service"] }
tesseract-one = { version = "0.5", features = ["service"] }
tesseract-protocol-test = { version = "0.5", features = ["service"] }

[build-dependencies]
cbindgen = "0.26"
```
* specify the type of library
```toml
[lib]
crate-type = ["staticlib"]
```
* create `build.rs` file for C headers generation
```rust
extern crate cbindgen;

use std::env;
use std::path::Path;

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let profile = env::var("PROFILE").unwrap();
    let name = env::var("CARGO_PKG_NAME").unwrap();
    let header_path = Path::new(&crate_dir)
        .join("target")
        .join(&profile)
        .join("include")
        .join(format!("{}.h", name));

    cbindgen::generate(&crate_dir)
        .expect("Unable to generate bindings")
        .write_to_file(&header_path);
}
```
* Create `cbindgen.toml` file with this contents
```toml
include_version = true
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
tab_width = 2
language = "C"
documentation_style = "doxy"
pragma_once = true
cpp_compat = true
after_includes = "@import CTesseractShared;"

[enum]
prefix_with_name = true

[parse]
parse_deps = true
include = ["tesseract-swift", "tesseract-swift-utils", "tesseract-swift-transport"]

[export]
exclude = [
  "CFutureBool", "SyncPtr_Void", "ServiceBoundTransport", "ServiceTransport",
  "ServiceTransportProcessor", "Void", "CError", "CString", "CStringRef", 
  "CAnyDropPtr"
]
```

Now you can export C functions, initialize Tesseract and wait accept request.

## Initialize Extension and Tesseract in Rust

Create Extension initialization function in Rust. Initialize Tesseract in it
```rust
use tesseract_one::service::Tesseract;

use tesseract_swift::error::TesseractSwiftError;
use tesseract_swift::service::transport::ServiceTransport;
use tesseract_swift::utils::{error::CError, ptr::SyncPtr, Void};

use std::mem::ManuallyDrop;
use std::sync::Arc;

// Your Extension application context. Put all needed data here.
// Rust only structure
struct ExtensionContext {
    _tesseract: Tesseract
}

// Type-erased ExtensionContext pointer for Swift.
#[repr(C)]
pub struct ExtensionContextPtr(SyncPtr<Void>);

// Helper methods for pointer
impl ExtensionContextPtr {
    fn new(ctx: ExtensionContext) -> Self {
        Self(SyncPtr::new(ctx).as_void())
    }

    unsafe fn unowned(&self) -> &ExtensionContext {
        self.0.as_typed_ref().unwrap()
    }

    unsafe fn owned(&mut self) -> ExtensionContext {
        self.0.take_typed()
    }
}

// Wallet extension init method
#[no_mangle]
pub unsafe extern "C" fn wallet_extension_init(
    signature: CStringRef, ui: UI, transport: ServiceTransport,
    value: &mut ManuallyDrop<ExtensionContextPtr>, error: &mut ManuallyDrop<CError>
) -> bool {
    TesseractSwiftError::context(|| {
        let service = TestService::new(ui, signature.try_as_ref()?.into());

        let tesseract = Tesseract::new().transport(transport).service(service);

        let context = ExtensionContext {
            _tesseract: tesseract,
        };

        Ok(ExtensionContextPtr::new(context))
    }).response(value, error)
}
```

## Call initialization function in Swift
```swift
import TesseractTransportsService
import CWallet

let transport = IPCTransportIOS(self).toCore()
let signature = "test"

let rustApp = try! TResult<ExtensionContextPtr>.wrap { value, error in
    wallet_extension_init(signature,
                          NativeUI(delegate: self).toCore(),
                          transport, value, error)
}.get()
```

## Usage

The rest of Tesseract APIs stay exacly the same everywhere. Please, consider to go through the docs in our [Tesseract shared Core](https://github.com/tesseract-one/Tesseract.rs) repo.