Обробка помилок 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;
}
}
PngReader
та ResultOfPngReader
є типами Rust --- об'єкти цих типів не можуть перетинати межу FFI без опосередкування Box<T>
. Ми не можемо мати out_parameter: &mut PngReader
, оскільки CXX не дозволяє C++ зберігати об'єкти Rust за значенням.
Цей приклад ілюструє, що навіть якщо CXX не підтримує довільні узагальнення або шаблони, ми все одно можемо передати їх через межу FFI, вручну спеціалізувавши / мономорфізувавши їх до не узагальненого типу. У прикладі ResultOfPngReader
є не узагальненим типом, який передається у відповідні методи Result<T, E>
(наприклад, у is_err
, unwrap
та/або as_mut
).