Внимание: с этой статьёй вы не освоите Rust, зато сможете быстро разобраться и приступить к работе с WASM, используя замечательный инструментарий wasm-pack и интуитивно понятную экосистему Rust.
Недавно я начал интересоваться Rust. Вы спросите: как я дошёл до жизни такой?
В какой-то момент вокруг WASM (Web Assembly) возникла шумиха, ажиотаж, и я вдруг почувствовал необходимость вплотную заняться чем-то новым… Движуха нарастала, и мне захотелось стать частью этой вечеринки ? ? ?.
Потихоньку я начал читать о wasm здесь и тут:
«WebAssembly — это новый тип кода, исполняемый в современных веб-браузерах. Он представляет собой низкоуровневый ассемблерный язык с компактным бинарным форматом, который работает с производительностью, близкой к нативной, и служит целью компиляции для таких языков, как C/C++ и Rust, позволяя им исполнять код в Сети.Он предназначен для дополнения JavaScript, позволяя им работать вместе».
Основное, что мы можем с WASM:
- компилировать код других, высокоуровневых языков и запускать двоичный код в браузере ?;
- достигать (почти) нативной производительности;
- загружать и исполнять бинарный код WASM непосредственно из JavaScript, а также обмениваться данными с кодом JavaScript.
Пришёл за WASM, остался с Rust
Можно было бы запустить “hello world” или ещё какой-нибудь простенький пример, но мне хотелось поизучать другой язык (новую экосистему, новый мир!).
Изучение нового языка помогает лучше разбираться в основном языке, на котором работаешь: ты всё меньше обращаешь внимание на различия, всё больше замечаешь привычные шаблоны и оттого острее восприятие.
Мне пришлось выбирать между C/C++ и Rust. Недолго думая, я отдал предпочтение языку Rust. И у меня были на то свои причины:
- Rust — это совершенно новый язык (новый и блестящий), в котором учтён опыт его старших собратьев для избежания «ошибок» экосистемы и использования лучших практик. (Я был реально заинтригован.)
- Создали его замечательные ребята из Mozilla, которые хорошо поработали над документацией mdn (Mozilla Developer Network — сеть разработчиков Mozilla). Это сообщество, которое поддерживает интересные проекты с открытым исходным кодом, такие как a-frame, servo, mozillaThings и т.д.
- У него классное название! На ум сразу же приходит альбом группы Megadeth “Rust in peace”(в переводе на русский «Ржавей с миром»).
- Погуглив Rust, можно быстро обнаружить, что в его основе лежит парадигма «функционального» программирования, а его переменные совершенно неизменяемы по умолчанию (если не задействуется ключевое слово
mut
). - Заметил, что у него есть поддержка асинхронной среды выполнения, а я обожаю использовать неблокирующие функции, promises, async/await.
- Кроме того, здесь есть хорошая система типов (на данный момент она не очень последовательна, зато есть дженерики).
Руководствовался я здесь скорее стремлением к большему удобству при написании кода, нежели какими-то соображениями, касающимися производительности или эффективности (безопасность доступа к памяти или небольшой размер двоичного кода, например). Просто мне нужен был язык, позволяющий писать в том стиле, который мне нравится (функциональный, но не только; с типами, с возможностями асинхронного программирования и т. д.).
Изучаем Rust онлайн
Есть хороший учебный курс Rust Fundamentals, посвящённый основам Rust, который можно смотреть на популярном онлайн-ресурсе pluralsight. Кроме того, я часто заглядываю в официальную документацию. Её составители потрудились на славу. Могу лишь пожелать вам проводить там столько же времени, сколько я посвящаю MDN. 🙂
Настройка среды разработки
Понадобится установить инструменты rust (компилятор, диспетчер пакетов, менеджер версий и т.д.). Следуйте инструкциям.
? Примечание: Cargo — это как npm, rustup аналогичен nvm, а rustc — это компилятор, и я бы сказал, что он аналогичен tsc, но не могу: ведь он компилирует код не в другой высокоуровневый язык, а в бинарный код.
И снова WASM — запускаем пилотную версию
Очень хорошая документация (eng) поможет разобраться. Для быстрого запуска используйте краткое руководство (eng) по установке средств разработки Rust и WASM.
При запуске проекта вам кое-что понадобится:
- крейты — это сторонние зависимости, которые вы можете использовать (такие как npm portal repos);
- cargo.toml — это как package.json. Узнайте, как его читать и редактировать, а также запускать его команды (новый, установить, публиковать и т.д.). Кстати, есть также автогенерируемый Cargo.lock;
- крейты для Rust+WASM при разработке веб-приложения.
Пилотную версию я запускал, следуя этому официальному справочному руководству, в котором описано применение инструмента под названием wasm-pack:
wasm-pack— это универсальный механизм для создания, тестирования и публикации WebAssembly, сгенерированного с помощью Rust.
Этот wasm-pack я и использовал при создании своего пилотного проекта. Можете заглянуть в мой репозиторий здесь и веб-демо.
Давайте разберём самые интересные части проекта, чтобы понять, как всё это работает:
Cargo.toml:
- Крейт-зависимость web_sys — вот что нас интересует больше всего! Она даёт привязку ко всем API браузера (отражения кода механизма визуализации на C++, если я правильно понял то, что здесь написано).
- Зависимость
wasm-bindgen
: с ней я имел дело при разработке приложения (библиотека Rust и инструмент CLI, облегчающие высокоуровневое взаимодействие между JavaScript и модулями wasm).
lib.rs:
#![allow(unused_variables)]
fn main() {
use wasm_bindgen::prelude::*;
// Вызывается нашей точкой входа JS для запуска примера
#[wasm_bindgen(start)]
pub fn rust_in_peace() -> Result<(), JsValue> {
// Используем глобальную функцию `окна` от `web_sys`, чтобы избавиться от глобального
// объекта окна.
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let body = document.body().expect("document should have a body");
// Подготовим элемент, который мы будем добавлять
let iframe = document.create_element("iframe")?;
iframe.set_attribute("width", "560");
iframe.set_attribute("height", "315");
iframe.set_attribute("src", "https://www.youtube.com/embed/Mmbo4jQBKVU");
let h2 = document.create_element("h2")?;
h2.set_inner_html("Rust In Peace made by Rust!");
body.append_child(&h2)?;
body.append_child(&iframe)?;
Ok(())
}
}
Обратили внимание на атрибут #[wasm_bindgen]
? Благодаря ему будут созданы 2 обёртки:
- обёртка JavaScript принимает типы JS и преобразует их в wasm;
- обёртка Rust получает типы wasm и преобразует их в типы Rust.
Больше узнать об этом можно в другой статье (eng).
Шаблон wasm-pack
Запуск сборщика модулей приведёт к созданию папок pkg и dist (файлу webpack config требуется @wasm-tool/wasm-pack-plugin, который компилирует наш ржавый код и генерирует pkg со всеми необходимыми шаблонами).
Если мы откроем index.js, находящийся в папке pkg, то увидим следующее:
import * as wasm from './index_bg.wasm';
/**
*/
export function rust_in_peace() {
wasm.rust_in_peace();
}
Wasm-pack сгенерировал обёртку JavaScript, которая вызывает нашу ржавую функцию, импортированную из бинарного кода WASM. Красота! 🙂
Фронтенд-платформы на Rust для будущих проектов
Существует множество проектов с открытым исходным кодом, которые охватывают практически все сферы, достаточно заглянуть в репозиторий awesome-rust.
Если говорить о фронтенде, можно попробовать заняться разработкой «нативных» приложений на Rust (WASM) с использованием какой-нибудь платформы, чтобы работа шла быстрее/проще/более масштабно (с точки зрения кодовой базы и архитектуры программного обеспечения).
Я предпочитаю Yew.Это современная платформа на Rust для создания внешней части (фронтенда) многопоточных веб-приложений с WebAssembly).
На сегодня это всё. Если захотите использовать связку WASM+rust, наилучшим для вас инструментом будет wasm-pack, и документация у него отличная.
Читайте также:
- Использование строк в Rust
- Кто на свете всех сильнее - Java, Go и Rust в сравнении
- Реализация base64 на Rust
Перевод статьи Liron Hazan: Intro to WebAssembly via Rust