Rust

在 VS Code 中給 Rust 專案使用的 launch.json 範例

(更新:rust-analyzer 也有自動產生 launch.json 的功能。可以停留在 main.rs 上,按 F1,選取 "rust-analyzer: Generate launch configuration" 即可。)

留個筆記,不然每次都要靠 google....

{
    // 使用 IntelliSense 以得知可用的屬性。
    // 暫留以檢視現有屬性的描述。
    // 如需詳細資訊,請瀏覽: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type":"lldb",
            "request": "launch",
            "name": "Debug",
            "program": "${workspaceFolder}/target/debug/${workspaceFolderBasename}",
            "args": [],
            "cwd": "${workspaceRoot}",
            "sourceLanguages": [
                "rust"
            ]
        }
    ]
}

然後記得要按 VS Code 自已的 debug/run 按鈕去執行,不要按 main() 上方的 "Run/Debug" inlay。後者不會吃 launch.json 中的 args

參考來源:Setting up a generic launch.json for Rust in VSCode

[Rust] Unit-Like Struct 在 Embedded Rust 中的應用

在處理嵌入式系統時常會需要控制 GPIO。所謂的 GPIO(General-Purpose I/O),就是 IC 的某些 pin 腳,可以透過軔體設定為「input(偵測外部的訊號是高電位還是低電位)」或是「output(對外輸出高電位或低電位)」狀態。

理論上來說,當 GPIO 設定為 input 狀態時,叫它「輸出高電位」是沒有意義的。反之,設定為 output 時,去讀取 pin 的電位狀態可能也是沒意義的。因此在設計存取 GPIO 的 API 時,最好能有適當的防呆機制。

Read More

[Rust] 如何產生靜態連結的 Win32/64 執行檔?

在預設情況下,Windows 版本的 rustc 編譯出來的 Win32/Win64 執行檔,會需要一些 Visual C++ 的 DLL 才能執行。對於軟體開發人員來說,在建構開發環境的過程中,這些 DLL 都會被安裝到系統之中,因此不太會遇到編譯出來的執行檔無法執行的問題;但若是我們要將執行檔給別人、在沒有安裝開發環境的電腦上執行,往往就會遇到問題。

我們可以利用 Visual Studio 所內建的工具程式 dumpbin(加上參數 /dependents)來檢查執行檔的 DLL 依存關係:

上面列出來的 DLL 中,KERNEL32.DLLbcrypt.dll 是 Windows 內建的 DLL,其他的都是 Visual C++ 提供的 DLL,不見得每一台 PC 上都會有這些 DLL。

如果希望 rustc 採用靜態連結的方式、移除對 VC++ DLL 的依存性,可以在 Rust 專案中的 .cargo\config 檔案中,加上這兩行:

[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

然後重新編譯程式。這樣就可以了:

  • 資料來源:https://stackoverflow.com/questions/31770604/how-to-generate-statically-linked-executables

用 Rust 寫簡單的互動式命令列程式

最近在研究 1904 年日期系統,想說寫一個簡單的 Rust 程式來測試一下想法。主要的轉換函式寫完後,希望把程式寫成簡單的互動式程式,方便測試。

參考網路上的文章,結果如下:

// 先不用管 y1904 的細節,在這個範例中不重要。
mod y1904;

// 使用 std::io::Write 是為了 flush()
use std::io::{stdin, stdout, Write};
use y1904::*;

fn main() {
    loop {
        // 記得轉成 lowercase,比較好處理
        match prompt_for_input("> ").to_ascii_lowercase().as_str() {
            "exit" => break,
            s @ _ => match s.parse::<u64>() {
                Ok(num) => println!("{:?}", num_to_date(num)),
                _ => continue,
            },
        }
    }
}

fn prompt_for_input(prompt: &str) -> String {
    print!("{}", prompt);

    // 如果沒有呼叫 flush() 的話,在使用者輸入之前,上一行可能不會印出來
    stdout().flush().unwrap();

    let mut result = String::new();
    stdin().read_line(&mut result).unwrap();

    // 使用 trim() 去掉換行符號。
    // trim() 回傳的是 &str,因此要再轉成 String 回傳
    result.trim().to_string()
}

至於 y1904 的內容.... 之後再說好了。 XDD

Rustlings 習題探討:errors6.rs

主要是要練習如何撰寫及應用 error conversion。

整個程式是要實作一個新的型別 PositiveNonzeroInteger,意即「正整數」;0 或負整數都不是合法的。這個正整數要從字串 parsing 而來。如果 parsing 時就出問題,要把 parse() 的 error 轉換成 ParsePosNonezeroError::ParseInt();而如果 parsing 沒問題,但數值本身是 0 或負整數的話,就要回傳 ParsePosNonezeroError::Creation()(依據數值是 0 或負整數,會代不同的 error code)。

Conversion 的部份很單純:

impl ParsePosNonzeroError {
    fn from_creation(err: CreationError) -> ParsePosNonzeroError {
        ParsePosNonzeroError::Creation(err)
    }

    fn from_parsing(err: ParseIntError) -> ParsePosNonzeroError {
        ParsePosNonzeroError::ParseInt(err)
    }
}

比較有趣的是應用的部份。

Read More

[Exercism][Rust] Diffie Hellman

題目網址(需登入 Exercism)

這個題目在 Rust 語言方面,沒有什麼太困難的地方。所以重點都是在 modular arithmetic 的運算上。

use rand::Rng;

pub fn private_key(p: u64) -> u64 {
    let mut rng = rand::thread_rng();
    rng.gen_range(2..p)
}

pub fn public_key(p: u64, g: u64, a: u64) -> u64 {
    modular_exp(g, a, p)
}

pub fn secret(p: u64, b_pub: u64, a: u64) -> u64 {
    modular_exp(b_pub, a, p)
}
Read More