Zig 言語用ライブラリ basis-concept を書きました

Zig 言語用のライブラリ basis-concept を書きましたのでその紹介をします。
> github.com/eldesh/basis_concept

Zig は手続き的な型付き言語です。表現力としては、型上のコンパイル時計算によりアドホック多相を表現出来ます。

ただし型コンストラクタや部分特殊化が無いため、型の分類をシステマチックに行うのが面倒になっています。

このライブラリは型上の述語によって基本的な型の分類方法とそれらの上のジェネリックな関数を提供するユーティリティーライブラリです。

Concept

このライブラリでは型を分類するための述語をコンセプトと呼びます。主なコンセプトを紹介します。

Eq
等値比較を可能な型です。== で比較でき、かつポインタを含まない型は自動的にこのコンセプトを満たします。eqne という関数を持っている型の場合もこのコンセプトを満たします。
Ord
全順序が定義されている型を表します。プリミティブの数値型の他、 fn compare(*const @This(), *const @This()) std.math.Order という関数を持っている型もこのコンセプトを満たします。
Clone
値のディープコピーが可能な型を表します。プリミティブ型、ポインタを含まない複合型、あるいは fn clone(*const @This()) @This().CloneError!@This() を持つ型がこのコンセプトを満たします。値を複製する際アロケーションが必要になることが考えられるため、エラーを返すことが出来る戻り型になっています。

この他に rust と同様に PartialEqPartialOrd も定義してみましたが、それらの分類を行っても処理系が活かせない情報なため削除を検討しています。

使い方

例としてユーザ定義の struct 型を等値比較する方法を示します。

以下のような型 S を考えます。

const S = struct {
  val_int: u32,
  val_opt: ?u8,
  val_eit: error{MyError}![5]u8,
};

このようなポインタを含まない struct のインスタンスEq.eq で比較できます。

comptime assert(isEq(S));
const s1: S = ...;
const s2: S = ...;
if (Eq.eq(&s1, &s2)) {
    ...
}

標準ライブラリにある std.mem.eql でも同様に構造に基づいた比較が可能ですが、これはポインタフィールドをアドレスで比較します。
ポインタを含む構造体で Eq コンセプトを満たすためには eqne メソッドを持つ必要があります。

const T = struct {
  val: *u32,
  pub fn eq(self: *const @This(), other: *const @This()) bool {
      return self.val.* == other.val.*;
  }
  pub fn ne(self: *const @This(), other: *const @This()) bool {
      return self.val.* != other.val.*;
  }
};

const x: T = ...
assert(Eq.eq(&x, &x));

より詳しくは README.md をご覧下さい。

プロジェクトへの追加

basis-concept は外部ライブラリに依存していないためその場でビルドすることが出来ます。

私は開発に zigmod を使用しているので zigmod プロジェクトへの依存の追加例を示しておきます。

root_dependencies:
  - src: git git@github.com:eldesh/basis_concept-zig commit-v1.3
dependencies:
  - src: git git@github.com:eldesh/basis_concept-zig commit-v1.3