ゼロコスト抽象化

型状態はゼロコスト抽象化の優れた例でもあります。特定の動作を、コンパイル時の実行もしくは解析に移動する機能です。 これらの型状態は、実際のデータを含んでおらず、代わりにマーカとして使われています。 型状態はデータを含んでいないため、実行時、メモリ内に実際のデータはありません。

use core::mem::size_of;

let _ = size_of::<Enabled>();    // == 0
let _ = size_of::<Input>();      // == 0
let _ = size_of::<PulledHigh>(); // == 0
let _ = size_of::<GpioConfig<Enabled, Input, PulledHigh>>(); // == 0

ゼロサイズの型

struct Enabled;

上記のように定義された構造体をゼロサイズの型、と呼びます。これは、実際のデータを含んでいません。 これらの型は、コンパイル時には「実際に」機能します。例えば、コピーも、ムーブも、参照を取ることもできます。 しかし、最適化はこれらを完全に取り除きます。

次のコードスニペットを見てください。

pub fn into_input_high_z(self) -> GpioConfig<Enabled, Input, HighZ> {
    self.periph.modify(|_r, w| w.input_mode().high_z());
    GpioConfig {
        periph: self.periph,
        enabled: Enabled,
        direction: Input,
        mode: HighZ,
    }
}

実行時、返り値のGpioConfigは、存在しません。この関数を呼び出すと、通常、1つのアセンブリ命令にまとめられます。 そのアセンブリ命令は、定数のレジスタ値を、レジスタの位置へ格納します。 これは、開発した型状態インタフェースが、ゼロコスト抽象化であることを意味します。 GpioConfigの状態を追跡するために、余分なCPU、RAM、コード領域を使用せず、直接レジスタアクセスするのと同じ機械語を表します。

ネスト

通常、これらの抽象化は、望み通りの深さでネストされます。使用される全てのコンポーネントが、ゼロサイズの型である限り、実行時には、構造体全体が存在しません。

複雑な構造体や深くネストした構造体については、全ての取り得る状態の組み合わせを定義することは、面倒です。 このような場合、全ての実装を生成するために、マクロが利用できます。