مدیریت خطا CXX: مثال PNG

نمونه اولیه PNG decoder نشان می‌دهد که وقتی نتیجه موفقیت آمیز نمی‌تواند از مرز FFI عبور کند و چه کاری می توان انجام داد:

#[cxx::bridge(namespace = "gfx::rust_bindings")]
mod ffi {
    extern "Rust" {
        /// This returns an FFI-friendly equivalent of `Result<PngReader<'a>,
        /// ()>`.
        fn new_png_reader<'a>(input: &'a [u8]) -> Box<ResultOfPngReader<'a>>;

        /// C++ bindings for the `crate::png::ResultOfPngReader` type.
        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++ bindings for the `crate::png::PngReader` type.
        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 هستند --- objectهای از این نوع نمیتوانند بدون جهت‌گیری غیرمستقیم Box<T> از مرز FFI عبور کنند. ما نمی‌توانیم out_parameter: &mut PngReader داشته باشیم، زیرا CXX به ++C اجازه نمی‌دهد Rust object ها را براساس مقدار ذخیره کند.

این مثال نشان می‌دهد که حتی اگر CXX از genericها و templateهای دلخواه پشتیبانی نمی‌کند، ما همچنان می‌توانیم آنها را از مرز FFI عبور دهیم و آنها را به‌صورت دستی تخصصی/تک‌شکلی ( specializing / monomorphizing) در یک نوع غیرعمومی تبدیل کنیم. در مثال ResultOfPngReader یک نوع non-generic است که به متدهای مناسب Result<T, E> (به عنوان مثال به «is_err»، «unwrap» و/یا «as_mut» ارسال می‌شود.