RustのCrate調査 (bitflags, byteorder, chrono, encoding_rs, num_cpus)

Rustのコードをコンパイルしていると、直接的には使っていないですが、依存関係のためにダウンロードされてくるcrateをよく見ます。

そういうcrateの中には便利なものもあるだろうと思い、いくつかのcrateの調査をしてみました。

今回は、bitflags、byteorder、chrono、encoding_rs、num_cpusの5つについて調べました。

コンパイラのバージョンは「rustc 1.33.0」です。

bitflags : 定数として使うビットフラグを簡単に構築

bitflagは、Linux環境のファイルパーミッションのような、ビットフラグを定義するのを助けるcrateです。

実際にサンプルコードとして、ファイルパーミッションのようなビットフラグを定義してみました。

crateのバージョンは、「bitflags = "1.0.4"」です。

use bitflags::bitflags;

bitflags! {
    struct FileFlags: u32 {
        const EXEC = 0b00000001;
        const WRITE = 0b00000010;
        const READ = 0b00000100;
        const RWX = Self::READ.bits | Self::WRITE.bits | Self::EXEC.bits;
    }
}

pub fn run() {
    println!("##### bitflags #####");
    let file_flags = FileFlags::READ | FileFlags::WRITE; // OR
    println!("OR: {:?}", file_flags);
    let file_flags = FileFlags::READ & FileFlags::WRITE; // AND
    println!("AND: {:?}", file_flags);
    let file_flags = FileFlags::RWX - FileFlags::WRITE; // Sub
    println!("Sub: {:?}", file_flags);
    let file_flags = FileFlags::RWX - FileFlags::WRITE - FileFlags::WRITE; // Sub2
    println!("Sub2: {:?}", file_flags);
}

出力は次のようになります。

##### bitflags #####
OR: WRITE | READ
AND: (empty)
Sub: EXEC | READ
Sub2: EXEC | READ

引き算の演算子は、きちんと内部でビット演算しているので、2回引いてもおかしなビットにならないようです。

byteorder : バイト列のエンディアンを指定

byteorderはデータを扱う際に、リトルエンディアンかビッグエンディアンかを指定することができます。

crateのバージョンは、「byteorder = "1.3.1"」です。

use byteorder::{ReadBytesExt, BigEndian, LittleEndian};

pub fn run() {
    println!("##### byteorder #####");
    let bytes: Vec<u8> = vec![0, 0, 255, 255];
    println!("Big Endian: {}", (&bytes[0..4]).read_u32::<BigEndian>().unwrap());
    println!("Little Endian: {}", (&bytes[0..4]).read_u32::<LittleEndian>().unwrap());
}

出力は次のようになります。

##### byteorder #####
Big Endian: 65535
Little Endian: 4294901760

ビッグエンディアンは、バイトの上位から読んで、65535=0x0000ffff。

トルエンディアンは、バイトの下位から読んで、16842752=0xffff0000。

今回はデータをu32で読み取る(read_u32)ことをしていますが、他の型(u16、u64など)のための読み込み関数も各種用意されており、それらはbyteorder::ReadBytesExtで定義されています。

また、書き込み用のbyteorder::WriteBytesExtも定義されています。

ネットで検索していたところ、PNG画像のデータをBigEndianで読み取る場面で使用している例がありました。データ構造によっては、エンディアンが指定されているものもあるのかもしれませんね。

chrono : 時間・日付を操作を便利に

chronoは、UTCと現地時間の変換や、文字列から時間データへの変換などの操作が簡単にできます。

crateのバージョンは、「chrono = "0.4.6"」です。

use chrono::prelude::*;

pub fn run() {
    println!("##### chrono #####");
    let utc: DateTime<Utc> = Utc::now();
    println!("UTC: {}", utc);
    println!("Convert from UTC to Local Timezone: {}", utc.with_timezone(&Local));
    println!("Convert from UTC to Unix Timestamp: {}", utc.timestamp());
    println!("");

    let local: DateTime<Local> = Local::now();
    println!("Local: {}", local);
    println!("Convert from Local Timezone to UTC: {}", local.with_timezone(&Utc));
    println!("Convert from Local to Unix Timestamp: {}", local.timestamp());
    println!("");

    let dt = Utc.timestamp(1_500_000_000, 0);
    println!("Convert from Unix Timestamp: {}", dt);
    println!("RFC3339: {}", dt.to_rfc3339());
    println!("");

    if let Ok(dt) = "2014-11-28T12:00:09Z".parse::<DateTime<Utc>>() {
        println!("Convert from String: {}", dt);
    }
}

出力は次のようになります。

##### chrono #####
UTC: 2019-03-30 12:53:56.797502255 UTC
Convert from UTC to Local Timezone: 2019-03-30 21:53:56.797502255 +09:00
Convert from UTC to Unix Timestamp: 1553950436

Local: 2019-03-30 21:53:56.797587758 +09:00
Convert from Local Timezone to UTC: 2019-03-30 12:53:56.797587758 UTC
Convert from Local to Unix Timestamp: 1553950436

Convert from Unix Timestamp: 2017-07-14 02:40:00 UTC
RFC3339: 2017-07-14T02:40:00+00:00

Convert from String: 2014-11-28 12:00:09 UTC

encoding_rs : Webブラウザでも使われているエンコーディング機能を提供

encoding_rsは、エンコーディングのためのcrateです。

GitHubのREADMEによると、レンダリングエンジン「Gecko」でも使われているようです。

crateのバージョンは、「encoding_rs = "0.8.17"」です。

use encoding_rs::*;

pub fn run() {
    println!("##### encoding_rs #####");
    let bytes = b"\x83n\x83\x8D\x81[\x81E\x83\x8F\x81[\x83\x8B\x83h"; // SJIS

    let (cow, encoding_used, had_errors) = SHIFT_JIS.decode(bytes);
    println!("bytes: {:?}", bytes);
    println!("cow: {}", cow);
    println!("encoding: {:?}", encoding_used);
    println!("error: {}", had_errors);
}

出力は次のようになります。

##### encoding_rs #####
bytes: [131, 110, 131, 141, 129, 91, 129, 69, 131, 143, 129, 91, 131, 139, 131, 104]
cow: ハロー・ワールド
encoding: Encoding { Shift_JIS }
error: false

Shift JISの文字列が変換されてプリントできるようになりました。

Webから取得した文字列には、様々なエンコーディングのものもあるので、文字列を変換したいときに重宝しそうです。

num_cpus : CPUの数を取得

num_cpusは、その名の通りCPUの数を取得できるcrateです。

use num_cpus;

pub fn run() {
    println!("##### num_cpus #####");
    println!("num of cpus: {}", num_cpus::get());
    println!("num of physical core: {}", num_cpus::get_physical());
}

出力は次のようになります。

##### num_cpus #####
num of cpus: 4
num of physical core: 2

実際に計算できるCPUのスレッド数と、物理的なCPUのコア数が、取得できます。

Rustでコマンドラインツールを作っている人も多いと思いますが、重い処理の高速化を図るためにマルチスレッドにしている場合は、この値を参考にしてスレッドの数を調節できそうですね。

まとめ

今回は、bitflags、byteorder、chrono、encoding_rs、num_cpusの5つについて調べました。

また、他のcrateについても調べていこうと思います。

情報処理学会 第81回 全国大会に参加しました

3月14日から3日間、福岡で開催されていた「情報処理学会 第81回 全国大会」に参加してきました。

f:id:toyamaguchi:20190326232126j:plain

情報処理学会の公式ページによれば、全国大会は一年に一度開催される、学会最大のイベントとのことです。 私もこの全国大会に参加したことで、学会がカバーする様々な分野の研究発表や、有名な先生をお招きしての特別講演、様々なテーマの企画など、興味深いコンテンツをたくさん見ることができました。

最近、私は、情報処理系の研究分野から知識を得ようと、論文を読むことを始めたのですが、全国大会でも多くの論文を読むことができ、様々な研究に触れることができました。

全国大会で発表される論文は、一つずつの長さが2ページと、やや短いです。 そのため、余分な文章は削ぎ落とされ、必要なところだけが残っているような論文に仕上がっています。 読む側からすると、日本語であることに加えてページ数も短いため、次々と論文を読み進むことができました。

全国大会で発表される論文は、研究を始めたばかりの学生のものから、一般企業からのものもあります。 そのため、多くの論文を読んでいると、だんだんと論文の良し悪しがわかってきてとても良いです。 学会への論文投稿を目指し始めた学生の方たちも、まずは全国大会の論文をたくさん読んでみて、良い構成の論文の書き方を真似してみたらどうでしょうか。

また、様々な研究の発表の場で交わされる質疑応答の中で、「なるほど」と思ったこともありました。 現在行っている研究の全体像はどのくらいの規模で、そのうちのどれくらいの割合が今回の実験でカバーできたのか、という内容を論文に加えるとさらに良くなる、という内容のコメントでした。

全国大会のセッションの一つにあった「論文必勝法」のパネル討論の中でも話されていましたが、研究の目標が100%達成できていなくても、現在までにできたことを論文の体裁で書くことができれば、採録は十分にありえるとのことです。

研究の達成率を100%にすることは難しかったりしますが、ある程度の区切りで論文を投稿してみるのもいいですね。

Shinjuku.rs #3にてLightning Talkをしました。

先日、3月12日に行われた勉強会「Shinjuku.rs #3」にて、Lightning Talkをしました。

発表は「Visualizatoin System in Rust - Rustで作る可視化サーバの紹介」というタイトルで行いました。

www.slideshare.net

CTFなどで活躍するOpenGL製の可視化サーバをRustで組んでみたとき、どのような利点があるのか、はたまたどんな問題に遭遇したのか発表しました。

OpenGLを使うシステムで、Rustを使う良い点は次のようなところがありました。

  1. 処理速度が速い
  2. ガベッジコレクションがない
  3. クロスプラットフォームで動作するアプリが作りやすい
  4. 新規ライブラリの導入が楽

一方で、いくつものスレッドが実行される並列処理のプログラムを組もうと思ったときに、スレッドをまたいだデータの扱いが難しく、初心者には大きな障壁になりえることを発表しました。

私自身、Rustの習熟度がまだまだなので、これからも勉強して、並列処理のうまい攻略法を探っていきたい所存です。

ただ、わからないなりに発表して良かったことは、参加者のκeenさんやqnighyさんからアドバイスをもらうことができたことです。

Rustコミュニティは、Rust自体が難しいせいか(笑)、みなさん優しいです。

発表 = 自己紹介、くらいの気持ちで発表すると、他の方たちとも早く打ち解けられるので、他の方たちもどんどん発表できたらいいなぁ、と思っています。