Rustでビット精度の整数型を使えるようにするライブラリを作った
はじめに
Rustのプリミティブ整数型のビット幅は他の多くの言語と同様に8の倍数です。
殆どの場合はこれで十分だと思いますが、7ビットなどの8の倍数でないビット幅の整数型が欲しい場合がまれにあると思います。
今回紹介するbit-intクレートは、そのような場合に利用できる任意のビット精度であることを保証した整数型を使えるようにするライブラリです。
作った理由
最近、C23に興味を持って調べていたときに、ビット精度の整数型の_BitInt(n)が追加されたことを知り、Rustでもビット精度の整数型を実装してみたいと思ったので作りました。
データ型
符号付き整数型はBitIntとして実装しており、符号無し整数型はBitUintとして実装しています。
BitIntは以下のように定義されています:
pub struct BitInt<T: Signed + PrimInt, const N: u32>(T);
Tにはnum-traitsクレートのSignedトレイトとPrimIntトレイトを実装している型(全てのプリミティブ符号付き整数型)を指定できます。
Nは符号ビットも含めた値のビット数です。
BitUintは以下のように定義されています:
pub struct BitUint<T: Unsigned + PrimInt, const N: u32>(T);
Tにはnum-traitsクレートのUnsignedトレイトとPrimIntトレイトを実装している型(全てのプリミティブ符号無し整数型)を指定できます。
Nは値のビット数です。
Nの範囲は1からT::BITSで、範囲外のビット数を指定した場合にはコンパイルエラーになります。
使い方
初期化にはnewメソッドかnew_uncheckedメソッドを使います。
前者は与えられた値がNビットに収まるかを検査し、収まる場合はSomeを返し、そうでない場合はNoneを返します。
後者は検査をしないで初期化をするunsafeメソッドで、与えられた値がNビットに収まらないときの動作は未定義です。
値をプリミティブ型として取得するにはgetメソッドを使います。
let n = BitInt::<i32, 7>::new(42);
assert_eq!(n.map(BitInt::get), Some(42));
let m = BitInt::<i32, 6>::new(42);
assert!(m.is_none());
プリミティブ整数型と同様に、最小値、最大値、ビット数を表す定数を定義しています。
assert_eq!(BitInt::<i32, 7>::MIN.get(), -64);
assert_eq!(BitInt::<i32, 7>::MAX.get(), 63);
assert_eq!(BitInt::<i32, 7>::BITS, 7);
演算は現時点では四則演算だけ実装しています。
今後、プリミティブ型にある他の演算も実装するつもりです。
let n = BitInt::<i32, 7>::new(42).unwrap();
assert_eq!(n.checked_add(21).map(BitInt::get), Some(63));
assert!(n.checked_add(22).is_none());
終わりに
Rustでビット精度の整数型を使えるようにするライブラリのbit-intクレートを紹介しました。
開発を始めたばかりで機能が少ないので、今後機能を強化できたら良いと思います。
Discussion