| Rust | Bit演算を用いて賢く構造体を定義する

# イントロダクション
こんにちは！最近Rustを学び始めたhihimamu(旧mamuDev)です！
今回は、Bit演算を用いて賢く構造体を定義する方法を備忘録として書き残したいと思います。それではどうぞ！
# 目次
1. [Rustとは]()
1. [Bit演算を用いた構造体定義]()
1. [終わりに]()
# Rustに関して
Rustとは、WebブラウザFirefoxを開発したMozilla社が携わり、2006年に開発がはじめられたオープンソースのプログラミング言語です。プログラミングコミュニティ「Stack Overflow」が行った調査「Stack Overflow Developer Survey 2022」において、Rustは7年連続で「開発者が最も愛する言語」として選出されている人気の言語です。
# Bit演算を用いた構造体定義
### ユースケース
現在私はRustの学習のためにパスワードジェネレーターを作っています。主に、構造体、列挙型、メソッド定義、外部トレイト定義、外部クレート利用などの知識習得を目的としています。
パスワードジェネレーターの基本戦略として文字プールを用意しそこからRNGを用いて指定回数文字を選びだす、というものがあると思います。その文字プールの種類として大文字、小文字、英数字、記号とさらにそれらを組み合わせた２４通りものパターンがあります。
これを列挙型として定義するのは骨が折れますし、何よりスマートさコンパクトさに欠けますよね。(だよね？)
### 対処法
ぶっちゃけます。**数値データ型フィールドと大文字、小文字、英数字、記号の４つの定数を持った構造体一つで十分なのです**。さて、どうやって２４通りのパターンを表すか、そうBit演算がここで登場します。
論理和(OR)です。以下のコードで実装します。
```rust
use std::opus::BitOr;

#[derive(Debug, PartialEq, Copy, Clone)]
struct Pool {
    value: u8
}

impl Pool {
    const UPPERCASE: Self = Self { value: 1 };
    const LOWERCASE: Self = Self { value: 2 };
    const NUMBER: Self = Self { value: 4 };
    const SYMBOL: Self = Self { value: 8 };
}

impl BitOr for Pool {
    type Output = Self;
    fn bitor(self, rhs: Self) -> Self::Output {
        Self {
            value: self.value | rhs.value,
        }
    }
}
```
論理和を用いることで例えば、文字プールを大小文字にしよう！となったとき
```rust
let pool: Pool = Pool::UPPERCASE | Pool::LOWERCASE;
```
というコードを書くとUPPERCASEが持つvalue: 1[01]とLOWERCASEが持つvalue: 2[10]をOR演算し、value: 3[11]となります。
同様に大小文字英数字としたかったら、
```rust
let pool: Pool = Pool::UPPERCASE | Pool::LOWERCASE | Pool::NUMBER;
```
このように表せます。
### なぜ論理和なのか、和ではだめなのか
はい、だめです。
Addトレイトを実装している前提でこのような場合を考えましょう。
```rust
let pool: Pool = Pool::UPPERCASE + Pool::UPPERCASE;
```
これはvalue:1 + value: 1が足されvalue: 2となります。おかしいですね、value: 2はLOWERCASEの値です。
そもそもUPPERCASE同士を足すのも変ですが、これではエラーにつながります。
論理和の場合、
```rust
let pool: Pool = Pool::UPPERCASE | Pool::UPPERCASE;
```
これはvalue: 1[01]とvalue: 1[01]の論理和でvalue: 1[01]となります。UPPERCASEとUPPERCASEを足してもUPPERCASEにしかならないということですね。これは良い！
### 具体的な文字プール(Stringまたは&str)はどうするのか？
ここでもう一つのBit演算、論理積(AND)が登場します。
以下のように実装します。
```rust
use std::ops::BitAnd;

impl BitAnd for Pool {
    type Output = Self;
    fn bitand(self, rhs: Self) -> Self::Output {
        Self {
            value: self.value & rhs.value
        }
    }
}
```
論理積を用いてif文で分岐させると、スマートに文字プールを定義できます。
```rust
impl Pool {
    fn to_string(pool: Pool) -> String {
        let mut res: String = String::new();
        if pool & Pool::UPPERCASE == Pool::UPPERCASE {
            res.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        }
        if pool & Pool::LOWERCASE == Pool::LOWERCASE {
            res.push_str("abcdefghijklmnopqrstuvwxyz");
        }
        if pool & Pool::NUMBER == Pool::NUMBER {
            res.push_str("0123456789");
        }
        if pool & Pool::SYMBOL == Pool::SYMBOL {
            res.push_str("!@#$%^&*()-_=+[{{]}}\\|;:'\"");
        }
        res
    }
}
```
なぜこれで適切な文字プールが返ってくるかというと、例えば
```rust
let pool: Pool = Pool::UPPERCASE | Pool::LOWERCASE;
```
とした時、pool(= value: 3[011])とPool::UPPERCASE(= value: 1[01])の論理積はUPPERCASE(= value: 1[01])となるためです。同様にpoolとLOWERCASEとの論理積もLOWERCASEと等しくなります。このそれぞれのif文を通過すると求めている文字プールが手に入るというわけです。
実に賢いロジックですね。
# 終わりに
今回解説したコードの全文です。
```rust
use std::ops::{BitOr, BitAnd};

#[derive(Debug, PartialEq, Copy, Clone)]
struct Pool {
    value: u8
}

impl Pool {
    const UPPERCASE: Self = Self { value: 1 };
    const LOWERCASE: Self = Self { value: 2 };
    const NUMBER: Self = Self { value: 4 };
    const SYMBOL: Self = Self { value: 8 };
}

impl BitOr for Pool {
    type Output = Self;
    fn bitor(self, rhs: Self) -> Self::Output {
        Self {
            value: self.value | rhs.value,
        }
    }
}

impl BitAnd for Pool {
    type Output = Self;
    fn bitand(self, rhs: Self) -> Self::Output {
        Self {
            value: self.value & rhs.value
        }
    }
}

impl Pool {
    fn to_string(pool: Pool) -> String {
        let mut res: String = String::new();
        if pool & Pool::UPPERCASE == Pool::UPPERCASE {
            res.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        }
        if pool & Pool::LOWERCASE == Pool::LOWERCASE {
            res.push_str("abcdefghijklmnopqrstuvwxyz");
        }
        if pool & Pool::NUMBER == Pool::NUMBER {
            res.push_str("0123456789");
        }
        if pool & Pool::SYMBOL == Pool::SYMBOL {
            res.push_str("!@#$%^&*()-_=+[{{]}}\\|;:'\"");
        }
        res
    }
}
```

又、Poolはvalue: u8を定義していますが、Pool(u8)のようにタプルを定義することでも同じ動作を望めます。
```rust
use std::ops::{BitOr, BitAnd};

#[derive(Debug, PartialEq, Copy, Clone)]
struct Pool(u8);

impl Pool {
    const UPPERCASE: Self = Self(1);
    const LOWERCASE: Self = Self(2);
    const NUMBER: Self = Self(4);
    const SYMBOL: Self = Self(8);
}

impl BitOr for Pool {
    type Output = Self;
    fn bitor(self, rhs: Self) -> Self::Output {
        Self(self.0 | rhs.0)
    }
}

impl BitAnd for Pool {
    type Output = Self;
    fn bitand(self, rhs: Self) -> Self::Output {
        Self(self.0 & rhs.0)
    }
}

impl Pool {
    fn to_string(pool: Pool) -> String {
        let mut res = String::new();
        if pool & Pool::UPPERCASE == Pool::UPPERCASE {
            res.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        }
        if pool & Pool::LOWERCASE == Pool::LOWERCASE {
            res.push_str("abcdefghijklmnopqrstuvwxyz");
        }
        if pool & Pool::NUMBER == Pool::NUMBER {
            res.push_str("0123456789");
        }
        if pool & Pool::SYMBOL == Pool::SYMBOL {
            res.push_str("!@#$%^&*()-_=+[{{]}}\\|;:'\"");
        }
        res
    }
}
```

この記事をお読みいただきありがとうございました！これからも備忘録などをアップロードしていきたいと思います。