Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

Ubuntu22LTSでRust言語をやる その3:外部パッケージいれる

Pythonにおけるpip、Rubyにおけるgemみたいなのが、Rustにもあります。
今回はactix-webというパッケージを使ってWEB鯖をつくってみます。

実際のところ

とりあえずシンプルに

パッケージ導入

tomlファイルというのがありましたが、こいつを弄ると入る様子

[package]
name = "grrs"  # cargo newで指定した名前
version = "0.1.0" # 自分で定義するバージョン情報
edition = "2021" # Rustのバージョン。特に強い理由がない場合、2024年時点では2021が推奨

[dependencies]
actix-web = "4.4"

** スクリプト

// Actix Web - 高性能な非同期Webフレームワーク
use actix_web::{web, App, HttpResponse, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().route("/", web::get().to(|| async {
            HttpResponse::Ok().body("Hello world!")
        }))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
実行
$ cargo run

で初回実行すると、必要なパッケージを導入してくれます。
platformIOみたいにパッケージを入れるというより、ビルドすると時に必要なパッケージを入れる様子。

ちょっとした機能を追加し複数パッケージでやる

toml
[dependencies]
actix-web = "4.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
スクリプト
use actix_web::{get, web, App, HttpResponse, HttpServer};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct TempQuery {
    value: f64,
    unit: String,  // "C" for Celsius, "F" for Fahrenheit
}

#[derive(Serialize)]
struct TempResult {
    input_value: f64,
    input_unit: String,
    output_value: f64,
    output_unit: String,
    formatted_result: String,
}

fn celsius_to_fahrenheit(celsius: f64) -> f64 {
    (celsius * 9.0 / 5.0) + 32.0
}

fn fahrenheit_to_celsius(fahrenheit: f64) -> f64 {
    (fahrenheit - 32.0) * 5.0 / 9.0
}

#[get("/")]
async fn hello() -> HttpResponse {
    // HTMLフォームを返す
    let html = r#"
        <!DOCTYPE html>
        <html>
        <head>
            <title>Temperature Converter</title>
        </head>
        <body>
            <h1>Temperature Converter</h1>
            <form action="/convert" method="get">
                <input type="number" step="0.1" name="value" required>
                <select name="unit">
                    <option value="C">Celsius</option>
                    <option value="F">Fahrenheit</option>
                </select>
                <input type="submit" value="Convert">
            </form>
        </body>
        </html>
    "#;
    
    HttpResponse::Ok()
        .content_type("text/html")
        .body(html)
}

#[get("/convert")]
async fn convert(query: web::Query<TempQuery>) -> HttpResponse {
    let result = match query.unit.as_str() {
        "C" => {
            let fahrenheit = celsius_to_fahrenheit(query.value);
            TempResult {
                input_value: query.value,
                input_unit: "C".to_string(),
                output_value: fahrenheit,
                output_unit: "F".to_string(),
                formatted_result: format!("{:.1} °C = {:.1} °F", query.value, fahrenheit),
            }
        },
        "F" => {
            let celsius = fahrenheit_to_celsius(query.value);
            TempResult {
                input_value: query.value,
                input_unit: "F".to_string(),
                output_value: celsius,
                output_unit: "C".to_string(),
                formatted_result: format!("{:.1} °F = {:.1} °C", query.value, celsius),
            }
        },
        _ => return HttpResponse::BadRequest().json(serde_json::json!({
            "error": "Invalid unit specified"
        })),
    };

    HttpResponse::Ok()
        .content_type("application/json")
        .json(result)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(hello)
            .service(convert)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
実行


ためしに120で摂氏から華氏変換してみると、こんな感じでJSONがでてきます。

{
  "input_value": 120,
  "input_unit": "C",
  "output_value": 248,
  "output_unit": "F",
  "formatted_result": "120.0 °C = 248.0 °F"
}