How to pass an array of strings from Swift


I'm new to rust and intrigued by the potential it seems to have for working with strings. My first hands-on experience is thanks to this fine gentleman's efforts. Here is the relevant module. He demonstrates how you can pass a string from Swift to Rust and get the levenshtein index.

I wonder what the best way is to pass an entire array of strings to do something with it in Rust. However, I am stopped short with not FFI-safe warnings. I tried a few things like defining something like a StringBridge struct, but that doesn't seem to solve the Sized conformance issues - and from what I've seen it's not as simple as extending my struct by declaring conformance and then implementing whatever is necessary for the struct to conform, or is there a way to do this? (Like one would do in Swift by conforming to Hashable or ExpressibleByFloatLiteral or w/e.)

I've been hacking my way through to something that's obviously stupid, but should illustrate what I mean. Interestingly, here the compiler gives me the not FFI-safe warning, too, but I can call it from Swift nevertheless.

use std::ffi::CStr;
use std::os::raw::{c_char, c_double, c_long};

pub extern "C" fn leven_loop_feeding_through_callback(indices: c_long, callback: fn(&c_long) -> *const c_char) -> c_double {
    let strings: Vec<String> = (0..indices)
            .map(|idx| unsafe { CStr::from_ptr(callback(&idx)) }.to_str().unwrap().to_string())

    // Do whatever
    let mut sum: f64 = 0.0;
    for _ in 0..2500 {
        for word in &strings {
            for other in &strings {
                let count_sum = (word.len() + other.len()) as f64;
                let dist = levenshtein::levenshtein(&word, &other) as f64;
                sum += (count_sum-dist)/count_sum;
    return sum

From Swift:

let mock: [String] = ["hello", "bonjour", "hola", "hallo"]
let sum: Double = leven_loop_feeding_through_callback(mock.count) { ptr -> UnsafePointer<Int8>? in
    let mockAgain: [String] = ["hello", "bonjour", "hola", "hallo"]
    let index: Int = ptr!.pointee
    let cString: [CChar] = mockAgain[index].cString(using: .utf8)!
    return UnsafePointer<Int8>(cString) // dangling pointer warning

Is the entire approach flawed (wanting to pass in String-Arrays) and should I thus consider a different one? If you have pointers to stuff that helps me understand this better, that would be great! Do you know about good resources that address common challenges with bridging? The compiler also suggests to consider using a raw pointer instead, how would one do that given an array of strings?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.