Как стать автором
Обновить

Комментарии 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.

Стабилизировали еще в конце прошлого года

Зарегистрируйтесь на Хабре, чтобы оставить комментарий