Передача R c вперед и назад между C ++ и Rust - PullRequest
2 голосов
/ 19 июня 2020

Согласно ответу на этот мой вопрос: Как удерживать объекты Rust в коде Rust, созданном с помощью C ++? Я могу передать обратно C что-то выделенное в Rust внутри Box, а затем получить его обратно как ссылку на &T, потому что Rust выделяет Sized структур с соблюдением C ABI.

Я хочу сделать то же самое, но теперь для Rc<RefCell<T>>. Стоит ли возвращать Box на Rc<RefCell<T>>? Я предполагаю, что нет, поскольку Rc не реализует Sized, который требуется для T в Box<T> в соответствии со страницей Box . Так что это не сработает:

#[no_mangle]
pub extern "C" fn foo_new() -> Box<Rc<RefCell<T>>> {
    Box::new(Foo { glonk: false })
}

Как я могу заставить это работать? По сути, мне нужно создать структуру Rust, к которой могут получить доступ многие, и которая может быть взаимно заимствована одним из них. Поэтому я выбираю Rc<RefCell<T>>. Может быть, есть другой тип структуры, которая может делать то, что я хочу, и быть C дружелюбной?

1 Ответ

4 голосов
/ 19 июня 2020

Оба интеллектуальных указателя Rc<T> и Box<T> действительно имеют размер , они реализуют Sized. Эта информация не представлена ​​в документации, вероятно, из-за особого характера Sized: она всегда автоматически выводится для всех типов, где это применимо, и эта реализация не может быть добавлена ​​или отменена (в отличие от Send и Sync) .

Если это не учитывать, инкапсуляция другого интеллектуального указателя в Box не принесет особой пользы. Если есть намерение переместить фактический интеллектуальный указатель (Rc) через границу C FFI и обратно, нужно иметь в виду только одну вещь: макет Rc<T> несовместим с необработанным указателем. , даже если T равно Sized ( в отличие от Box<T>).

Следовательно, нам нужно явно преобразовать его в необработанный указатель и обратно. Функции into_raw и from_raw также доступны для Rc.

/// create a new Foo and give it to caller
#[no_mangle]
pub extern "C" fn foo_new() -> *const RefCell<Foo> {
    Rc::into_raw(Rc::new(RefCell::new(Foo { glonk: false })))
}

/// clone the pointers into two
#[no_mangle]
pub extern "C" fn foo_clone(foo: *const RefCell<Foo>) -> (*const RefCell<Foo>, *const RefCell<Foo>) {
    unsafe {
        let ptr = Rc::from_raw(foo);
        let c = Rc::clone(ptr);
        (ptr, c)
    }
}

/// get a property of a Foo without returning ownership
#[no_mangle]
pub extern "C" fn foo_glonk(foo: *const RefCell<Foo>) -> bool {
    unsafe { (*foo).borrow().glonk }
}

/// return ownership of the Foo,
/// so it can be freed in Rust-land
#[no_mangle]
pub extern "C" fn foo_return(foo: *const RefCell<Foo>)  {
    let _ = Rc::from_raw(foo);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...