CXX Error Handling: PNG Example

Un prototipo de un decodificador PNG ilustra lo que se puede hacer cuando el resultado correcto no se puede transmitir a través del límite de FFI:

#[cxx::bridge(namespace = "gfx::rust_bindings")]
mod ffi {
    extern "Rust" {
        /// Esto devuelve un equivalente de `Result<PngReader<'a>,
        /// ()>`, compatible con FFI.
        fn new_png_reader<'a>(input: &'a [u8]) -> Box<ResultOfPngReader<'a>>;

        /// Enlaces de C++ para el tipo `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>;

        /// Enlaces de C++ para el tipo `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 y ResultOfPngReader son tipos de Rust. Los objetos de estos tipos no pueden cruzar el límite de FFI sin la indirección de un Box<T>. No se puede tener un out_parameter: &mut PngReader, ya que CXX no permite que C++ almacene objetos de Rust por valor.

Este ejemplo ilustra que, aunque CXX no es compatible con plantillas ni genéricos arbitrarios, podemos transmitirlos a través de los límites de FFI si los especializamos de forma manual o los monomorfizamos en un tipo no genérico. En el ejemplo, ResultOfPngReader es un tipo no genérico que redirige los métodos adecuados de Result<T, E> (por ejemplo, a is_err, unwrap o as_mut).