Rust & iOS

Let's start with Why

  • Cross-platform (including Android)
  • Reusing already written Rust crates
  • You can write Rust and still building an app

How this is gonna work?

Primitives


// C declaration 
int32_t test(int32_t x);

// Rust
#[no_mangle]
pub extern fn test(x: i32) -> i32 {
    x * 3 
}

// Swift
let a: Int32 = test(10) // a == 30


  

Strings, Swift -> Rust

// C declaration
void hello(const char* s)

// Rust
use std::os::raw::c_char;
#[no_mangle]
pub unsafe extern "C" fn hello(s: *const c_char)  {
    let str = CStr::from_ptr(s).to_string_lossy().into_owned();
    ...
}

// Swift
hello("World")

  

Strings, Rust -> Swift

// C declaration
const char* hello() 

// Rust
use std::os::raw::c_char;
#[no_mangle]
pub unsafe extern "C" fn hello() -> *const c_char {
    CString::new("World").unwrap().into_raw();
}

// Swift
let cString = hello()
let s = String(cString: cString) // "World"

  
pub fn into_raw(self) -> *mut c_char

Consumes the CString and transfers ownership of the string to a C caller.

The pointer which this function returns must be returned to Rust and reconstituted using from_raw to be properly deallocated.

...

Deallocating string

// C declaration
void cstr_free (const char* s);

// Rust
#[no_mangle]
pub unsafe extern "C" fn cstr_free(s: *mut c_char) {
    CString::from_raw(s);
}

// Swift
let cString = hello() // cString: UnsafePointer<Int8>
let s = String(cString: cString) // "World"
cstr_free(cString) 

  

Primitives and strings are ok, but what if I have a more complex data structure?

📦 also has into_raw and from_raw, but you can not access the data inside the 📦 from Swift directly.

// Rust 
pub struct Meetup { data: Vec<i32> }
#[no_mangle]
pub extern fn meetup_new() -> *mut Meetup {
    let data = Meetup{ data: vec![1, 2, 3, 4, 5] };
    Box::into_raw(Box::new(data))
}
pub extern fn meetup_count(meetup: *const Meetup) -> size_t {
    let meetup = unsafe { &*meetup };
    meetup.data.len() as size_t
}
// C declaration
struct meetup;
struct meetup *meetup_new(void);
size_t meetup_count(const struct meetup *data);

// Swift
let raw = meetup_new()
meetup_count(raw) // 5

         

Why am I doing this?

Because I'm writing a wallet for cryptocurrency written in Rust and I do not want to reimplement blockchain myself.

Ironbelly - mobile wallet for Grin

  • Grin is minimal implementation of the MimbleWimble protocol
  • React Native for UI
  • Thin Swift glue layer
  • Thin Rust bridge to the main codebase

A little demo

Materials

Well, this is it. Thank you for your attention!

This presentation: https://slides.sorokin.io/rustandios/


My Twitter, Github: @i1skn

presentation qr link