Передайте черту ржавчины в C

Я строю библиотеку Rust, которая должна вызывать некоторые функции C с объектами Rust. У меня есть черта с функцией, которая вызывает функцию C, функция C определяется в Rust следующим образом:

extern {
    fn process_trait(my_trait: MyTrait);
}

Идея состоит в том, что пользователь может реализовать признак для своей структуры и затем вызвать функции C (в основном, C затем вызывает некоторый другой Rust, который вызывает некоторые функции Trait). Ошибка здесь: the trait core::marker::Sized is not implemented for the type Selfпотому что я прохожу *self обработать Я делаю что-то неправильно? Я попытался изменить это немного, даже приведение, я получаю или эту ошибку или неправильный тип.

Я думаю, проблема в том, что он должен быть выделен кучей, нет? Единственное, чего я пытаюсь избежать, это API, который выглядит ужасно. Пользователь должен просто иметь возможность

struct MyUnit;
impl MyTrait for MyUnit...
MyUnit.callC();

1 ответ

Передавать объект trait по значению не имеет смысла, особенно при взаимодействии с C. Фактический тип (в смысле C) и его размер неизвестны, и внутри объекта нет vtable. Скорее всего, вы хотите передать характеристику (&MyTrait). Тем не менее, черты чужды C и, следовательно, делают плохой интерфейс. Хотя вы могли бы определить эквивалент core::raw::TraitObject в C делать что-либо с помощью vtable крайне уродливо, хрупко и небезопасно.

Если вам нужен полиморфизм через барьер Rust-C, явные указатели на функции являются гораздо лучшим вариантом. Вы все еще можете иметь MyTrait и callC метод, это просто части FFI, которые выглядят иначе. Может быть возможно передать обратные вызовы библиотеки C с объектами в качестве полезной нагрузки.

В качестве альтернативы, обойти вышеупомянутое TraitObjects (толстые указатели), но никогда не проверяйте их из C, вызывайте методы через (не-trait) вспомогательную функцию в Rust:

extern fn call_method(obj: TraitObject) {
    let obj: &MyTrait = transmute(obj); // should be safe, but not tested
    obj.meth();
}

Это позволяет избежать проблем, возникающих при копании вручную через Rust vtable в C.

Другие вопросы по тегам