Внимание: с этой статьёй вы не освоите 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. И у меня были на то свои причины:

  1. Rust — это совершенно новый язык (новый и блестящий), в котором учтён опыт его старших собратьев для избежания «ошибок» экосистемы и использования лучших практик. (Я был реально заинтригован.)
  2. Создали его замечательные ребята из Mozilla, которые хорошо поработали над документацией mdn (Mozilla Developer Network — сеть разработчиков Mozilla). Это сообщество, которое поддерживает интересные проекты с открытым исходным кодом, такие как a-frame, servo, mozillaThings и т.д.
  3. У него классное название! На ум сразу же приходит альбом группы Megadeth “Rust in peace”(в переводе на русский «Ржавей с миром»).
  4. Погуглив Rust, можно быстро обнаружить, что в его основе лежит парадигма «функционального» программирования, а его переменные совершенно неизменяемы по умолчанию (если не задействуется ключевое слово mut).
  5. Заметил, что у него есть поддержка асинхронной среды выполнения, а я обожаю использовать неблокирующие функции, promises, async/await.
  6. Кроме того, здесь есть хорошая система типов (на данный момент она не очень последовательна, зато есть дженерики).

Руководствовался я здесь скорее стремлением к большему удобству при написании кода, нежели какими-то соображениями, касающимися производительности или эффективности (безопасность доступа к памяти или небольшой размер двоичного кода, например). Просто мне нужен был язык, позволяющий писать в том стиле, который мне нравится (функциональный, но не только; с типами, с возможностями асинхронного программирования и т. д.).

Изучаем Rust онлайн

Есть хороший учебный курс Rust Fundamentals, посвящённый основам Rust, который можно смотреть на популярном онлайн-ресурсе pluralsight. Кроме того, я часто заглядываю в официальную документацию. Её составители потрудились на славу. Могу лишь пожелать вам проводить там столько же времени, сколько я посвящаю MDN. 🙂

Настройка среды разработки

Понадобится установить инструменты rust (компилятор, диспетчер пакетов, менеджер версий и т.д.). Следуйте инструкциям.

? Примечание: Cargo — это как npm, rustup аналогичен nvm, а rustc — это компилятор, и я бы сказал, что он аналогичен tsc, но не могу: ведь он компилирует код не в другой высокоуровневый язык, а в бинарный код.

И снова WASM — запускаем пилотную версию

Очень хорошая документация (eng) поможет разобраться. Для быстрого запуска используйте краткое руководство (eng) по установке средств разработки 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, и документация у него отличная.

Читайте также:


Перевод статьи Liron Hazan: Intro to WebAssembly via Rust

Предыдущая статья7 причин выгорания программистов
Следующая статьяИспользуйте перечисления, а не логические аргументы