Обработка ошибок CXX: пример с PNG
Прототип декодера PNG показывает, что можно сделать, когда успешный результат нельзя передать через границу FFI:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
#[cxx::bridge(namespace = "gfx::rust_bindings")]
mod ffi {
extern "Rust" {
/// Это возвращает эквивалент `Result<PngReader<'a>,
/// ()>`, удобный для FFI.
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).