Комментарии 12
Как в Rust-е сделать объектную динамически-подключаемую библиотеку.
На Java, C#, Python и т.п. объекты стандартизированы. Т.е. ты в своем классе реализуешь какой-то интерфейс и подключаешь свой плагин к основной программе.
В Rust-е, я так понимаю, можно реализовывать только Си-шные функции. И вся прелесть раста при этом теряется.
Если хочется сделать доступ через C ABI, то делаем тип либы dylib, выключаем манглинг функций для нашего интерфейса и приводим свой API к сишным сигнатурам. Собственный отдельный ржавый FFI уже много лет в разработке, но и работы там непочатый край ибо никто не осилил пока оформить какой-то пропозал, удовлетворяющий эту хотелку. В некотором экспериментальном виде для WASM можно использовать interface types, так что в теории если ваш wasm рантайм их поддерживает, то можно делать через него подключаться.
В остальном не очень понятно какие ещё вам варианты нужны? Общение между языками традиционно происходит через C ABI происходит, хоть в python, хоть в go, хоть в java и пока что лучше ничего не придумали. Есть отдельные крейты, позволяющие работать с этими языками на уровне объектов этих языков - например, pyo3 для питона или robusta для JNI.
Попробую по другому объяснить. Есть внешняя, динамически-подключаемая, библиотека, которая тоже написана на Rust. Но, несмотря на то, что она написана на Rust-е, я должен вызывать её методы в Unsafe-блоках. В Java, C#, Python и т.д. в аналогичной ситуации внешний вызов не отличается от вызова внутренней функции и соблюдаются все защиты, заложенные в языке.
А большие приложения никогда не идут одним исполняемым файлом, т.е. Rust не готов к использованию в больших приложениях.
Или я ошибаюсь?
Судя по докам и обсуждениям динамические либы доступны только через С API, поэтому да, даже если она на Rust, она будет считаться за либу на другом языке и необходимы врапперы поверх unsafe кода. WASM+WASI модули в теории могут позволить избегать этого, но принципиально ситуация не меняется.
А большие приложения никогда не идут одним исполняемым файлом, т.е. Rust не готов к использованию в больших приложениях.
Не вижу принципиальной разницы, если б всё писалось на том же C/С++. Оно буквально работает "как у всех". С тем же успехом можно сказать, что и С/С++ не готовы к использованию в больших приложениях.
В Java, C#, Python и т.д. в
эти языки по-умолчанию имеют некоторый рантайм с некоторым окружением и пространством имён, в который они могут импортировать внешние модули. Они не имеют гарантий безопасности аналогичных Rust и фактически превращаются в каст void* к сигнатуре, которую вы представили. В Rust вам необходимо представить какие-то гарантии относительно загружаемого модуля компилятору, т.к. нет никакого рантайма, поэтому да - unsafe и врапперы - ваш вариант. Благо их кажется можно генерировать автоматически через макросы.
Они не имеют гарантий безопасности аналогичных Rust и фактически превращаются в каст void* к сигнатуре, которую вы представили.
Я думаю человек выше больше подразумевал что конечные бинарники Java/C# содержат в себе метаинформацию(рефлексию) о всех структурах/классах и методах внутри, так что их можно динамически подключать с гарантией что нужный класс реализует заданный интерфейс. В расте же при компиляции никакой метаинформации вроде того какие трейты для какой структуры реализованы не сохраняется, по-этому динамическая загрузка библиотеки всегда будет unsafe.
вроде того какие трейты для какой структуры реализованы не сохраняется
не совсем так. оно в том или ином виде будет ссылаться на некоторые виртуальные таблицы, которые можно отрефлексировать при желании, но из-за того язык компилируемый гарантии интерфейса намертво зашиваются в бинарь. У managed языков есть рантайм, который позволяет его расширять и работать с ним как будто рабочее окружение было таким всегда.
crate-type = ["dylib"]
https://stackoverflow.com/a/75903553
Другое дело, что у раста ABI пока ещё (?) не стабилизировано, так что динамические библиотеки и код придётся собирать одинаковой версией компилятора.
Но проблемы с unsafe-блоками не вижу, если у вас есть исходники библиотеки.
фьючерса
Фьючерсы - это термин из финансов. В расте они фьючи или футуры aka Future<T>.
вызов
send()
блокирует текущий поток до тех пор, пока в канале имеется место для новых сообщений
Разве не наоборот?
Unbounded в случае очередей будет логичнее назвать безразмерной.
Rust
имеет систему задач (task system), которая является формой легковесного трейдинга (threading).
tokio, не rust
Для того, чтобы это работало, клиент и сервер должны находиться в директории
src/bin
(см. документацию).
Это один из вариантов.
Проще указать path в cargo:
https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target
Асинхронные методы в трейтах пока не поддерживаются в стабильной версии
Rust
.
Стабилизировали еще в конце прошлого года
Практическое руководство по Rust. Бонус