Продолжаю бороться с типами. Есть надежда, что FFI (Foreign Function Interface) – это самая сложная и последняя часть, где система типов в Rust будет доставлять серьезные неудобства. Пока что, главное выстраданное правило гласит: если тебе Rust не дает написать какую-то конструкцию, то эта конструкция зло. То есть не надо пытаться обмануть систему типов и писать “как привык в C++”. Довольно простой, если верить документации на сайте Rust, интерфейс FFI оказался с заковырками. Даже пришлось создать маленькую песочницу для игр именно с FFI.
Наверное самая поразившая меня фича в этой области Rust-а – преобразование типов, особенно при работе с массивами. Простейший пример (
println!("type: {}, ptr: 0x{:x}, len {}",
type_of(&array), array.as_ptr() as u64, array.len());
let new_array: &[u32] = unsafe { mem::transmute(array) }; // (2)
println!("type: {}, ptr: 0x{:x}, len {}",
type_of(&new_array), new_array.as_ptr() as u64, new_array.len());
Классический вопрос из разряда “а что оно напечатает?”. Кажется что всё невероятно просто, создаем массив
type: &'static [u32], ptr: 0x1037a1414, len 4
Но был сильно удивлен. Дело в том, что по мнению компилятора Rust второй массив хоть и является массивом uint32, но по прежнему содержит 4 элемента, т.е. конверсия делается в лоб и только для типа, но не размера и физический размер “вырос” в 4 раза без перераспределения памяти.
При этом вроде как правильное решение будет выглядеть следующим образом:
slice::from_raw_parts_mut(array.as_ptr() as *mut u32,
array.len() / mem::size_of::<u32>())
};
println!("type: {}, ptr: 0x{:x}, len {}",
type_of(new_array_2), new_array_2.as_ptr() as u64, new_array_2.len());
Хотя меня гложут сомнения на тему того, что я правильно всё делаю, так как вывести новый размер массива вроде очень просто из чего следует что я вызвал какую-то неправильную функцию, или правильную, но криво…