読者です 読者をやめる 読者になる 読者になる

テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(rust report) 単位つき数値を読む関数を実装した

Hi Rust Guys,

Rustのcoreutils rewriteの一つの問題は重複だ. 各開発者が各自自由に実装を行っているため, 共通的な部品がほとんど抜き出されていない.

コマンドで良くある仕様として, 数値について1kとか1kBとかいう記法を許すというものがある. 私の知る限りでは, trancate, duですでに重複しており, ddなどでも必要な関数だと思う. splitでも必要だ. たぶん他にも必要なコマンドがありそうだ.

そこで私はこれらの共通化を図るため, 以下の関数を書いてみた. 正規表現でやるのも良いと思うが, 再帰で書いた方がかっこいいと思う. パターンマッチは良い・・・.

これを使ったdedupを提案してみようと思う. まずはsplitの拡張として投げて, 他のにも反映させていくのが良いだろう. コードの改善案お待ちしております. (提案してみた: https://github.com/uutils/coreutils/issues/340 )

use std::ascii::StrAsciiExt;

type P = (Option<int>, Option<String>);

fn fun(s: String) -> P
{
    do_fun(s, true)
}

fn do_fun(s: String, b: bool) -> P
{
    let sl = s.as_slice();
    let size = sl.char_len();
    let last = sl.char_at(size - 1);
    if last.is_alphabetic() {
        match last.to_ascii().to_char() {
            c @ 'B' | c @ 'b' if b => match do_fun(sl.slice(0, size - 1).to_str(), false) {
                    (Some(n), Some(s)) => (Some(n), Some(s + c.to_str())),
                    (_, Some(s)) => (None, Some(s)),
                    _ => (None, None)
            },
            c @ 'k' | c @ 'K' | c @ 'm' | c @ 'M' => {
                (from_str(sl.slice(0, size - 1)), Some(c.to_str()))
            },
            _ => (None, None)
        }
    } else {
        (from_str(sl), Some("".to_str()))
    }
}

// Mask for capitalize(10)/uncapitalize(01)
// E.g.
// If k is permitted but K is not permitted
// the unitmask is 1 (01)
// If both K and k are permitted
// the unitmask is 3 (11)
// If B is permitted but b is not permitted
// the bytemask is 2 (20)
fn sanitize_unit(p: P, unitmask: uint, bytemask: uint) -> P
{
    match p {
        (a, Some(u)) => {
            let n = u.as_slice().char_len();
            // TODO
            (a, None)
        },
        a => a
    }
}

fn to_num(p: P) -> int
{
    match p {
        (Some(n), Some(u)) => {
            n * match u.as_slice().to_ascii_upper().as_slice() {
                "" => 1,
                "KB" => 1000,
                "MB" => 1000 * 1000,
                "K" => 1024,
                "M" => 1024 * 1024,
                _ => 0 // tmp. should fail
            }
        },
        _ => 0 // tmp. should fail
    }
}