Передать черту Rust на 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 в process_trait. Я делаю что-то неправильно? Я попытался немного изменить это, даже при кастинге, я получаю либо эту ошибку, либо неправильный тип.

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

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

person User    schedule 02.04.2015    source источник


Ответы (1)


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

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

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

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

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

person Community    schedule 02.04.2015
comment
Я не такой уж большой эксперт, поэтому я, вероятно, не понимаю многого из того, что вы здесь написали, но у меня есть комментарий по поводу конца. C никаким образом не взаимодействует с данными, кроме создания моста между кодом Rust (который имеет обратные вызовы). Я собираюсь протестировать этот метод, но он кажется правильным (судя по объяснению). Спасибо - person User; 02.04.2015
comment
Но как мне интегрировать этот TraitObject код в мою функцию-признак? - person User; 02.04.2015
comment
@User Этот код не относится ни к какому признаку. Это автономная функция, которая позволяет коду C вызывать метод для &MyTrait, не зная, как Rust реализует вызовы методов для объектов типажей. - person ; 02.04.2015
comment
Я думаю, вы неправильно поняли, код C не должен взаимодействовать с трейтом, ему просто нужно передать трейт в обратный вызов ржавчины - person User; 02.04.2015
comment
@User Пожалуйста, добавьте более конкретное описание того, что вы пытаетесь сделать (и на каком языке) в вопрос. Примеры псевдокода или тому подобное. Мне сложно представить, с какой именно проблемой вы столкнулись. - person ; 02.04.2015
comment
Код без объекта признака: is.gd/yCJ2SU Код с: is.gd/VkMeSs Оба файла не компилируются. - person User; 02.04.2015
comment
@User Важная часть - это то, что код C делает с Scope. И это any_function(param: MyTrait) не работает, не имеет ничего общего с C или FFI. - person ; 02.04.2015
comment
похоже, что я спросил в IRC, и теперь у меня есть ответ, это просто требует некоторого тестирования, хотя спасибо за ваш ответ :) - person User; 02.04.2015