Я разработал библиотеку на Rust для анализа содержимого RTF. Изначально я ориентировался на архитектуру x86. Поэтому я использовал множество фрагментов строк (&str
) для ссылки на исходный источник без копирования его содержимого. Например, Token
выглядит так:
enum Token<'a> {
PlainText(&'a str),
OpeningBracket,
ClosingBracket,
...
}
Я хочу обновить свою библиотеку, чтобы она также ориентировалась на WebAssembly. Я заглянул в ящик wasm-bingen и книгу Rust Wasm, и оказалось, что wasm_bindgen
не поддерживает ни ссылки, ни времена жизни.
Есть ли у меня элегантное решение адаптировать мою кодовую базу для поддержки WebAssembly без ущерба для начальной производительности?
У меня есть условная компиляция, но у меня все еще есть проблема с жизнью:
#[cfg(not(target_arch = "wasm32"))]
pub type StrRef<'a> = &'a str;
#[cfg(target_arch = "wasm32")]
pub type StrRef = String;
Как я могу предоставить это перечисление Token
, например, для использования в среде JS?
Ящик wasm-bindgen
их не поддерживает. Я пытаюсь ссылаться на фрагменты строк и иметь согласованную кодовую базу между x86 и wasm.
Вероятно, у меня есть для вас ответ, но мне нужны некоторые разъяснения. Не могли бы вы отредактировать свой вопрос, включив в него следующее: (1) Ваша цель написать библиотеку Rust, которую можно скомпилировать в целевой объект wasm32, написать библиотеку Rust, которую можно будет использовать непосредственно из JavaScript, или что-то еще? ? (2) С какой именно проблемой вы столкнулись при попытке использовать свой код со ссылками без изменений? Wasm-bindgen заботится только об элементах с аннотациями #[wasm_bindgen]
, поэтому простая компиляция для Wasm должна работать, если вы не вносите другие изменения.
Спасибо за ваш ответ, я отредактировал свой вопрос. Я хочу открыть перечисление Token
для JS, но у меня возникли проблемы с wasm-bindgen
из-за ссылки &str
и времени жизни, которые на данный момент не поддерживаются.
Здесь больше проблем, чем вы обнаружили.
В JavaScript нет средства проверки заимствований, поэтому не существует бесплатного способа использовать долгоживущие ссылки за пределами FFI, поскольку ничто не может гарантировать, что они останутся действительными при использовании. Вы вообще не можете вернуть тип со временем жизни в JS.
Вы также не можете делиться строками без копирования. JavaScript String
непрозрачен — вы не можете получить доступ к их байтам, только к их символам — но, скорее всего, они закодированы в UTF-16. Rust &str
по определению указывает на текст, закодированный в UTF-8. Итак, нет и не может быть способа свободно разделять строковые буферы между JavaScript и Rust.
(Вы можете избежать копирования текста строки, используя js_sys::JsString, который указывает на объект JS String в куче JS, но тогда вам придется выполнять отдельные мостовые операции для доступа к тексту из этой строки, поэтому вряд ли будет быстрее.)
Ваш Token
тип вообще не подойдет. Вы не можете экспортировать перечисление с полями, поскольку в JS нет типов перечислений/дискриминируемых объединений. Вам нужно будет найти способ выразить свои токены в виде объектов JS.
Учитывая все эти проблемы, я бы рекомендовал вместо того, чтобы пытаться использовать условную компиляцию для корректировки определений типов, создавать отдельные типы и функции, предназначенные для предоставления JS-совместимого API, который имеет наибольший смысл для JS. Подойдите к этому как к обертыванию существующей библиотеки, а не как к ее изменению для обеспечения совместимости.
Фактически, вам следует рассмотреть возможность выделения этой оболочки привязки JS в отдельный контейнер, который зависит от вашей библиотеки. Если вы вставите экспорт #[wasm_bindgen]
в свою основную библиотеку Rust, это означает, что каждая сборка Rust-to-WebAssembly, включая вашу библиотеку, будет включать весь этот экспорт в JS, даже если ваша библиотека используется исключительно другим кодом Rust в этом одном модуле Wasm. (Это может даже вызвать конфликт имен.) Разделение означает, что экспорт JS присутствует только тогда, когда он необходим.
Спасибо за ваш ответ, я думаю, что выберу вариант с отдельным ящиком, который кажется лучшим для моего случая.
Что вы имеете в виду, что WebAssembly не поддерживает ни ссылки, ни время жизни? конечно, это так. На что вы пытаетесь сделать ссылку?