【Rust】ダイクストラ法

fn dijkstra(edges: Vec<Vec<[usize; 2]>>, num_v: usize)  -> Vec<usize>{
    let inf = 999;
    let mut dist = Vec::new();
    for _ in 0..num_v {
        dist.push(inf);
    }
    dist[0] = 0;

    let mut q = Vec::new();
    for i in 0..num_v {
        q.push(i);
    }
    
    while *&q.len() > 0 {
        let mut r = q[0];
        for i in &q{
            if dist[*i] < dist[r] {
                r = *i;
            }
        } 
        let n = q.iter().position(|n| *n == r).unwrap();
        let u = q[n];
        q.retain(|&x| x != u);
        
        for i in edges[u].clone() {
            if dist[i[0]] > dist[u] + i[1] {
                dist[i[0]] = dist[u] + i[1];
            }
        }      
    }
    return dist;
}

fn main() {
    let edges = vec![
        vec![[1, 4], [2, 3]],
        vec![[2, 1], [3, 1], [4, 5]],
        vec![[5, 2]],
        vec![[4, 3]],
        vec![[6, 2]],
        vec![[4, 1], [6, 4]],
        vec![],
    ];
    println!("{:?}", edges);

    println!("{:?}", dijkstra(edges, 7));
}

Compiling rust v0.1.0 (/home/vagrant/dev/algorithm/rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.24s
Running `target/debug/rust`
[[[1, 4], [2, 3]], [[2, 1], [3, 1], [4, 5]], [[5, 2]], [[4, 3]], [[6, 2]], [[4, 1], [6, 4]], []]
[0, 4, 3, 5, 6, 5, 8]

おおおお、これは凄いな…

【Rust】bellman fordアルゴリズム

最短距離を探すアルゴリズム

fn bellman_ford(edges: Vec<[usize; 3]>, num_v: usize)  -> Vec<usize>{
    let inf = 999;
    let mut dist = Vec::new();
    for _ in 0..num_v {
        dist.push(inf);
    }
    

    dist[0] = 0;
    let mut changed = true;

    while changed == true {
        changed = false;
        for edge in &edges {
            if dist[edge[1]] > dist[edge[0]] + edge[2] {
                dist[edge[1]] =  dist[edge[0]] + edge[2];
                changed = true;
            }
        }
    }
    return dist;
}

fn main() {
    let edges = vec![[0, 1, 4], [0, 2, 3], [1, 2, 1], [1, 3, 1], 
    [1, 4, 5], [2, 5, 2], [4, 6, 2], [5, 4, 1], 
    [5, 6, 4]];

    let dist = bellman_ford(edges, 7);
    println!("{:?}", dist);
}

Compiling rust v0.1.0 (/home/vagrant/dev/algorithm/rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
Running `target/debug/rust`
[0, 4, 3, 5, 6, 5, 8]

いまいちよーわからん…

【Rust】UDPのやり取り

ncコマンドの場合、”-u”がUDPを指定している
$ nc -u -l 8888
$ echo “hoge” | nc -u 127.0.0.1 8888

use std::net::UdpSocket;

fn main() -> std::io::Result<()> {
    {
        let socket = UdpSocket::bind("127.0.0.1:8080")?;

        let mut buf = [0; 100];
        let (amt, src) = socket.recv_from(&mut buf)?;

        let buf = &mut buf[..amt];
        buf.reverse();
        socket.send_to(buf, &src)?;
    }
    Ok(())
}

$ echo “hoge” | nc -u 127.0.0.1 8080

egoh

UDPのbindはできるけど、レスポンスが何かおかしい…

use std::net::UdpSocket;
use std::thread;
use std::str;

fn main() -> std::io::Result<()> {
    {
        let socket = UdpSocket::bind("127.0.0.1:8080")?;
        let mut buf = [0; 2048];
        loop {
            match socket.recv_from(&mut buf) {
                Ok((buf_size, src_addr)) => {
                    thread::spawn(move || {
                        let buf = &mut buf[..buf_size];
                        let req_msg = str::from_utf8(&buf).unwrap();
                        println!("request message: {:?}", req_msg);
                    });
                },
                Err(e) => {
                    println!("couldn't receive request: {:?}", e);
                }
            }
        }
    }
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.63s
Running `target/debug/app`
request message: “hoge\n”

なるほど、TCPだけでなく、UDPも割と簡単にできるのね。。音声、動画streamingはUDPが優れているが…

【Rust】Tokioとは?

Node.jsとGolangを合体させたもの
膨大なリクエストをシングルスレッド&イベントループ&非同期I/Oで効率よく処理するランタイム(ライブラリ)
tokioではOSではなくランタイムがタスクのスケジューリングを行う。タスク生成はtokio::spawnを呼び出す

use std::time::Duration;

#[tokio::main]
async fn main() {
    tokio::task::spawn(async {
        tokio::time::sleep(Duration::from_secs(2)).await;
        println!("Done");
    });

    std::thread::sleep(Duration::from_secs(3));
    println!("wake up");
}

シングルスレッド

use std::time::Duration;

#[tokio::main(flavor="current_thread")]
async fn main() {
    tokio::task::spawn(async {
        tokio::time::sleep(Duration::from_secs(2)).await;
        println!("Done");
    });

    std::thread::sleep(Duration::from_secs(3));
    println!("wake up");
}
use std::time::Duration;

#[tokio::main(flavor="multi_thread", worker_threads = 1)]
async fn main() {
    let cpus = num_cpus::get();
    println!("logical cores: {}", cpus);

    tokio::task::spawn(async move {
        println!("task 1 started..");
        tokio::time::sleep(Duration::from_secs(3)).await;
        println!("task 1 wake up");
    });

    tokio::task::spawn(async move {
        println!("task 2 started..");
        tokio::time::sleep(Duration::from_secs(1)).await;
        println!("task 2 wake up");
    });

    tokio::time::sleep(Duration::from_secs(5)).await;
    println!("wake up");
}

task 1 started..
task 2 started..
task 2 wake up
task 1 wake up
wake up

use std::time::Duration;
use futures::{stream::FuturesUnordered, StreamExt};
use std::thread;

#[tokio::main(flavor="multi_thread", worker_threads = 1)]
async fn main() {
    // console_subscriber::init();

    let mut tasks = FuturesUnordered::new();

    let h1 = tokio::spawn(async move {
        thread::sleep(Duration::from_secs(10)).await;
        println!("0 wake up");
    });
    tasks.push(h1);
    println!("0 started...");

    for i in 1..100 {
        let h2 = tokio::spawn(async move {
            tokio::time::sleep(Duration::from_secs(1)).await;
            println!("{i} woke up!");
        });
        tasks.push(h2);
        println!("{i} ...");
    }
    while let Some(item) = tasks.next().await {
        let () = item.unwrap();
    }
    println!("Done");
}

【Rust】axumでパスパラメータを取得して使用する

Postではなく、Getでデータを渡したいときに、パスパラメータを使用する
route(“/withdrawal/{param}” でパスパラメータを取得できる。以前は、route(“/withdrawal/:param” だったので変わったみたい。

html

<button onclick="location.href='./withdrawal/eyJ2ZXJzaW9uIjoiMC4xLjAiLCJ0aW1lIjoiMjAyNS0wMi0xNVQwNzoxNzo0Mi4xMDU3Njk4NDNaIiwic2VuZGVyIjoiMDQxMGY4NzQyOWU4OTQ5OGU5MjhkMDBiNmE2MTg2ZmRjOWNjYmRlMmNhNTVkNTc0NmYwZTFiZjhmMWExZmJkYjc'">ボタン</button>

axum

    let app = Router::new()
        .route("/", get(handle_index))
        .route("/withdrawal/{param}", get(handle_withdrawal))

//

async fn handle_withdrawal(axum::extract::Path(param): axum::extract::Path<String>) {

    println!("{}", param);
}

なるほど〜

【Rust】WebAssemblyを使用する

$ cargo install wasm-pack
$ cargo new –lib hello-wasm
$ tree
.
└── hello-wasm
├── Cargo.toml
└── src
└── lib.rs

2 directories, 2 files

src/lib.rs

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    pub fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str){
    alert(&format!("Hello, {}!", name));
}

Cargo.toml

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen= "0.2"

build
$ wasm-pack build –target web

index.html

<body>
    <script type="module">
        import init, { greet } from "./pkg/hello_wasm.js";
        init().then(() => {
            greet("WebAssembly");
        });
    </script>
</body>

なるほど、WebAssemblyか、次々に新しい技術が出てきますね…

参考)
https://developer.mozilla.org/ja/docs/WebAssembly/Guides/Rust_to_Wasm

【Rust】ワークスペースによるパッケージ管理

$ mkdir add
$ cd add

Cargo.toml

[workspace]

members = [
    "adder",
]

$ cargo new –bin adder
$ tree
.
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── Cargo.toml

$ cargo new add-one –lib
$ tree
.
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
├── add-one
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── Cargo.toml

pub fn add_one(x: i32) -> i32 {
    x + 1
}

adder/Cargo.toml

[dependencies]
add-one = {path = "../add-one"}

adder/src/main.rs

extern crate add_one;

fn main() {
    let num = 10;
    println!("Hello, world!{} plus one is {}!", num, add_one::add_one(num));
}

$ cargo run
Compiling add-one v0.1.0 (/home/vagrant/dev/rust/add/add-one)
Compiling adder v0.1.0 (/home/vagrant/dev/rust/add/adder)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.15s
Running `target/debug/adder`
Hello, world!10 plus one is 11!

なるほど、ワークスペースを使ってパッケージ管理してるのか!

【Rust】非同期処理 Async, awaitを整理する

プリエンティブマルチタスク: OSにより実行を制御する
協調的マルチタスク: コンテキストの切り替え、スレッドの置き換えはできる
コールチン: 協調的マルチタスクを制御できる
Futureオブジェクト: 処理が終わったらコールバック、awaitは実行完了まで待つ

use std::{thread, time};
#[tokio::main]
async fn main(){

    let handle = tokio::spawn(async {
        thread::sleep(time::Duration::from_millis(1000));
        println!("1 sec elapsed");
    });
    
    let order = "beef burger".to_string();
    order_burger(order).await;
    play_game().await;
}

async fn order_burger(order: String) -> Result<String, Box<dyn std::error::Error>> {
    match order {
        ref val if *val == "beef burger".to_string() => thread::sleep(time::Duration::from_millis(200)),
        ref val if *val == "cake".to_string()  => thread::sleep(time::Duration::from_millis(300)),
        _ => println!("Please order!"),
    }
    println!("Order received {}", order);
    Ok(order)
}

async fn play_game() {
    println!("I am playing game");
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.60s
Running `target/debug/app`
Order received beef burger
I am playing game
1 sec elapsed

asyncの関数をawaitで実行した場合は、その次の関数は実行完了まで実行されない。
別のスレッドを立てた場合は、並列で処理がされる。

なるほど、async処理をawaitする意味が何となくわかった。

【Rust】WebSocketのClient側の送信

https://docs.rs/websockets/latest/websockets/struct.WebSocket.html
websockets=”0.3.0″

use websockets::WebSocket;
use websockets::Frame;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut ws = WebSocket::connect("wss://echo.websocket.org/").await?;
    ws.send_text("foo".to_string()).await?;
    ws.receive().await?;
    if let Frame::Text { payload: received_msg, .. } =  ws.receive().await? {
        println!("{}", received_msg);
    }
    ws.close(None).await?;
    Ok(())
}   

Compiling app v0.1.0 (/home/vagrant/dev/rust/app)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.00s
Running `target/debug/app`
foo

なるほどー