Passing a list of strings from Python to Rust

前端 未结 1 1266
野性不改
野性不改 2021-02-13 21:31

I\'ve been learning Rust for about two weeks now and today, I got into its FFI. I used Python to play with Rust, using ctypes and libc. I passed integers, strings and even learn

相关标签:
1条回答
  • 2021-02-13 21:33

    There is absolutely no difference with the case of array of numbers. C strings are zero-terminated arrays of bytes, so their representation in Rust will be *const c_char, which could then be converted to &CStr which then can be used to obtain &[u8] and then &str.

    Python:

    import ctypes
    
    rustLib = "libtest.dylib"
    
    def testRust():
        lib = ctypes.cdll.LoadLibrary(rustLib)
        list_to_send = ['blah', 'blah', 'blah', 'blah']
        c_array = (ctypes.c_char_p * len(list_to_send))(*list_to_send)
        lib.get_strings(c_array, len(list_to_send))
    
    if __name__=="__main__":
        testRust()
    

    Rust:

    #![feature(libc)]
    extern crate libc;
    
    use std::slice;
    use std::ffi::CStr;
    use std::str;
    use libc::{size_t, c_char};
    
    #[no_mangle]
    pub extern fn get_strings(array: *const *const c_char, length: size_t) {
        let values = unsafe { slice::from_raw_parts(array, length as usize) };
        let strs: Vec<&str> = values.iter()
            .map(|&p| unsafe { CStr::from_ptr(p) })  // iterator of &CStr
            .map(|cs| cs.to_bytes())                 // iterator of &[u8]
            .map(|bs| str::from_utf8(bs).unwrap())   // iterator of &str
            .collect();
        println!("{:?}", strs);
    }
    

    Running:

    % rustc --crate-type=dylib test.rs
    % python test.py
    ["blah", "blah", "blah", "blah"]
    

    And again, you should be careful with lifetimes and ensure that Vec<&str> does not outlive the original value on the Python side.

    0 讨论(0)
提交回复
热议问题