Ответ 1
Когда вы увидите что-то вроде этого (в C):
struct S {
void (*f)(int, long)
}
это означает, что struct S
содержит поле под названием f
, которое является указателем на функцию. Это не значит, что сама библиотека предоставляет функцию под названием f
. Например, это действительно:
void some_function_1(int x, long y) { ... }
void some_function_2(int a, long b) { ... }
int main() {
struct S s1; s1.f = some_function_1;
struct S s2; s2.f = some_function_2;
}
Здесь struct instance s1
содержит указатель на some_function_1
, а s2
содержит указатель на some_function_2
.
Когда вы пишете привязку FFI в Rust для некоторой библиотеки C, вы обычно определяете копии Rust для структур C. Некоторые инструменты, такие как rust-bindgen
, могут сделать это автоматически. В вашем случае вам придется написать что-то вроде этого:
#[repr(C)]
struct LxcContainer {
name: *mut c_char,
configfile: *mut c_char,
// ...
numthreads: c_int,
// ...
is_defined_f: extern fn(c: *mut LxcContainer) -> bool,
state_f: extern fn(c: *mut LxcContainer) -> *const c_char,
// ...
}
То есть, странные типы указателей функций C соответствуют типам указателей функций extern fn
в Rust. Вы также можете написать extern "C" fn(...) -> ...
, но "C"
определитель по умолчанию, поэтому он не требуется.
Вам нужно будет написать что-то вроде этого, чтобы вызвать эти функции:
impl LxcContainer {
fn is_defined_f(&mut self) -> bool {
unsafe {
(self.is_defined_f)(self as *mut LxcContainer)
}
}
}
Вам нужно указать ссылку на необработанный указатель, а также скопировать self.is_defined_f
в круглые скобки, чтобы устранить неоднозначность между вызовом метода и доступом к полю.
Подробнее о FFI в Rust здесь. Однако указатели на функции объясняются очень кратко.