2015-03-21 4 views
4

Я пытаюсь сделать ржавчину dylib и использовать ее с других языков, таких как C, Python и другие. Я успешно вызвал функцию функции Rust и аргумент i32 из python. Теперь я пытаюсь сделать функцию, которая принимает массив (указатель на него или все необходимое для передачи набора данных в Rust lib).Передайте массив C в функцию Rust

#![crate_type = "dylib"] 
#[no_mangle] 
pub extern fn rust_multiply(size: i32, arrayPointer: &i32) -> i32 
{ 
    *(arrayPointer) 
} 

Это работает должным образом. Но

#![crate_type = "dylib"] 
#[no_mangle] 
pub extern fn rust_multiply(size: i32, arrayPointer: &i32) -> i32 
{ 
    *(arrayPointer + 1) // trying to get next element 
} 

терпит неудачу с

src/lib.rs:5:2: 6:2 error: type `i32` cannot be dereferenced 
src/lib.rs:5 *(arrayPointer + 1) 
src/lib.rs:6 } 

Кроме этого:

pub extern fn rust_multiply(size: i32, array: &[i32]) -> i32 

и делать что-то вроде array[0] терпит неудачу с "длина = 0" ошибки.

+1

Возможно, вы не хотите иметь функции 'extern', которые принимают' i32' или ссылки (например, '& i32'). Лучше использовать типы C, которые гарантированно соответствуют вашей платформе - 'libc :: uint32_t', как показано в ответе. Кроме того, ссылки Rust * гарантированы * как не-NULL, но нет ничего, что обеспечивало бы это, когда вы отказываетесь от FFI. Было бы безопаснее принять '* const libc :: uint32_t' (опять же, как показано в ответе), а затем утверждать, что он не является NULL, прежде чем превращать его в ссылку. – Shepmaster

ответ

7

Вам необходимо приложить усилия, чтобы обеспечить чистую C api и реализовать некоторые преобразования с использованием небезопасного кода. К счастью, это не так уж сложно:

extern crate libc; 

#[no_mangle] 
pub extern fn rust_multiply(size: libc::size_t, array_pointer: *const libc::uint32_t) -> libc::uint32_t { 
    internal_rust_multiply(unsafe { std::slice::from_raw_parts(array_pointer as *const i32, size as usize) }) as libc::uint32_t 
} 

fn internal_rust_multiply(array: &[i32]) -> i32 
{ 
    assert!(!array.is_empty()); 
    array[0] 
} 

Существует хорошее введение для ржавчины FFI on the official site.

+4

Обратите внимание, что при использовании небезопасного блока ** до программиста ** для проверки того, что код соответствует всем требованиям Rust для безопасности. В этом примере ссылки могут ** никогда не быть 'NULL', поэтому у вас действительно должно быть утверждение, что' array_pointer' не является 'NULL' (если вы как-то не можете гарантировать, что это никогда не будет, что еще более жестче). – Shepmaster

+0

@Shepmaster, который поставляется с территорией (C FFI). И обратите внимание, что указатели '&' должны быть также не нулевыми, поэтому, если он может когда-либо быть нулевым, подпись в коде OP также неверна. – delnan

+2

@ delnan Я мог бы не понимать вашу точку зрения. Я хочу сказать, что '* const libc :: uint32_t' разрешено быть NULL, потому что это совершенно верно C, как вы упомянули. Этот код преобразует его в срез, который * не позволяет * указателю данных быть NULL (не уверен, что длина входит в игру - имеет значение, если данные NULL, если длина равна '0'?). Я просто говорю, что перед вызовом 'from_raw_parts' должен быть' assert! (Array_pointer! = Std :: ptr :: null()) '. Это все о том, чтобы защитить себя от сумасшедших абонентов C, насколько это возможно. – Shepmaster

0

Просто хочу указать, что в коде @ swizard он получает unsigned ints и преобразовывает их в подписанные ints. Код, который вы, вероятно, хотите, -

extern crate libc; 

#[no_mangle] 

pub extern fn rust_multiply(size: libc::size_t, array_pointer: *const libc::int32_t) -> libc::int32_t { 
    internal_rust_multiply(unsafe { std::slice::from_raw_parts(array_pointer as *const i32, size as usize) }) as libc::int32_t 
} 

fn internal_rust_multiply(array: &[i32]) -> i32 
{ 
    assert!(!array.is_empty()); 
    array[0] 
}