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についても調べていこうと思います。