Estoy tratando de llamar al código Rust desde mi proyecto C para un dispositivo integrado. El dispositivo imprime sobre UART, por lo que puedo ver cuál es el resultado de mi llamada.
El siguiente código C y Rust funciona como se esperaba (he omitido una gran cantidad de código Rust repetitivo que se necesita para compilarlo).
C:
uint8_t input[] = {1,2,3}; uint8_t output[] = {4,5,6}; output = func(input, output); printf("Sum: %d", output[0]);Óxido:
#[no_mangle] pub extern fn func(input: &[u8], dst: &mut[u8]) -> u8 { 3 }Esto imprime 3 como se esperaba. Pero estoy atascado en la mutación de las matrices pasadas como referencias:
C:
uint8_t input[] = {1,2,3}; uint8_t output[] = {4,5,6}; func(input, output); printf("Sum: %d", output[0]);Óxido:
#[no_mangle] pub extern fn func(input: &[u8], dst: &mut[u8]) { for i in (0..1) { dst[i] = input[i]; } }Esto compila, pero imprime 4 en lugar del 1 esperado. Por alguna razón, no puedo cambiar el valor de la matriz. ¿Algunas ideas?
EDITAR: Las declaraciones de la función C son respectivamente:
extern uint8_t func(uint8_t in[64], uint8_t output[64]); extern void func(uint8_t in[64], uint8_t output[64]);EDIT2: Código actualizado: C:
uint8_t input[64]; uint8_t output[64]; for(uint8_t = 0; i < 64; i++) { input[i] = i; } func(input, output); printf("Sum: %d", output[2]);Espera salida 2.
Una &[T] en Rust no es lo mismo que una T [] o una T * en C. Nunca debe usar punteros prestados para interactuar con el código C de Rust. Tampoco debe usar nunca [T] o str al interactuar con el código C.
nunca
[T] y str son tipos de tamaño dinámico , lo que significa que todos los punteros hacia ellos (de cualquier tipo) tienen el doble del tamaño de un puntero normal. Esto significa que su código C pasa dos punteros, mientras que Rust espera cuatro . Es un pequeño milagro que tu segundo ejemplo no te explote en la cara.
El ejemplo de Slice Arguments de Rust FFI Omnibus es casi exactamente lo que desea.
También está el capítulo FFI del Rust Book .
Editar : esas firmas C también son falsas; en primer lugar, no hay límite en el tamaño de las matrices que Rust aceptará en cualquier lugar, por lo que no estoy seguro de dónde vino 64 . Un tipo Rust vagamente comparable sería [u8; 64] , pero incluso eso sería incorrecto, porque C y Rust pasan matrices de tamaño fijo de manera diferente. C los pasa por referencia, Rust los pasa por valor.
Edición 2 : asumiendo que estás hablando de la segunda func , la traducción de Rust es solo:
// C ffi signature: // void copy(uint8_t src[4], uint8_t dst[4]); #[no_mangle] pub unsafe extern fn copy(src: *const [u8; 4], dst: *mut [u8; 4]) { if src.is_null() { return; } if dst.is_null() { return; } // Convert to borrowed pointers. let src: &[u8; 4] = &*src; let dst: &mut [u8; 4] = &mut *dst; for (s, d) in src.iter().zip(dst.iter_mut()) { *d = *s; } } #[cfg(test)] #[test] fn test_copy() { let a = [0, 1, 2, 3]; let mut b = [0; 4]; unsafe { copy(&a, &mut b); } assert_eq!(b, [0, 1, 2, 3]); }También encontré mucha información útil sobre esto en el libro Rust nightly, donde la función "dot_product" básicamente hace exactamente lo que estaba buscando: https://doc.rust-lang.org/nightly/book/no-stdlib .html