Предлагаю обсудить опыт интеграции Rust в другие языки, с целью расширения какой-то среды исполнения или при переписывании кода на другом языке на Rust.
Начну и предлагаю всем делиться опытом использования Rust из других языков и других языков из Rust.
У меня есть проект, который реализует движок исполнения скриптов на Lua, и предоставляет скриптам API для управления несколькими нативными объектами: виртуальными и физическими машинами (через единый API) и процессами на данной машине. Для примера, с машинами можно делать:
запускать данный образ ОС на них
включать/выключать/перезагружать
получать вывод из последовательного порта
писать в последовательный порт
над выводом можно делать дальнейшие действия, типа сравнения с образцом (простым или с использованием регвыров)
По сути это всё похоже на операционную систему в миниатюре. Когда в скрипте написано
machine = Machine.new(config)
Rust создаёт реальную структуру Machine, в которой лежит вся необходимая для управления информация, а в Lua отдаёт хэндл - просто индекс в массив машин на стороне Rust.
Для всего этого я пользуюсь hlua.
Что нравится:
ядро на Rust - безопасно, удобно, легко расширять (например сериализовать результат выполнения скрипта в JSON);
Что не нравится:
hlua - довольно сырая штука, и там помимо багов встречаются полностью нереализованные возможности; некоторые фиксы заблокированы продвинутыми возможностями компилятора. На данный момент она не поддерживается и очень напрашивается форк.
Подробнее можно посмотреть в слайдах к прошлогоднему докладу.
На данный момент используем библиотеку jni-rs, которая предоставляет Rust-байндинги для довольно известного Java Native Interface. Написание кода для связи двух языков выглядит довольно прямолинейно - в Java достаточно объявить нативный метод, в Rust - его реализовать с правильной сигнатурой.
Основные проблемы - с передачей сложных структур данных между языками и с обработками исключений, которые могут возникать как с одной, так и с другой стороны.
Впрочем, работает все довольно неплохо и стабильно.
Есть и другие проекты по взаимодействию Rust <-> Java: JNR, JNA и перспективный GraalVM.
Мы уже не раз рассказывали про проект на различных конференциях: раз, два, три
Но твой вариант тоже не сказать что стабильный, как ты пишешь. Да и потом вроде у тебя не такие сложные задачи требуются от скрипта решать. Хотя могу ошибаться. Я бы глянул от задач, если хватает, то может все таки стоит выбрать скриптовый язык который более удобно с растом конектится, да и вроде как развитие есть.
уже несколько месяцев как вступил на “скользкую” дорожку раста… и не жалею.
Хотя несколько раз пребывал в таком тупике, что думал - а может ну его нафиг.
В основном работаю над сопряжением работы ИЗ Rust с базовой библиотекой разбора протокола написанной на С.
Непонятки были с тем что генерил bindgen для undefined size array in struct
ну и поддержка сишных Variadic functions вызывало вопросы и озабоченность.
Rust подкинул мне несколько идей.
В частности, думал и решил - полностью перехожу на строки в формате UTF8 . Это позволит отказаться от необходимости при описании протокола указывать сколько байт занимает один char данной строки.
Да, вычисление количества символов в строке будет не таким простым, но мой анализ показывает, что чаще всего длинна строки была нужна, и использовалась, чтобы отвести под её хранение, перемещение необходимое число байт.
Вот этот разрыв в мозгу, прямой зависимости между числом символов в строке и числом байт, потребовал усилий…
архитектуру сишного кода в некоторых аспектах переосмыслил.
А вообще команда у раста просто отличная. Страшно доволен языком и языковыми конструкциями.
Раньше подумывал после версии для Rust буду пилить версию для C++ … теперь однозначно решил, что C++ версии не будет.
атавизм ибо.
Вариант стабильный, т.е. он не меняется спонтанно.
Это известный язык с обширной документацией, и заведомо известно что сам язык достаточно матёрый, чтобы не иметь проблем с самим интерпретатором.
Другой скриптовый язык, который на коленке делают в опенсорсе, будет также подвержен проблеме что его не поддерживают - только не поддерживают уже не только FFI-обёртку, а интерпретатор в целом.
В конечном счёте пользуюсь этим не я один и Lua - это понятный выбор, а никому не известный скриптовый язык на расте - нет.
Поступаем просто - не передаем . На данный момент необходимости в передаче сложных структур данных нет, нам требуются только примитивы, с которыми проблем нет. Для обратного взаимодействия (Вызова Java-методов из Rust) используются прокси-объекты - указатель на Java-объект (инстанс класса) хранится в структуре, которая реализует нужный нам трейт, вызывая Java-методы. пример
А с исключениями что делаете? Кажется размотка стека через границу FFI это UB.
Хороший вопрос. Если не ошибаюсь, начиная с 1.25 (или 1.26) - размотка стека больше не UB, просто приводит к abort. В любом случае, исключения джавы и паники раста аккуратно ловятся, приводятся в читаемый вид и печатаются в лог, что сильно помогает находить ошибки. Вспомогательный код для этого дела написан методом проб и ошибок и может выглядеть страшно
Выглядит очень любопытно, спасибо!
На данный момент мы рассматриваем различные альтернативные подходы к байндингам, думаю на этот вариант тоже взглянем.