Как вызывать функции Rust в приложении Deno? | 🏆 Первый прием работ по технической тематике

задняя часть внешний интерфейс Rust deno
Как вызывать функции Rust в приложении Deno? | 🏆 Первый прием работ по технической тематике

Ключевые моменты:

  • И Deno, и Node.js выполняют JavaScript в среде выполнения на основе C/C++ для обеспечения высокой производительности.
  • Deno — это отдельное бинарное приложение, несовместимое с модулями NPM, и нет простого способа включить нативные модули в приложение.
  • WebAssembly позволяет запускать высокопроизводительный код в приложениях Deno.
  • WebAssembly используется для серверных приложений и представляет собой безопасный, легкий и легкий контейнер.
  • Инструментарий компилятора Rust обеспечивает мощную поддержку WebAssembly.

Долгожданный проект Deno недавно выпустил версию 1.0. Deno был запущен Райаном Далем, одним из создателей Node.js, для решения того, что Райан считает «10 вещами, о которых я сожалею о Node.js».

Deno не принимает NPM и печально известнуюnode_modules. Deno — это единый двоичный исполняемый файл, который запускает приложения, написанные на TypeScript и JavaScript.

Однако, хотя TypeScript и JavaScript подходят для большинства веб-приложений, они не подходят для ресурсоемких задач, таких как обучение нейронных сетей и вывод, машинное обучение и криптография. На практике для выполнения этих задач Node.js часто требуются собственные библиотеки (например, шифрование с помощью openssl).

Как мы можем писать на Deno серверные приложения, требующие собственной производительности, без системы, подобной NPM, для включения собственных модулей? WebAssembly поможет! В этой статье мы пишем высокопроизводительные функции на Rust, компилируем функции Rust в WebAssembly и запускаем их в приложении Deno.

TL;DR

клон или форк на GitHubСтартовый шаблон Deno. Следуйте приведенным ниже инструкциям, и вы сможете запустить функцию WebAssembly (написанную на Rust) в Deno всего за 5 минут.

жизненный опыт

Node.js настолько успешен, потому что он дает разработчикам лучшее из обоих миров: простоту использования JavaScript (особенно для асинхронных приложений, основанных на событиях) и высокую производительность C/C++. Приложения Node.js написаны на JavaScript, но выполняются в собственной среде выполнения на основе C/C++, например, в механизме JavaScript Google V8 и во многих модулях собственной библиотеки. Deno хочет воспроизвести эту формулу успеха, но с другой стороны, Deno поддерживает современный технологический стек с помощью TypeScript и Rust.

Deno написан на Rust, простой, современной и безопасной среде выполнения для JavaScript и TypeScript на основе V8. - сайт deno.land.

В знаменитом выступлении «10 вещей, о которых я сожалею о Node.js» создатель Node.js Райан Даль объясняет, почему он основал Deno и считает Deno конкурентом или даже заменой Node.js. Сожаления Даля сосредоточены на том, как Node.js управляет сторонним кодом и модулями.

  • Сложная система сборки для подключения модулей C к Node.js.
  • package.json,node_modules,index.jsи другие артефакты NPM очень сложны, но не обязательны.

Таким образом, Deno делает очень осознанный и осознанный выбор, когда дело доходит до управления зависимостями.

  • Deno — это один двоичный исполняемый файл.
  • Приложение написано на TypeScript или JavaScript, а зависимости явно объявлены в коде какimportоператор с полным URL-адресом для ссылки на исходный код зависимости.
  • Deno не совместим с модулями Node.js.

Это хорошо. Но как насчет приложений, требующих более высокой производительности? В частности, как насчет приложений ИИ как услуги, которые должны выполнять сложные модели нейронных сетей за считанные секунды? В Deno и Node.js многие функции вызываются через TypeScript или JavaScript API, но эти функции выполняются в нативном коде, написанном на Rust или C. В Node.js всегда есть возможность вызывать сторонние нативные библиотеки из JavaScript API. Но разве мы не можем сейчас сделать это в Deno?

Поддержка WebAssembly в Deno

WebAssembly — это облегченная виртуальная машина, предназначенная для выполнения переносимого байт-кода почти на исходной скорости. Вы можете скомпилировать функции Rust или C C++ в байт-код WebAssembly, а затем получить доступ к этим функциям из TypeScript. Для некоторых задач это намного быстрее, чем выполнение эквивалентной функции, написанной на TypeScript. Например, исследование, опубликованное IBM, показало, что использование Rust и WebAssembly в определенных алгоритмах обработки данных может увеличить скорость выполнения Node.js на 1200-1500%.

Deno использует внутри себя движок Google V8. V8 — это не только среда выполнения JavaScript, но и виртуальная машина WebAssembly. Deno поддерживает WebAssembly из коробки. Deno предоставляет API для приложений TypeScript для вызова функций в WebAssembly.

Фактически, некоторые популярные компоненты Deno уже реализованы в WebAssembly. Например, используйте Emscripten для компиляции исходного кода sqlite C в WebAssembly для созданиямодуль sqlite.Компоненты Deno WASIДелает приложения WebAssembly доступными для базовых ресурсов операционной системы, таких как файловая система. В этой статье будет показано, как писать высокопроизводительные приложения Deno на Rust и WebAssembly.

настраивать

Первый шаг, конечно же, установкаDeno, в большинстве операционных систем требуется только одна строка команды

$ curl -fsSL https://deno.land/x/install/install.sh | sh

Поскольку мы собираемся писать функции на Rust, нам также необходимо установить компилятор и инструменты для языка Rust.

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

наконец-то,ssvmupИнструмент автоматизирует процесс сборки и генерирует все артефакты, облегчая приложениям Deno вызов функций Rust. Опять же, необходимо установить зависимость ssvmup.

$ curl https://raw.githubusercontent.com/second-state/ssvmup/master/installer/init.sh -sSf | sh

Примечание: ssvmup используетwasm-bindgenАвтоматически генерируйте «связующий» код между исходным кодом JavaScript и Rust, чтобы JavaScript и Rust могли взаимодействовать, используя соответствующие собственные типы данных. Без ssvmup аргументы функций и возвращаемые значения были бы ограничены простыми типами, изначально поддерживаемыми WebAssembly (т. е. 32-битными целыми числами). Например, без ssvmup иwasm-bindgen, вы не можете использовать строки или массивы.

Hello world

Во-первых, давайте взглянем на Deno'shello worldНапример, получите исходный код и шаблон приложения hello world с GitHub.

Функции Rust находятся вsrc/lib.rsфайл, просто добавьте «привет» к входной строке. Уведомление,say()использование функции #[wasm_bindgen]Аннотировано, чтобы ssvmup мог генерировать необходимые «трубы». Исходя из этого, мы можем вызывать функции Rust из TypeScript.

#[wasm_bindgen]
pub fn say(s: &str) -> String {
  let r = String::from("hello ");
  return r + s;
}

Приложение Deno находится по адресуdeno / server.tsв файле. Приложение импортирует Rust из файла pkg/functions_lib.js.say()функция, которая генерируется инструментом ssvmup.functions_lib.jsИмя файла зависит отCargo.tomlИмя проекта Rust, определенное в файле.

import { serve } from "https://deno.land/std@0.54.0/http/server.ts";
import { say } from '../pkg/functions_lib.js';

type Resp = {
    body: string;
}

const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
  let r = {} as Resp;
  r.body = say (" World\n");
  req.respond(r);
}

Теперь запустите ssvmup, чтобы построить функцию Rust как функцию Deno WebAssembly.

$ ssvmup build --target deno

После успешного завершения ssvmup вы можете проверитьpkg / functions_lib.jsчтобы узнать, как выполнять скомпилированные файлы WebAssembly с помощью API Deno WebAssembly.pkg / functions_lib.wasm.

Затем запустите приложение Deno. Deno требуется разрешение на чтение файловой системы, потому что ему нужно загружать файлы WebAssembly. В то же время Deno также необходим доступ к сети, поскольку ему необходимо получать HTTP-запросы и отвечать на них.

$ deno run --allow-read --allow-net deno/server.ts

Теперь в другом окне терминала вы можете получить доступ к веб-приложению Deno и поздороваться через HTTP-соединение!

$ curl http://localhost:8000/

hello World

сложный пример

Этот проект начального шаблона включает множество подробных примеров, показывающих, как передавать сложные данные между функциями Deno TypeScript и Rust. Этоsrc/lib.rsдругие функции Rust в . Обратите внимание, что они оба используют#[wasm_bindgen]Примечания.

#[wasm_bindgen]
pub fn obfusticate(s: String) -> String {
  (&s).chars().map(|c| {
    match c {
      'A' ..= 'M' | 'a' ..= 'm' => ((c as u8) + 13) as char,
      'N' ..= 'Z' | 'n' ..= 'z' => ((c as u8) - 13) as char,
      _ => c
    }
  }).collect()
}

#[wasm_bindgen]
pub fn lowest_common_denominator(a: i32, b: i32) -> i32 {
  let r = lcm(a, b);
  return r;
}

#[wasm_bindgen]
pub fn sha3_digest(v: Vec<u8>) -> Vec<u8> {
  return Sha3_256::digest(&v).as_slice().to_vec();
}

#[wasm_bindgen]
pub fn keccak_digest(s: &[u8]) -> Vec<u8> {
  return Keccak256::digest(s).as_slice().to_vec();
}

Пожалуй, самое интересноеcreate_line()функция. Эта функция ожидает две строки JSON. Каждая строка представляет собойPointstruct и возвращает представлениеLineСтрока JSON структуры. Уведомление,Pointа такжеLineструктура используетсяSerializeа такжеDeserializeаннотировано так, чтоRustКомпилятор автоматически генерирует необходимый код для их поддержки.JSONПреобразование между строками.

use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Point {
  x: f32,
  y: f32
}

#[derive(Serialize, Deserialize, Debug)]
struct Line {
  points: Vec<Point>,
  valid: bool,
  length: f32,
  desc: String
}

#[wasm_bindgen]
pub fn create_line (p1: &str, p2: &str, desc: &str) -> String {
  let point1: Point = serde_json::from_str(p1).unwrap();
  let point2: Point = serde_json::from_str(p2).unwrap();
  let length = ((point1.x - point2.x) * (point1.x - point2.x) + (point1.y - point2.y) * (point1.y - point2.y)).sqrt();

  let valid = if length == 0.0 { false } else { true };
  let line = Line { points: vec![point1, point2], valid: valid, length: length, desc: desc.to_string() };
  return serde_json::to_string(&line).unwrap();
}

#[wasm_bindgen]
pub fn say(s: &str) -> String {
  let r = String::from("hello ");
  return r + s;
}

Далее, давайте рассмотрим программу JavaScriptdeno/test.ts, который показывает, как вызывать функцию Rust.Stringа также&strэто простая строка в JavaScript,i32это число, иVec <u8>или&[8]это JavaScriptUint8Array. Объекты JavaScript должны быть переданы в первую очередьJSON.stringify()илиJSON.parse()для перехода в функцию Rust или возврата из нее.

import { say, obfusticate, lowest_common_denominator, sha3_digest, keccak_digest, create_line } from '../pkg/functions_lib.js';

const encoder = new TextEncoder();

console.log( say("SSVM") );
console.log( obfusticate("A quick brown fox jumps over the lazy dog") );
console.log( lowest_common_denominator(123, 2) );
console.log( sha3_digest(encoder.encode("This is an important message")) );
console.log( keccak_digest(encoder.encode("This is an important message")) );

var p1 = {x:1.5, y:3.8};
var p2 = {x:2.5, y:5.8};
var line = JSON.parse(create_line(JSON.stringify(p1), JSON.stringify(p2), "A thin red line"));
console.log( line );

После запуска ssvmup для сборки библиотеки Rust запуск deno/test.ts в среде выполнения Deno приводит к следующему выводу:

$ ssvmup build --target deno
... Building the wasm file and JS shim file in pkg/ ...

$ deno run --allow-read deno/test.ts
hello SSVM
N dhvpx oebja sbk whzcf bire gur ynml qbt
246
Uint8Array(32) [
  87, 27, 231, 209, 189, 105, 251,  49,
  ... ...
]
Uint8Array(32) [
  126, 194, 241, 200, 151, 116, 227,
  ... ...
]
{
  points: [ { x: 1.5, y: 3.8 }, { x: 2.5, y: 5.8 } ],
  valid: true,
  length: 2.2360682,
  desc: "A thin red line"
}

Что дальше?

Теперь мы можем создавать функции Rust и получать доступ к функциям Rust из приложений Deno TypeScript. Затем мы можем писать ресурсоемкие задачи с помощью функций Rust и обслуживать высокопроизводительные и безопасные веб-сервисы через Deno. Примеры таких услуг включаютмашинное обучениеа такжеИдентификация изображения.

🏆 Первый выпуск технической тематики | Расскажем немного о Deno...