Обробка помилок CXX: Приклад PNG

Прототип декодера PNG ілюструє, що можна зробити, коли успішний результат не може бути переданий через межу FFI:

#[cxx::bridge(namespace = "gfx::rust_bindings")] mod ffi { extern "Rust" { /// Повертає дружній до FFI еквівалент `Result<PngReader<'a>, /// ()>`. fn new_png_reader<'a>(input: &'a [u8]) -> Box<ResultOfPngReader<'a>>; /// Зв'язування C++ для типу `crate::png::ResultOfPngReader`. type ResultOfPngReader<'a>; fn is_err(self: &ResultOfPngReader) -> bool; fn unwrap_as_mut<'a, 'b>( self: &'b mut ResultOfPngReader<'a>, ) -> &'b mut PngReader<'a>; /// Зв'язування C++ для типу `crate::png::PngReader`. type PngReader<'a>; fn height(self: &PngReader) -> u32; fn width(self: &PngReader) -> u32; fn read_rgba8(self: &mut PngReader, output: &mut [u8]) -> bool; } }

Speaker Notes

PngReader та ResultOfPngReader є типами Rust — об’єкти цих типів не можуть перетинати межу FFI без опосередкування Box<T>. Ми не можемо мати out_parameter: &mut PngReader, оскільки CXX не дозволяє C++ зберігати об’єкти Rust за значенням.

Цей приклад ілюструє, що навіть якщо CXX не підтримує довільні узагальнення або шаблони, ми все одно можемо передати їх через межу FFI, вручну спеціалізувавши / мономорфізувавши їх до не узагальненого типу. У прикладі ResultOfPngReader є не узагальненим типом, який передається у відповідні методи Result<T, E> (наприклад, у is_err, unwrap та/або as_mut).