0
<< предыдущая заметкаследующая заметка >>
09 марта 2023
Веб-разработка: wasm, rust и yew

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

Оказывается, в современных браузерах есть две возможности написать исполняемый код: это язык JavaScript и бинарный кроссплатформенный ассемблер WASM. Который по сути не язык, а результат компиляции с другого языка, например C++, GO или Rust.

Поначалу я воодушевился и даже думал, не переписать ли мне движок блога на wasm. Но оказалось, что практического смысла у wasm немного: он обычно не быстрее JS, не надежнее, не экономичнее, и уж точно не компактнее. Никаких новых фич и лазеек программисту он не открывает: как и для JS, тут действуют ровно те же политики безопасности, те же ограничения на соединения и доступ к в файловой системе. Однако есть два типа задач, где WASM будет полезен. Во-первых, это могучие вычисления, которые надо производить в браузере у пользователя. Ну, не знаю, обрабатывать мегатаблицы. Или сложными алгоритмами найти на фотке лицо и подрисовать усы и рога. Во-вторых — это использование готовых библиотек, которые почему-то (почему?) были написаны не на JS, а на C или Rust. Например, какие-то обработки изображений или процедуры блокчейна.

Про Rust пока не буду ничего говорить, надо разобраться ещё и попривыкнуть. А вот про yew (один из способов превратить Rust в wasm) скажу. Оказалось, это какой-то клон React. По крайней мере, у него подозрительно совпадает синтаксис и библиотеки. React — поделка, рожденная в недрах бесовского Фейсбука.

Но если поставлена задача собрать браузерный код на библиотеках Rust, то иного пути нет. Поэтому я пока успешно сделал модельку на yew, которая достаточно кривым способом (умнее пока не придумал) получает некие данные (строку), передает ее в подгруженный файл.wasm (240кб говна), где находится обработчик на Расте, который выдает результат:

Это транслятор чисел в кодировке Compact. Можно вводить например:
а) Число, например 12345 (результат: кодировка Scale в HEX, получается 2 байта: 0xe5c0)
б) hex-строку, начинающуюся с 0x, например: 0xe5c0 (результат: раскодированное 12345)
в) также можно просто ввести HEX-массив, начинающийся с 0X (заглавная), и получить число, где первый байт считается младшим

Смысла в этой софтинке немного, за исключением того, что это работают на Расте библиотеки hex="0.4.3" и parity-scale-codec="3.1.5", успешно превратившись в браузерный ассемблер.

Кому интересно (но в первую очередь для себя), положу код здесь:

показать

Cargo.toml

[package]
name "touch_wasm"
version 
"0.1.0"
authors = ["LLeo <lleo@lleo.me>"]
edition = "
2021"
license = "MIT OR Apache-2.0"

[dependencies]
yew = { path "/home/work/RUST/web/yew-yew-v0.19.3/packages/yew" }
gloo-utils = "
0.1"
gloo = "
0.8"
js-sys = "
0.3"

hex = "
0.4.3"
parity-scale-codec = "
3.1.5"
?>


index.html

<!DOCTYPE html>
<
html lang="en">
  <
head>
    <
meta charset="utf-8" />
    <
title>Yew • touch_wasm</title>

<
script>function wasmt_go() {
    
document.querySelector('#wasmt_in').innerHTML=document.querySelector('#wasmt_input').value;
    
document.querySelector('#wasmt_button').click();
}</
script>

</
head><body>

<
div id="wasmt_in" style="display:none"></div>
<
div id="wasmt_buka" style="border:1px solid red;display:inline-block;position:relative;padding:10px;"></div>
<
div>
<
input id="wasmt_input" size="32" onchange="wasmt_go()">
<
input type="button" value="GO" onclick="wasmt_go()">
</
div>

</
body></html>

src/main.rs

// yew::set_event_bubbling(false);

use yew::{prelude::*}; // , html::IntoPropValue
use js_sys::Date;
use 
parity_scale_codec::{CompactDecodeEncode};

// Define the possible messages which can be sent to the component
pub enum Msg {
    
Set,
}

pub struct App {
    
stringString,
    
valuei64// This will store the counter value
}

impl Component for App {
    
type Message Msg;
    
type Properties = ();

    fn 
create(_ctx: &Context<Self>) -> Self {
        
Self value0string"started".to_string() }
    }

    fn 
update(&mut self_ctx: &Context<Self>, msgSelf::Message) -> bool {
        match 
msg {
            
Msg::Set => {
                
let document gloo_utils::document();
                
let mut moo document.query_selector("#wasmt_in").unwrap().unwrap().inner_html();

                let str = moo.clone();

                if str.starts_with("
0x") { // если это SCALE HEX

                    
let str = &str[2..]; // убираем '0x'
                    
let mut bytes: &[u8] = &hex::decode(str).unwrap_or((&[0]).to_vec()); // раскодируем из HEX
                    
let scale Compact::<u128>::decode(&mut bytes)
                    .
unwrap_or(parity_scale_codec::Compact(0)); // переведем из SCALE
                    
let r bytes.len(); // сколько осталось после выбора первого scale
                    
if == {
                        
moo format!("scale-число {} = {:}", &str,&scale);
                    } else {
                        let ost = hex::encode(bytes); // остаток неиспользованных байт
                        moo = format!("scale-число {} = {:} {}"
,
                            &
str[0..(str.len()-ost.len())],
                            &
scale,
                            
format!("остаток {}: {ost}",ost.len()/2)
                        );
                    }

                } else if str.starts_with("
0X") { // если это просто HEX без всякого SCALE
                    
let str = &str[2..]; // убираем 0x
                    
let bytes: &[u8] = &hex::decode(str).unwrap_or((&[0]).to_vec()); // раскодируем из HEX
                    
let mut bytes128: [u816] = Default::default(); // готовим массив для u128
                    
bytes128[0..bytes.len()].copy_from_slice(&bytes); // копируем в него из нашего массива сколько надо
                    
let value u128::from_le_bytes(bytes128); // переводим в число u128
                    
moo=format!("hex-число {} = {}", &str, value );

                } else {
                    // str.as_str()
                    let value: u128 = u128::from_str_radix(str.as_str(), 10).unwrap_or(0); // переводим в число u128
                    let scale = Compact(value).encode(); // переводим в Compact
                    let hex = hex::encode(scale); // кодируем в HEX
                    moo=format!("число: {} = {} scale-hex ({}): 0x{}"
, &strvaluehex.len()/2hex);
                }

             
self.string moo// moo.to_uppercase(); // format!("[ {:} [{:}] ]", "er".to_string() , moo );
                 
self.value += 1;
                 
true // Return true to cause the displayed change to update
            
}
        }
    }

    fn 
view(&selfctx: &Context<Self>) -> Html {
        
let d Date::new_0();
        
let t format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
            
d.get_full_year(),d.get_month()+1,d.get_day(),
            
d.get_hours(),d.get_minutes(),d.get_seconds()
        );

        
html! {
            <
div>{ self.string.clone() }</div>
            
// hidden div
            
<div style="width:0;height:0;" id="wasmt_button" onclick={ctx.link().callback(|_Msg::Set)}></div>
            
// update time
            
<p style="font-size:8px">{ } {" №"}{ self.value }</p>
        </>}
    }
}

fn main() {
    let document = gloo_utils::document();
    let mount_point = document.query_selector("
#wasmt_buka").unwrap().unwrap();
    
yew::start_app_in_element::<App>(mount_point);
}

А как вы думаете, какие интересные штуки можно реализовать на wasm вместо JS?


UPD: Подумав, удалил все комменты про React, он вообще не тема сегодняшней заметки, а был упомянут лишь в контексте, что на него похож yew, на котором я делал wasm, что мне не сильно понравилось. Откуда разгорелся такой флейм и кому он нужен — загадка. Пойду удалю все комменты на эту тему, включая свои. Приношу извинения всем, кого так больно ранит мое мнение про React, Facebook, Windows и ряд других религиозных святынь. Это мое личное мнение, мой собственный осознанный выбор между альтернативами, я время от времени высказываю свое мнение в своем личном дневнике, но никому не навязываю. Просто разрешите мне иметь собственное мнение, не надо так оскорбляться.

<< предыдущая заметка следующая заметка >>
пожаловаться на эту публикацию администрации портала
архив понравившихся мне ссылок

Комментарии к этой заметке скрываются - они будут видны только вам и мне.

Оставить комментарий