Можете ли вы запустить код ржавчины из библиотеки c, вызываемой из ржавчины?

Я просмотрел ржавый интерфейс внешних функций и успешно (и счастливо) может вызывать библиотеку c из моего кода ржавчины.

Однако я не могу найти никаких подробностей о том, как зарегистрировать обратный вызов для вызова кода ржавчины, из области c-кода.

Возможно ли это?

В качестве оправдания для "почему бы вам это сделать?"; в частности, я смотрю на встраивание lua или python в приложение с ржавчиной и выставляя скрипты-api для скриптов, которые выполняются во встроенной среде выполнения.

Вызов этих элементов будет выглядеть следующим образом:

  • Загрузка основных ресурсов ржавчины
  • Приложение использует ffi для инициализации времени выполнения скриптов.
  • Приложение связывает локальные функции ржавчины с C-обратными вызовами
  • Приложение вызывает ffi, чтобы связать C-обратные вызовы с уровнем сценариев
  • Приложение работает ~
  • Периодически ffi используется для запуска исполняемого файла сценариев для выполнения блоков байт-кода
  • Код сценария выполняет различную тривиальную логику и вызывает связанные ручки
  • Связанные дескрипторы ссылаются на код c
  • Связанный c-код вызывает локальный код ржавчины

Все эти шаги, за исключением выделенных жирным, мне удалось получить работу, и я проделал какую-то тривиальную работу с помощью планировщика, который C-callbacks запускает команды "запустите меня" в очередь и когда управление возвращается в область ржавчины, приложение запрашивает очередь и запускает в ней команды...

... но это немного неудобно со стороны сценариев, потому что это означает множественные вложенные обратные вызовы async, а точка слоя сценариев - это упростить код, который должен войти в слой сценариев.

Ответ 1

Да, вы можете передать функцию обратного вызова из Rust в C и вызвать ее там. Главное знать, что вам нужно определить функцию с атрибутом extern "C".

Неподтвержденный пример (здесь нет компилятора Rust):

Сторона ржавчины:

extern "C" fn callback(a:i32) {
    println!("I'm called from C with value {0}", a);
}

#[link(name = "mylib")]
extern {
   fn register_callback(cb: extern "C" fn(i32)) -> i32;
}

fn main() {
    unsafe {
        register_callback(callback);
    }
    ...
}

C сторона:

typedef void (*rust_callback)(int32_t);
rust_callback cb;

int32_t register_callback(rust_callback callback) {
    cb = callback;
    return 1;
}

void thread() {
  // do sth
  cb(xyz);
}