Rustの便利クレート

RustにはCargoという優れたパッケージマネージャーがあるので細かい多数の依存パッケージが問題になることはあまりありません。というより同一のアプリケーションでもパッケージを細かく分割することが推奨されています。ちょっとしたボイラープレートを取り除くような小さなライブラリも大量にあります。これらは積極的に使うべきです。

問題があるとすれば悪意のあるようなパッケージの存在ですが、これらに対処する[cargo-audit](https://crates.io/crates/cargo-audit)や[cargo-crev](https://crates.io/crates/cargo-crev)というツールもあります。

- [Rustの依存関係の信頼性を検証する (crev) - Qiita](https://qiita.com/qnighy/items/34bed9dbd826dc76d3ba)
- [cargo crev でコードレビューをしてみたらバグを見付けた話など - 何とは言わない天然水飲みたさ](https://blog.cardina1.red/2019/08/27/code-review-using-cargo-crev/)

本記事では

- 誰かがTwitterやブログで紹介するか誰かが使っているのを見る、あるいは何かのtrendingに載っているのを見るなどしない限り出会わない
- 日本語の情報があまり無い
- 用途がニッチすぎない
- （[syn](https://crates.io/crates/syn)とかはしょうがないとして）あまり[bloat](https://raphlinus.github.io/rust/2019/08/21/rust-bloat.html)を引き起こさない
- deprecatedとかWIPとか書かれたやつは含まない
- ~~総DL数が100k以上~~ なるべく有名なもの

のような便利なクレートを**60個**紹介したいと思います。もちろんこのようなクレートは他にも沢山あります。暇があれば[crates.io](https://crates.io)を眺めてみるのもいいでしょう。

執筆当時のRustのバージョンは~~1.40.0~~ 1.44.1です。

## 対象読者

- Rustに触れたことが無い

    「Rustではこういうことができる」というのを感じてもらえれば。

- チュートリアル and/or 書籍を読んだばかり

    頭の片隅にでも置いておくと後で少しだけ楽になるかもしれません。

- Rustに慣れた人

    知らないクレートがあるかもしれません。

## Changelog

<details><summary>Changelog</summary><div>

- 2021-04-28
    - [itertools](#itertools)のコード例を修正
- 2020-07-11
    - [itertools](#itertools), [fallible-iterator](#fallible-iterator), [walkdir](#walkdir), [anyhow](#anyhow), [num-derive](#num-derive), [ref-cast](#ref-cast), [ascii](#ascii), [unicase](#unicase), [ordered-float](#ordered-float), [im](#im), [indexmap](#indexmap), [generic-array](#generic-array), [crossbeam](#crossbeam), [difference](#difference), [assert\_cmd](#assert_cmd)の説明と例を更新
    - defmac, matches, tempdirの3つを削除
    - [ignore](#ignore), [duct](#duct), [duct\_sh](#duct_sh), [paste](#paste), [easy-ext](#easy-ext), [ghost](#ghost), [dunce](#dunce), [tempfile](#tempfile), [test-case](#test-case), [rusty-fork](#rusty-fork), [trybuild](#trybuild), [insta](#insta), [indoc](#indoc)の13個を追加
- 2019-12-30
    - `std::matches!`が[安定化された](https://github.com/rust-lang/rust/pull/67659)ので[matches](#matches)の説明を変更
- 2019-12-28
    - [itertools](#itertools), [anyhow](#anyhow), [if\_chain](#if_chain), [maplit](#maplit), [derivative](#derivative), [derive\_more](#derive_more), [strum](#strum), [derive-new](#derive-new), [getset](#getset), [ref-cast](#ref-cast)の説明と例を変更
- 2019-12-27
    - 冒頭の文面を変更
    - [anyhow](#anyhow), [thiserror](#thiserror)の説明と例を変更
    - ["対象読者"](#対象読者)を追加
    - せっかくなので[ref-cast](#ref-cast), [ordered-float](#ordered-float), [im](#im), [crossbeam](#crossbeam)を追加してちょうど50個に
- 2019-12-26
    - リンクを修正
    - typoを修正（編集リクエスト）
    - 冒頭の文面を変更
    - [defmac](#defmac), [structopt](#structopt), [getset](#getset), [ascii](#ascii), [stable\_deref\_trait](#stable_deref_trait), [owning\_ref](#owning_ref)の説明と例を変更
</div></details>

## ボイラープレート削減

### itertools

[![crates.io](https://img.shields.io/crates/v/itertools)](https://crates.io/crates/itertools) [![docs.rs](https://docs.rs/itertools/badge.svg)](https://docs.rs/itertools) [![license](https://img.shields.io/crates/l/itertools)](https://crates.io/crates/itertools) [![downloads](https://img.shields.io/crates/d/itertools)](https://crates.io/crates/itertools)

<code>[Iterator](https://doc.rust-lang.org/std/iter/trait.Iterator.html)</code>を拡張した<code>[Itertools](https://docs.rs/itertools/0.8/itertools/trait.Itertools.html)</code>とイテレータを生成するいくつかの関数とマクロを提供します。

Pythonの[more-itertools](https://pypi.org/project/more-itertools)のようなものです。 ただし単純に対応するものではなく、互いに存在しないものや対応していても名前が違う場合があります。

良く使われているのは<code>[join](https://docs.rs/itertools/0.8/itertools/trait.Itertools.html#method.join)</code>と<code>[format](https://docs.rs/itertools/0.8/itertools/trait.Itertools.html#method.format)</code>ですがその他のメソッドも大変便利です。一度<code>[Itertools](https://docs.rs/itertools/0.8/itertools/trait.Itertools.html)</code>のメソッドを眺めるのも良いでしょう。

例を挙げると、

- <code>[Itertools::all\_equal](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.all_equal)</code>

    ```diff
    -if xs.iter().all(|x| x % 2 == 0) || xs.iter().all(|x| x % 2 == 1) {
    +if xs.iter().map(|x| x % 2).all_equal() {
         todo!();
     }
    ```

- <code>[Itertools::tuple\_combinations](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.tuple_combinations)</code>

    ```diff
    -for i in 0..xs.len() {
    -    for j in i + 1..xs.len() {
    -        todo!();
    -    }
    +for (i, j) in (0..xs.len()).tuple_combinations() {
    +    todo!();
     }
    ```

    ```diff
     let sum = (0..xs.len())
    -    .flat_map(|i| (i + 1..xs.len()).map(move |j| (i, j)))
    +    .tuple_combinations()
         .map(|(i, j)| f(&xs[i..=j]))
         .sum::<i32>();
    ```

- <code>[iproduct!](https://docs.rs/itertools/0.9.0/itertools/macro.iproduct.html)</code>

    ```diff
    -for i in 0..xs.len() {
    -    for j in 0..ys.len() {
    -        todo!();
    -    }
    +for (i, j) in iproduct!(0..xs.len(), 0..ys.len()) {
    +    todo!();
     }
    ```

    ```diff
    -let sum = (0..xs.len())
    -    .flat_map(|i| (0..ys.len()).map(move |j| (i, j)))
    +let sum = iproduct!(0..xs.len(), 0..ys.len())
         .map(|(i, j)| f(i, j))
         .sum::<i32>();
    ```

- <code>Itertools::\{[chunks](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.chunks), [join](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.join), [tuple\_windows](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.tuple_windows), ..\}</code>

    ```diff
     let max = xs
         .into_iter()
         .map(f)
    -    .collect::<Vec<_>>()
    -    .windows(2)
    -    .map(|w| g(w[0], w[1]))
    +    .tuple_windows()
    +    .map(|(a, b)| g(a, b))
         .max()
         .unwrap();
    ```

    ```diff
     let s = [1u32, 2, 3, 4, 5]
         .iter()
         .filter(|&x| x % 2 == 0)
    -    .map(|x| (10 * x).to_string())
    -    .collect::<Vec<_>>()
    +    .map(|x| 10 * x)
         .join(" "); // `<[_]>::join` → `Itertools::join`
    ```

そのほか

- <code>[izip!](https://docs.rs/itertools/0.9.0/itertools/macro.izip.html)</code> (3個以上を<code>[zip](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.zip)</code>)
- <code>[iterate](https://docs.rs/itertools/0.9.0/itertools/fn.iterate.html)</code> (<code>[successors](https://doc.rust-lang.org/stable/std/iter/fn.successors.html)</code>の`Some`固定版)
- <code>[assert\_equal](https://docs.rs/itertools/0.9/itertools/fn.assert_equal.html)</code> (イテレータを`assert_eq!`)
- <code>[Itertools::sorted](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.sorted)</code> (`.collect::<Vec<_>>()`してソート)
- <code>[Itertools::merge](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.merge)</code> (ソート済みの2つをマージ)
- <code>[Itertools::permutations](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.permutations)</code> (順列)
- <code>[Itertools::combinations](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.combinations)</code> (組み合わせ)
- <code>[Itertools::zip\_longest](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.zip_longest)</code> (要素を切り捨てない<code>[zip](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.zip)</code>)
- <code>[Itertools::intersperse](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.intersperse)</code> (ある要素を挟んでいく)
- <code>Itertools::\{[interleave](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.interleave), [interleave\_shortest](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.interleave_shortest)\}</code> (交互)
- <code>[Itertools::coalesce](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.coalesce)</code> (柔軟に部分的にfold)
- <code>[Itertools::set\_from](https://docs.rs/itertools/0.9.0/itertools/trait.Itertools.html#method.set_from)</code> (`Item = &mut T`のに対し、`&mut`の参照先を`Item = T`ので埋める)

等の様々なユーティリティを提供します。 是非一度網羅的に調べてみるのはどうでしょうか。メソッドチェーン一発で解決できる問題が増えます。

極めて軽量かつ使いどころも多いので[structopt](#structopt)や[anyhow](#anyhow)等と共に`cargo new`直後に入れておくのもいいかもしれません。

See also: [itertoolsの紹介 | κeenのHappy Hacκing Blog](https://keens.github.io/blog/2019/12/06/itertoolsnoshoukai)（[その1](https://qiita.com/advent-calendar/2019/rust)の6日目）

### itertools-num

[![crates.io](https://img.shields.io/crates/v/itertools-num)](https://crates.io/crates/itertools-num) [![docs.rs](https://docs.rs/itertools-num/badge.svg)](https://docs.rs/itertools-num) [![license](https://img.shields.io/crates/l/itertools-num)](https://crates.io/crates/itertools-num) [![downloads](https://img.shields.io/crates/d/itertools-num)](https://crates.io/crates/itertools-num)

itertoolsと同じく`Iterator`を拡張しますが提供するのは<code>[cumsum](https://docs.rs/itertools-num/0.1/itertools_num/trait.ItertoolsNum.html#method.cumsum)</code>と<code>[linspace](https://docs.rs/itertools-num/0.1.3/itertools_num/fn.linspace.html)</code>、これだけです。

[@bluss](https://github.com/bluss)氏本人によるクレートですがitertoolsから分離されている理由はよくわかりません。[num-traits](https://crates.io/crates/num-traits)への依存を嫌ったのでしょうか..?

```diff
+use itertools_num::ItertoolsNum as _;
+
 static XS: &[u32] = &[1, 2, 3, 4, 5];
-let cumsum = XS
-    .iter()
-    .scan(0, |sum, x| {
-        *sum += x;
-        Some(*sum)
-    })
-    .collect::<Vec<_>>();
+let cumsum = XS.iter().cumsum().collect::<Vec<u32>>();
 assert_eq!(cumsum, &[1, 3, 6, 10, 15]);

 const START: f64 = 2.0;
 const STOP: f64 = 3.0;
 const NUM: usize = 5;
-let linspace = (0..NUM)
-    .map(|i| START + (STOP - START) * (i as f64) / ((NUM - 1) as f64))
-    .collect::<Vec<_>>();
+let linspace = itertools_num::linspace(START, STOP, NUM).collect::<Vec<_>>();
 assert_eq!(linspace, &[2.0, 2.25, 2.5, 2.75, 3.0]);
```

### fallible-iterator

[![crates.io](https://img.shields.io/crates/v/fallible-iterator)](https://crates.io/crates/fallible-iterator) [![docs.rs](https://docs.rs/fallible-iterator/badge.svg)](https://docs.rs/fallible-iterator) [![license](https://img.shields.io/crates/l/fallible-iterator)](https://crates.io/crates/fallible-iterator) [![downloads](https://img.shields.io/crates/d/fallible-iterator)](https://crates.io/crates/fallible-iterator)

`Iterator<Item = Result<_, _>>`を[変換](https://docs.rs/fallible-iterator/0.2/fallible_iterator/fn.convert.html)して扱いやすくします。

```diff
+use fallible_iterator::FallibleIterator as _;
+
 use std::io::{BufRead as _, Cursor};

 let stdin = Cursor::new("1\n2\n3\n101\n");
 ​
-let xs = stdin
-    .lines()
-    .map(|line| {
-        let x = line?.parse::<u32>()?;
-        Ok(if x <= 100 { Some(x) } else { None })
-    })
-    .flat_map(Result::transpose)
-    .collect::<anyhow::Result<Vec<_>>>()?;
+let xs = fallible_iterator::convert(stdin.lines())
+    .map_err(anyhow::Error::from)
+    .map(|line| line.parse::<u32>().map_err(Into::into))
+    .filter(|&x| Ok(x <= 100))
+    .collect::<Vec<_>>()?;

 assert_eq!(xs, &[1, 2, 3]);
```

### walkdir

[![crates.io](https://img.shields.io/crates/v/walkdir)](https://crates.io/crates/walkdir) [![docs.rs](https://docs.rs/walkdir/badge.svg)](https://docs.rs/walkdir) [![license](https://img.shields.io/crates/l/walkdir)](https://crates.io/crates/walkdir) [![downloads](https://img.shields.io/crates/d/walkdir)](https://crates.io/crates/walkdir)

ディレクトリを捜索するときに使えるユーティリティです。

```rust
use walkdir::WalkDir;

for entry in WalkDir::new("./src").follow_links(true).max_depth(10) {
    let path = entry?.into_path();
    if path.extension() == Some("rs".as_ref()) {
        println!("{}", path.display());
    }
}
```

### ignore

[![crates.io](https://img.shields.io/crates/v/ignore)](https://crates.io/crates/ignore) [![docs.rs](https://docs.rs/ignore/badge.svg)](https://docs.rs/ignore) [![license](https://img.shields.io/crates/l/ignore)](https://crates.io/crates/ignore) [![downloads](https://img.shields.io/crates/d/ignore)](https://crates.io/crates/ignore)

hidden fileや`gitignore`されているものを除外して探索できます。

[ripgrep](https://github.com/BurntSushi/ripgrep)の一部です。

```rust
use ignore::WalkBuilder;

let text_file_paths = WalkBuilder::new(".")
    .require_git(true)
    .follow_links(true)
    .max_depth(Some(32))
    .build()
    .map(|entry| {
        let path = entry?.into_path();
        Ok(if path.extension() == Some("txt".as_ref()) {
            Some(path)
        } else {
            None
        })
    })
    .flat_map(Result::transpose)
    .collect::<Result<Vec<_>, ignore::Error>>()?;
```

ripgrepのファイルパス関連のオプションがそのまま使えます。 例えば`-g, --glob <GLOB>...`のフィルターが使えます。

```rust
use ignore::{overrides::OverrideBuilder, WalkBuilder};
use structopt::StructOpt;

#[derive(StructOpt)]
struct Opt {
    /// Include or exclude files. For more detail, see the help of ripgrep
    #[structopt(short, long, value_name("GLOB"))]
    glob: Vec<String>,
}

let Opt { glob } = Opt::from_args();

let mut overrides = OverrideBuilder::new(".");
for glob in glob {
    overrides.add(&glob)?;
}
let overrides = overrides.build()?;

for entry in WalkBuilder::new(".").overrides(overrides).build() {
    todo!();
}
```

> ```
>     -g, --glob <GLOB>...
>             Include or exclude files and directories for searching that match the given
>             glob. This always overrides any other ignore logic. Multiple glob flags may be
>             used. Globbing rules match .gitignore globs. Precede a glob with a ! to exclude
>             it. If multiple globs match a file or directory, the glob given later in the
>             command line takes precedence.
>
>             When this flag is set, every file and directory is applied to it to test for
>             a match. So for example, if you only want to search in a particular directory
>             'foo', then *-g foo* is incorrect because 'foo/bar' does not match the glob
>             'foo'. Instead, you should use *-g +++'foo/**'+++*.
>
>         --glob-case-insensitive
>             Process glob patterns given with the -g/--glob flag case insensitively. This
>             effectively treats --glob as --iglob.
>
>             This flag can be disabled with the --no-glob-case-insensitive flag.
> ```

### duct

[![crates.io](https://img.shields.io/crates/v/duct)](https://crates.io/crates/duct) [![docs.rs](https://docs.rs/duct/badge.svg)](https://docs.rs/duct) [![license](https://img.shields.io/crates/l/duct)](https://crates.io/crates/duct) [![downloads](https://img.shields.io/crates/d/duct)](https://crates.io/crates/duct)

扱いやすくした<code>[std::process::Command](https://doc.rust-lang.org/stable/std/process/struct.Command.html)</code>です。

`std::process::Command`と比べて

1. 短いです。一行に収まることが多いです。
2. ステータスチェック & 失敗時のエラーメッセージの設定が不要です。
3. `.stderr(Stdio::inherit())`が不要です。
4. `stdout`の`str::from_utf8`と`.trim_end()`が不要です。

```rust
use duct::cmd;
use std::path::Path;

let path = Path::new("/etc/os-release");
let os_release = cmd!("cat", path).read()?; // マクロ版だと`.as_ref()`とかで`args`の型を揃えなくてもよい

if os_release.starts_with("NAME=\"Arch Linux\"") {
    println!("Arch Linux!");
}
```

また<code>[pipe](https://docs.rs/duct/0.13.4/duct/struct.Expression.html#method.pipe)</code>でパイプ処理が可能です。

```rust
use duct::cmd;
use duct_sh::sh; // ↓で紹介

let output = sh("yes | head -5").pipe(cmd!("xargs", "echo")).read()?;
assert_eq!(output, "y y y y y");
```

その関係でいくつかのdependencyがくっついてきますが、軽量な上にどの道他のdependencyにくっついてくるようなポピュラーなものばかりなので問題はあまり無いでしょう。

```
$ pwd # `git clone`したリポジトリ上
/home/ryo/src/github.com/oconnor663/duct.rs
$ cargo metadata --format-version 1 | jq -r '.workspace_members[]'
duct 0.13.4 (path+file:///home/ryo/src/github.com/oconnor663/duct.rs)
$ cargo metadata --format-version 1 | jq -r '. as $r | .packages[] | select(. as $p | $r.workspace_members | contains([$p.id]) | not) | .id' | sort
fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)
libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)
once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)
os_pipe 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)
rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)
rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)
rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)
rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)
remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)
shared_child 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)
tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)
winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)
winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)
winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)
```

### duct_sh

[![crates.io](https://img.shields.io/crates/v/duct_sh)](https://crates.io/crates/duct_sh) [![docs.rs](https://docs.rs/duct_sh/badge.svg)](https://docs.rs/duct_sh) [![license](https://img.shields.io/crates/l/duct_sh)](https://crates.io/crates/duct_sh) [![downloads](https://img.shields.io/crates/d/duct_sh)](https://crates.io/crates/duct_sh)

`cfg(unix)`の場合`/bin/sh -c ...`、`cfg(windows)`の場合`%COMSPEC% /C ...`を呼びだす`duct::{cmd, cmd!}`のショートカットです。

```rust
use duct_sh::sh;

let output = sh("echo Hello!").read()?;
assert_eq!(output, "Hello!");
```

### anyhow

[![crates.io](https://img.shields.io/crates/v/anyhow)](https://crates.io/crates/anyhow) [![docs.rs](https://docs.rs/anyhow/badge.svg)](https://docs.rs/anyhow) [![license](https://img.shields.io/crates/l/anyhow)](https://crates.io/crates/anyhow) [![downloads](https://img.shields.io/crates/d/anyhow)](https://crates.io/crates/anyhow)

（[thiserror](#thiserror)と合わせれば）[error-chain](https://crates.io/crates/error-chain) → [failure](https://crates.io/crates/failure) →と続くエラーハンドリングライブラリ3代目の最有力候補です。

[2019-10-05ZにInitial commit](https://github.com/dtolnay/anyhow/commit/138ec41c16179d70350fd52e96575a74bf19724d)された後[2日で1.0.0がリリースされ](https://github.com/dtolnay/anyhow/commit/3d65a7849c79b3faf9e731eda553cadcc98985a2)、爆発的に使われ始めました。2ヶ月経った頃には先発の[snafu](https://crates.io/crates/snafu)を総DL数で抜いて[Playgroundでも使えるようにもなりました](https://github.com/integer32llc/rust-playground/commit/ed8386a72a9919e9b823c2fd2e6cf937d0c809a2#diff-414118474d9e50d61fe1a39cb88a29f7)。 (2020-05-25現在は外れています)

<code>[anyhow::Error](https://docs.rs/anyhow/1/anyhow/struct.Error.html)</code>は`Box<std::error::Error>`や`failure::Error`のように`From<_: std::error::Error + Send + Sync + 'static>`を実装しているのでエラーを雑にまとめることができます。

あと`Debug`表示がhuman-readableになっているのでコードを書き始めるとき、あるいはサンプルコードを書くときに`main`の戻り値をとりあえず`anyhow::Result<()>`とするといいでしょう。流石に`"Error: "`や`"Cuased by:"`の部分をカラーにはしてくれませんが。

```rust
use anyhow::Context as _;
use std::fs;

fn main() -> anyhow::Result<()> {
    fs::read_to_string("./nonexisting.txt").with_context(|| "Could not read ./nonexisting.txt")?;
    Ok(())
}
```

```
Error: Could not read ./nonexisting.txt

Caused by:
    No such file or directory (os error 2)
```

[failureはdeprecatedになった](https://github.com/rust-lang-nursery/failure/pull/347)ので新規にコードを書くときはanyhowを使うべきでしょう。 現在は[cargo](https://crates.io/crates/cargo)もanyhowを使っています。 ただしanyhowはstable上でバックトレースを扱えません。 [backtrace](https://crates.io/crates/backtrace)クレートではなく現在安定化していない<code>[std::backtrace](https://doc.rust-lang.org/nightly/std/backtrace/index.html)</code>を[nightlyコンパイラ上でのみ](https://github.com/dtolnay/anyhow/blob/9060b6b754b05cd184c9549864cdd7b481dd8f84/build.rs)使っているためです。

See Also:

- [Rust のエラーまわりの変遷](https://qiita.com/legokichi/items/d4819f7d464c0d2ce2b8)
- [Error Handling Survey - YOSHUA WUYTS](https://blog.yoshuawuyts.com/error-handling-survey/)

```diff
-use std::fmt;
-use thiserror::Error;
-type Result<T> = std::result::Result<T, Box<dyn std::error::Error + 'static>>;
-trait ResultExt {
-    fn with_context<F: FnOnce() -> E, E: fmt::Display>(self, f: F) -> Self;
-}
-impl<T> ResultExt for Result<T> {
-    fn with_context<F: FnOnce() -> E, E: fmt::Display>(self, f: F) -> Self {
-        #[derive(Debug, Error)]
-        #[error("{}", .0)]
-        struct WithContext(String, #[source] Box<dyn std::error::Error + 'static>);
-        self.map_err(|e| WithContext(f().to_string(), e).into())
-    }
-}
+use anyhow::Context as _;
 ​
-fn main() -> Result<()> {
+fn main() -> anyhow::Result<()> {
     todo!();
 }
```

### either

[![crates.io](https://img.shields.io/crates/v/either)](https://crates.io/crates/either) [![docs.rs](https://docs.rs/either/badge.svg)](https://docs.rs/either) [![license](https://img.shields.io/crates/l/either)](https://crates.io/crates/either) [![downloads](https://img.shields.io/crates/d/either)](https://crates.io/crates/either)

<code>[Either\<\_, \_\>](https://docs.rs/either/1/either/enum.Either.html)</code>と<code>[try\_left!](https://docs.rs/either/1/either/macro.try_left.html)</code>, <code>[try\_right!](https://docs.rs/either/1/either/macro.try_right.html)</code>を提供します。

即席の構造体としてタプルが使えるように`Either`は即席の（バリアント2つの）直和型として使えます。

また`Either`には使いやすくするためのメソッドがいくつか付いていて、また`std`の各トレイトについて`impl<L: Trait, R: Trait> Trait for Either<L, R>`という定義がなされています。

実装が非常に小さいのもあり[itertools](#itertools)や[rayon](https://crates.io/crates/rayon)をはじめとした[多くのクレート](https://crates.io/crates/either/reverse_dependencies)に使われ、またre-exportされています。

ちなみに[即席直和型を専用構文付きで入れようという議論がpre 1.0時代からあります](https://github.com/rust-lang/rfcs/issues/2414)。

```diff
-enum Either<L, R> {
-    Left(L),
-    Right(L),
-}
+use either::Either;
```

### paste

[![crates.io](https://img.shields.io/crates/v/paste)](https://crates.io/crates/paste) [![docs.rs](https://docs.rs/paste/badge.svg)](https://docs.rs/paste) [![license](https://img.shields.io/crates/l/paste)](https://crates.io/crates/paste) [![downloads](https://img.shields.io/crates/d/paste)](https://crates.io/crates/paste)

[現在unstable](https://github.com/rust-lang/rust/issues/29599)である<code>[std::concat\_ident!](https://doc.rust-lang.org/stable/std/macro.concat_idents.html)</code>の代用となるマクロです。

[式](https://doc.rust-lang.org/reference/expressions.html)または[アイテム](https://doc.rust-lang.org/reference/items.html)単位で[識別子](https://doc.rust-lang.org/reference/identifiers.html)をconcatします。

proc-macroを書かなくても、このクレートがあればいくつかのケースでは`macro_rules!`だけでどうにかすることができます。

```rust
use std::path::{Path, PathBuf};

const _: fn(&Struct) -> &str = Struct::name;
const _: fn(&Struct) -> &Path = Struct::path;
const _: fn(&mut Struct) -> &mut String = Struct::name_mut;
const _: fn(&mut Struct) -> &mut PathBuf = Struct::path_mut;
const _: fn(&mut Struct, String) = Struct::set_name;
const _: fn(&mut Struct, PathBuf) = Struct::set_path;

struct Struct {
    name: String,
    path: PathBuf,
}

macro_rules! impl_accessor {
    ($struct:ident { $($tt:tt)* }) => {
        impl $struct {
            impl_accessor_inner!(@rest($($tt)*));
        }
    };
}

macro_rules! impl_accessor_inner {
    (@rest()) => {};
    (@rest($field:ident { get<& $get:ty>, get_mut<&mut $get_mut:ty>, set<$set:ty> } $($rest:tt)*)) => {
        fn $field(&self) -> &$get {
            &self.$field
        }

        paste::item! {
            fn [<$field _mut>] (&mut self) -> &mut $get_mut {
                &mut self.$field
            }
        }

        paste::item! {
            fn [<set_ $field>] (&mut self, $field:$set) {
                self.$field = $field;
            }
        }

        impl_accessor_inner!(@rest($($rest)*));
    };
}

impl_accessor! {
    Struct {
        name { get<&str>, get_mut<&mut String>, set<String> }
        path { get<&Path>, get_mut<&mut PathBuf>, set<PathBuf> }
    }
}
```

### if\_chain

[![crates.io](https://img.shields.io/crates/v/if_chain)](https://crates.io/crates/if_chain) [![docs.rs](https://docs.rs/if_chain/badge.svg)](https://docs.rs/if_chain) [![license](https://img.shields.io/crates/l/if_chain)](https://crates.io/crates/if_chain) [![downloads](https://img.shields.io/crates/d/if_chain)](https://crates.io/crates/if_chain)

`if`と`if let`を『まとめる』マクロ<code>[if\_chain!](https://docs.rs/if_chain/1/if_chain/macro.if_chain.html)</code>を提供します。

```rust
let x: Option<i32> = todo!();

if let Some(x) = x {
    if p(x) {
        f(x);
    } else {
        g();
    }
} else {
    g();
}
```

を

```rust
use if_chain::if_chain;

let x: Option<i32> = todo!();

if_chain! {
    if let Some(x) = x;
    if p(x);
    then {
        f(x);
    } else {
        g();
    }
}
```

のようにできます。`else`節が必要なくてもインデントを2段までに抑える効果があります。

難点はRustの構文としては不正なため現在の[rustfmt](https://github.com/rust-lang/rustfmt)では中がフォーマットできないことです。私はrustfmtっぽく手動フォーマットするのが面倒なので適当に書いちゃうことが多いです。

### maplit

[![crates.io](https://img.shields.io/crates/v/maplit)](https://crates.io/crates/maplit) [![docs.rs](https://docs.rs/maplit/badge.svg)](https://docs.rs/maplit) [![license](https://img.shields.io/crates/l/maplit)](https://crates.io/crates/maplit) [![downloads](https://img.shields.io/crates/d/maplit)](https://crates.io/crates/maplit)

`std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}`に対して`vec!`のようなマクロを提供します。また各key, valueを指定の関数に通す<code>[convert\_args!](https://docs.rs/maplit/1/maplit/macro.convert_args.html)</code>マクロも便利です。

結構歴史が長くポピュラーなクレートで、mapのようなデータ型を提供するライブラリは大抵これに似た形式のマクロを提供しています。

ちなみにpre 1.0時代から[こんな提案](https://github.com/rust-lang/rfcs/issues/542)があります。もしかしたら標準ライブラリに似たようなのが入るかもしれません。

```diff
-use std::collections::HashMap;
+use maplit::hashmap;
 ​
-let mut map = HashMap::new();
-map.insert("foo", 10);
-map.insert("bar", 20);
-map.insert("baz", 30);
+let map = hashmap!(
+    "foo" => 10,
+    "bar" => 20,
+    "baz" => 30,
+);
```

### structopt

[![crates.io](https://img.shields.io/crates/v/structopt)](https://crates.io/crates/structopt) [![docs.rs](https://docs.rs/structopt/badge.svg)](https://docs.rs/structopt) [![license](https://img.shields.io/crates/l/structopt)](https://crates.io/crates/structopt) [![downloads](https://img.shields.io/crates/d/structopt)](https://crates.io/crates/structopt)

[clap](https://crates.io/crates/clap)（コマンドラインパーサーのデファクトスタンダード）のラッパーです。

[v0.3でAPIが大きく変わりました](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md#v030-2019-08-30)。attributeは[一部の名前を除き](https://docs.rs/structopt/0.3.6/structopt/#magical-methods)、<code>[clap::Arg](https://docs.rs/clap/2/clap/struct.Arg.html)</code>のメソッドとして[扱われ](https://docs.rs/structopt/0.3.6/structopt/#raw-methods)ます。

またclapのv0.3でstructoptと同じAPIのderive macroが[追加される予定です](https://github.com/clap-rs/clap/tree/v3-dev#how-does-clap-compare-to-structopt)。

> **How does `clap` compare to [structopt](https://github.com/TeXitoi/structopt)?**
>
> Simple! `clap` *is* `stuctopt`. With the 3.0 release, `clap` imported the `structopt` code into it's own codebase as the [`clap_derive`](https://github.com/clap-rs/clap_derive) crate. Since `structopt` already used `clap` under the hood, the transition was nearly painless, and is 100% feature compatible. 
>
> If you were using `structopt` before, the only thing you should have to do is change the attributes from `#[structopt(...)]` to `#[clap(...)]`.
>
> Also the derive statements changed from `#[derive(Structopt)]` to `#[derive(Clap)]`. There is also some additional functionality that's been added to the `clap_derive` crate. See the documentation for that crate, for more details.

とのことなので安心して使いましょう。

数行で用意できるので引数を取らないアプリケーションで`--help`のためだけに使うのも良いでしょう。

```rust
use structopt::StructOpt;

#[derive(StructOpt)]
struct Opt {}

fn main() -> anyhow::Result<()> {
    Opt::from_args();
    Ok(())
}
```

ちなみにコマンドラインパーサーにはclapの他に以下のものがあります。

- [getopts](https://crates.io/crates/getopts) [![downloads](https://img.shields.io/crates/d/getopts)](https://crates.io/crates/getopts) （cargoはclapですがrustcはこれです）
- [docopt](https://crates.io/crates/docopt) [![downloads](https://img.shields.io/crates/d/docopt)](https://crates.io/crates/docopt)
- [argparse](https://crates.io/crates/argparse) [![downloads](https://img.shields.io/crates/d/argparse)](https://crates.io/crates/argparse)

See also:

- [実践structopt: Rustのコマンドラインパーサを使う](https://qiita.com/dalance/items/56dba0dd54c82f937feb)

```diff
-use clap::{App, Arg};
+use structopt::StructOpt;
 use url::Url;

 use std::ffi::OsStr;
 use std::path::PathBuf;

 static ARGS: &[&str] = &[
     "",
     "--norobots",
     "--config",
     "../config.yml",
     "https://example.com",
 ];
 ​
-let matches = App::new(env!("CARGO_PKG_NAME"))
-    .version(env!("CARGO_PKG_VERSION"))
-    .author(env!("CARGO_PKG_AUTHORS"))
-    .about(env!("CARGO_PKG_DESCRIPTION"))
-    .arg(
-        Arg::with_name("norobots")
-            .long("norobots")
-            .help("Ignores robots.txt"),
-    )
-    .arg(
-        Arg::with_name("config")
-            .long("config")
-            .value_name("PATH")
-            .default_value("./config.yml")
-            .help("Path to the config"),
-    )
-    .arg(
-        Arg::with_name("url")
-            .validator(|s| s.parse::<Url>().map(drop).map_err(|e| e.to_string()))
-            .help("URL"),
-    )
-    .get_matches_from_safe(ARGS)?;
-let norobots = matches.is_present("norobots");
-let config = PathBuf::from(matches.value_of_os("config").unwrap());
-let url = matches.value_of("url").unwrap().parse::<Url>().unwrap();
+#[derive(StructOpt)]
+#[structopt(author, about)]
+struct Opt {
+    /// Ignores robots.txt
+    #[structopt(long)]
+    norobots: bool,
+    /// Path to the config
+    #[structopt(long, value_name("PATH"), default_value("./config.yml"))]
+    config: PathBuf,
+    /// URL
+    url: Url,
+}
+let Opt {
+    norobots,
+    config,
+    url,
+} = Opt::from_iter_safe(ARGS)?;

 assert_eq!(norobots, true);
 assert_eq!(config, OsStr::new("../config.yml"));
 assert_eq!(url, "https://example.com".parse().unwrap());
```

### derivative

[![crates.io](https://img.shields.io/crates/v/derivative)](https://crates.io/crates/derivative) [![docs.rs](https://docs.rs/derivative/badge.svg)](https://docs.rs/derivative) [![license](https://img.shields.io/crates/l/derivative)](https://crates.io/crates/derivative) [![downloads](https://img.shields.io/crates/d/derivative)](https://crates.io/crates/derivative)

[ドキュメント](https://mcarton.github.io/rust-derivative/)（docs.rsには何も書かれていない）

`std`のderive macroの代替品を提供します。これらのマクロは型境界等を色々とカスタマイズできます。`Default`には[`Default::default`と同じ値を返すメソッド`new() -> Self`を生やすオプション](https://mcarton.github.io/rust-derivative/Default.html#new-function)もあります。

See also: [Rustのderiveはあまり頭がよくない](https://qnighy.hatenablog.com/entry/2017/06/01/070000)

```rust
use std::fmt;

struct Foo {
    name: String,
    content: ExternalNonDebuggableItem,
}

impl fmt::Debug for Foo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Foo")
            .field("name", &self.name)
            .field("content", &format_args!("_"))
            .finish()
    }
}
```

↓

```rust
use derivative::Derivative;

use std::fmt;

#[derive(Derivative)]
#[derivative(Debug)]
struct Foo {
    name: String,
    #[derivative(Debug(format_with = "fmt_underscore"))]
    content: ExternalNonDebuggableItem,
}

fn fmt_underscore(_: impl Sized, fmt: &mut fmt::Formatter) -> fmt::Result {
    write!(fmt, "_")
}
```

### derive\_more

[![crates.io](https://img.shields.io/crates/v/derive_more)](https://crates.io/crates/derive_more) [![docs.rs](https://docs.rs/derive_more/badge.svg)](https://docs.rs/derive_more) [![license](https://img.shields.io/crates/l/derive_more)](https://crates.io/crates/derive_more) [![downloads](https://img.shields.io/crates/d/derive_more)](https://crates.io/crates/derive_more)

[derivative](#derivative)と同じく`std`のトレイトに対するderive macroを提供しますが、こちらは`From`, `Into`, `Deref`, `FromStr`, `Display`等`std`でderive macroが用意されていないものが対象です。

また[`new`というメソッドを生やすderive macro](https://jeltef.github.io/derive_more/derive_more/constructor.html)がありますが、カスタマイズができないのでしたい場合は（ドキュメントにも書かれてますが）[derive-new](#derive-new)を使いましょう。

```diff
-use std::fmt;
+use derive_more::Display;
 ​
+#[derive(Display)]
+#[display(fmt = "({}, {})", _0, _1)]
 struct Point2(f64, f64);
-
-impl fmt::Display for Point2 {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        write!(fmt, "({}, {})", self.0, self.1)
-    }
-}
```

### thiserror

[![crates.io](https://img.shields.io/crates/v/thiserror)](https://crates.io/crates/thiserror) [![docs.rs](https://docs.rs/thiserror/badge.svg)](https://docs.rs/thiserror) [![license](https://img.shields.io/crates/l/thiserror)](https://crates.io/crates/thiserror) [![downloads](https://img.shields.io/crates/d/thiserror)](https://crates.io/crates/thiserror)

<code>[std::error::Error](https://doc.rust-lang.org/stable/std/error/trait.Error.html)</code>を対象とするderive macroを提供します。`source`には[anyhow](#anyhow)を使うといいでしょう。

```rust
use std::path::PathBuf;
use std::{fmt, io};

#[derive(Debug)]
enum Error {
    ReadFile(PathBuf, io::Error),
    Command(PathBuf, io::Error),
    Reqwest(reqwest::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::ReadFile(path, _) => write!(fmt, "Failed to read {}", path.display()),
            Self::Command(path, _) => write!(fmt, "Failed to execute {}", path.display()),
            Self::Reqwest(err) => write!(fmt, "{}", err),
        }
    }
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::ReadFile(_, source) | Self::Command(_, source) => Some(source),
            Self::Reqwest(err) => err.source(),
        }
    }
}
```

↓

```rust
use thiserror::Error;

use std::io;
use std::path::PathBuf;

#[derive(Debug, Error)]
enum Error {
    #[error("Failed to read {}", .0.display())]
    ReadFile(PathBuf, #[source] io::Error),
    #[error("Failed to execute {}", .0.display())]
    Command(PathBuf, #[source] io::Error),
    #[error("{}", .0)]
    Reqwest(#[from] reqwest::Error),
}
```

### num-derive

[![crates.io](https://img.shields.io/crates/v/num-derive)](https://crates.io/crates/num-derive) [![docs.rs](https://docs.rs/num-derive/badge.svg)](https://docs.rs/num-derive) [![license](https://img.shields.io/crates/l/num-derive)](https://crates.io/crates/num-derive) [![downloads](https://img.shields.io/crates/d/num-derive)](https://crates.io/crates/num-derive)

[num-traits](https://crates.io/crates/num-derive)の各トレイトを実装するderive macro集です。

1. filedが1つのtuple struct (e.g. `struct Foo(i32)`)
2. variantがすべてunitのenum (e.g. `enum Bar { A, B }`)

が対象です。 このクレートは[num](https://crates.io/crates/num)には含まれていません。

注意: [rust-num/num-derive#34](https://github.com/rust-num/num-derive/issues/34)

```rust
use num_derive::{FromPrimitive, Num, NumCast, NumOps, One, ToPrimitive, Zero};

#[derive(Zero, One, FromPrimitive, ToPrimitive, NumCast, NumOps, PartialEq, Num)]
struct Newtype(i64);

#[derive(FromPrimitive, ToPrimitive)]
enum Enum {
    A,
    B,
    C,
}
```

### strum

[![crates.io](https://img.shields.io/crates/v/strum)](https://crates.io/crates/strum) [![docs.rs](https://docs.rs/strum/badge.svg)](https://docs.rs/strum) [![license](https://img.shields.io/crates/l/strum)](https://crates.io/crates/strum) [![downloads](https://img.shields.io/crates/d/strum)](https://crates.io/crates/strum)

**`enum`の**文字列への/からの変換に特化したderive macro集です。

`FromStr`や`Display`の実装はもちろん、[`&'static str`へ変換](https://github.com/Peternator7/strum/wiki/Derive-IntoStaticStr)したり<code>[clap::arg\_enum!](https://docs.rs/clap/2/clap/macro.arg_enum.html)</code>のように[対応する文字列を`&[&str]`で得](https://github.com/Peternator7/strum/wiki/Derive-EnumVariantNames)たり[個数を定数で得](https://github.com/Peternator7/strum/wiki/Derive-EnumCount)たり[各バリアントからフィールドを抜いた`enum`を生成](https://github.com/Peternator7/strum/wiki/Derive-EnumDiscriminants)したりすることができます。

少し前までstrumとstrum-macroの2つのクレートを使う形でしたが[0.16.0からfeature-gatedの形でderive macroをre-exportするように](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md#0160)なりました。ドキュメントはそのままのようですが..

```toml
[dependencies]
strum = { version = "0.17.1", features = ["derive"] }
```

serdeと同様の問題を抱えていますが（前はメソッドを直に生やしてたのがトレイトを経由するようになり、それらがマクロ名と衝突する）[皆がfeatureを有効化すれば良い話なので使いましょう](https://qiita.com/qnighy/items/74ff6436860c79ceb940#derive-を使うべきか使わざるべきか)。

See also: [serdeの \`derive\` feature と名前空間の困った関係](https://qiita.com/qnighy/items/74ff6436860c79ceb940)

```diff
-use std::convert::Infallible;
-use std::str::FromStr;
+use structopt::StructOpt;
+use strum::{EnumString, EnumVariantNames, VariantNames as _};

 #[derive(StructOpt)]
 struct Opt {
     /// Output format
     #[structopt(
         long,
         value_name("FORMAT"),
         default_value("human"),
         possible_values(Format::VARIANTS)
     )]
     format: Format,
 }
 ​
+#[derive(EnumString, EnumVariantNames)]
+#[strum(serialize_all = "kebab-case")]
 enum Format {
     Human,
     Json,
 }
-
-impl Format {
-    const VARIANTS: &'static [&'static str] = &["human", "json"];
-}
-
-impl FromStr for Format {
-    type Err = Infallible;
-
-    fn from_str(s: &str) -> Result<Self, Infallible> {
-        match s {
-            "human" => Ok(Self::Human),
-            "json" => Ok(Self::Json),
-            _ => todo!(),
-        }
-    }
-}
```

### derive-new

[![crates.io](https://img.shields.io/crates/v/derive-new)](https://crates.io/crates/derive-new) [![docs.rs](https://docs.rs/derive-new/badge.svg)](https://docs.rs/derive-new) [![license](https://img.shields.io/crates/l/derive-new)](https://crates.io/crates/derive-new) [![downloads](https://img.shields.io/crates/d/derive-new)](https://crates.io/crates/derive-new)

コンストラクタを`"new"`という名のメソッドとして生やすderive macroです。

<code>[derive\_more::Constructor](https://jeltef.github.io/derive_more/derive_more/constructor.html)</code>とは違い、fieldの値を設定することで引数を減らすことができます。

引数を取らず、`Default::default`と同じ値を返すのなら[derivative](#derivative)の<code>[#\[derivative(Default(new = "true"))\]](https://mcarton.github.io/rust-derivative/Default.html#new-function)</code>を使うといいでしょう。

```diff
+use derive_new::new;
+
+#[derive(new)]
 struct Item {
     x: i32,
+    #[new(value = "42")]
     y: i32,
 }
-
-impl Item {
-    fn new(x: i32) -> Self {
-        Self { x, y: 42 }
-    }
-}
```

### getset

[![crates.io](https://img.shields.io/crates/v/getset)](https://crates.io/crates/getset) [![docs.rs](https://docs.rs/getset/badge.svg)](https://docs.rs/getset) [![license](https://img.shields.io/crates/l/getset)](https://crates.io/crates/getset) [![downloads](https://img.shields.io/crates/d/getset)](https://crates.io/crates/getset)

getterとsetterを生やすderive macroです。

難点は個々のgetter/setterにdocが設定できない（フィールドのdocが使われる）点と<code>\&[Deref](https://doc.rust-lang.org/stable/std/ops/trait.Deref.html)::Target</code>（e.g. `&String` → `&str`）を返すgetterを作れない点です。ただ`pub(crate)`までなら問題にはならないでしょう。

```diff
+use getset::{CopyGetters, MutGetters, Setters};
+
+#[derive(CopyGetters, MutGetters, Setters)]
 pub(crate) struct Item {
+    #[get_copy = "pub(crate)"]
+    #[get_mut = "pub(crate)"]
+    #[set = "pub(crate)"]
     param: u64,
 }
-
-impl Item {
-    #[inline]
-    pub(crate) fn param(&self) -> u64 {
-        self.param
-    }
-
-    #[inline]
-    pub(crate) fn param_mut(&mut self) -> &mut u64 {
-        &mut self.param
-    }
-
-    #[inline]
-    pub(crate) fn set_param(&mut self, param: u64) {
-        self.param = param;
-    }
-}
```

### derive\_builder

[![crates.io](https://img.shields.io/crates/v/derive_builder)](https://crates.io/crates/derive_builder) [![docs.rs](https://docs.rs/derive_builder/badge.svg)](https://docs.rs/derive_builder) [![license](https://img.shields.io/crates/l/derive_builder)](https://crates.io/crates/derive_builder) [![downloads](https://img.shields.io/crates/d/derive_builder)](https://crates.io/crates/derive_builder)

builder patternのbuilderを生成するマクロです。

`.build()`の返り値は`Result<_, _>`のみのようです。

```rust
use derive_builder::Builder;

#[derive(Builder)]
struct Foo {
    required_param: String,
    #[builder(default)]
    optional_param: Option<String>,
}

let item = FooBuilder::default()
    .required_param("foo".to_owned())
    .optional_param(Some("bar".to_owned()))
    .build()?;
```

### easy-ext

[![crates.io](https://img.shields.io/crates/v/easy-ext)](https://crates.io/crates/easy-ext) [![docs.rs](https://docs.rs/easy-ext/badge.svg)](https://docs.rs/easy-ext) [![license](https://img.shields.io/crates/l/easy-ext)](https://crates.io/crates/easy-ext) [![downloads](https://img.shields.io/crates/d/easy-ext)](https://crates.io/crates/easy-ext)

[extension trait pattern](https://github.com/rust-lang/rfcs/blob/master/text/0445-extension-trait-conventions.md)のためのproc-macroです。

```diff
+use easy_ext::ext;
 use termcolor::{BufferedStandardStream, ColorChoice};
 ​
-trait BufferedStandardStreamExt {
-    fn stderr_with_atty_filter(choice: ColorChoice) -> Self;
-}
-
-impl BufferedStandardStreamExt for BufferedStandardStream {
+#[ext]
+impl BufferedStandardStream {
     fn stderr_with_atty_filter(choice: ColorChoice) -> Self {
        let choice = if choice == ColorChoice::Always || atty::is(atty::Stream::Stderr) {
            choice
        } else {
            ColorChoice::Never
        };
        Self::stderr(choice)
     }
 }

 let _: fn(_) -> _ = BufferedStandardStream::stderr_with_atty_filter;
```

ふと試したところ`impl <T: Trait> _Dummy for T { .. }`とすることでトレイトに対して実装できるようです。

```rust
use easy_ext::ext;
use std::{
    fmt,
    io::{self, Sink},
};
use termcolor::{NoColor, WriteColor};

#[ext]
impl<W: WriteColor> __ for W {
    /// [`cargo::core::shell::Shell::warn`]のようなやつ
    ///
    /// [`cargo::core::shell::Shell::warn`]: https://docs.rs/cargo/0.44.1/cargo/core/shell/struct.Shell.html#method.warn
    fn warn<T: fmt::Display>(&mut self, message: T) -> io::Result<()> {
        todo!();
    }
}

let _: fn(_, _) -> _ = NoColor::<Sink>::warn::<&str>;
```

注意すべき点として、生成されるトレイトの名前は指定できますが今現在そのvisibilityを設定する方法はありません。

[Consider adding another way to specify visibility #13](https://github.com/taiki-e/easy-ext/issues/13)

## 型を強化する

### ghost

[![crates.io](https://img.shields.io/crates/v/ghost)](https://crates.io/crates/ghost) [![docs.rs](https://docs.rs/ghost/badge.svg)](https://docs.rs/ghost) [![license](https://img.shields.io/crates/l/ghost)](https://crates.io/crates/ghost) [![downloads](https://img.shields.io/crates/d/ghost)](https://crates.io/crates/ghost)

ジェネリックな`PhantomData`を生成します。

```rust
use ghost::phantom;

#[phantom]
pub struct MyPhantom<T: ?Sized>;
```

この`MyPhantom`は

```rust
pub enum MyPhantom<T: ?Sized> {
    __Phantom(self::__void_MyPhantom::MyPhantom<T>),
    MyPhantom,
}
```

のように展開されます。

何が嬉しいのかと言うと自分で書く型のため、自由にトレイトを実装することができます。 READMEにある例のように`IntoIterator`を実装する等といった使い方があります。

```rust
use ghost::phantom;
use std::vec;

fn main() {
    for item in Registry::<Flag> {
        let _: &'static str = item;
    }
}

#[phantom]
struct Registry<T: ?Sized>;

enum Flag {}

impl IntoIterator for Registry<Flag> {
    type Item = &'static str;
    type IntoIter = vec::IntoIter<&'static str>;

    fn into_iter(self) -> vec::IntoIter<&'static str> {
        vec!["foo", "bar", "baz"].into_iter()
    }
}
```

### ref-cast

[![crates.io](https://img.shields.io/crates/v/ref-cast)](https://crates.io/crates/ref-cast) [![docs.rs](https://docs.rs/ref-cast/badge.svg)](https://docs.rs/ref-cast) [![license](https://img.shields.io/crates/l/ref-cast)](https://crates.io/crates/ref-cast) [![downloads](https://img.shields.io/crates/d/ref-cast)](https://crates.io/crates/ref-cast)

`String`や`PathBuf`のnewtypeを作りたくなったとします。ここでは必ず絶対パスを示す`AbsPathBuf`を作りたいとします。

```rust
use std::ffi::OsString;
use std::path::Path;

/// An owned, mutable absolute path.
pub(crate) struct AbsPathBuf(OsString);

impl AbsPathBuf {
    #[inline]
    fn unchecked(s: OsString) -> Self {
        Self(s)
    }

    #[inline]
    fn new(s: OsString) -> Option<Self> {
        if Path::new(&s).is_absolute() {
            Some(Self::unchecked(s))
        } else {
            None
        }
    }
}
```

`AbsPathBuf`と来たら`AbsPath`を作りたくなります。これもいいですが

```rust
pub(crate) struct AbsPath<'a>(&'a OsStr);
```

せっかくなのでこうしたいです。

```rust
pub(crate) struct AbsPath(OsStr);
```

そうすると少し困ったことになります。`&OsStr`や`&AbsPathBuf`からどうやって`&AbsPath`を得るのでしょうか?

```rust
impl AbsPath {
    fn unchecked(s: &OsStr) -> &Self {
        todo!("what to do?")
    }
}

impl AbsPathBuf {
    fn as_abs_path(&self) -> &AbsPath {
        todo!("what to do?")
    }
}
```

実はunsafeな手段しかありません。

```rust
#[repr(transparent)]
pub(crate) struct AbsPath(OsStr);

impl AbsPath {
    fn unchecked(s: &OsStr) -> &Self {
        unsafe { &*(s as *const OsStr as *const AbsPath) }
    }
}

impl AbsPathBuf {
    fn as_abs_path(&self) -> &AbsPath {
        AbsPath::unchecked(&self.0)
    }
}
```

ここで注意しなければならないこととして、[安全性を確保するために`#[repr(C)]`か`#[repr(transparent)]`を付ける必要があります](https://github.com/lo48576/opaque_typedef/issues/1)。さて、何とかできましたが`unsafe`が出てしまいました。少し収まりが悪いです。

ここでこのクレートの出番です。ref-castはこのunsafe操作を肩代りしてくれます。何が嬉しいのかと言うとコードの見た目から`unsafe`が消えます。実は`#[forbid(unsafe_code)]`にも引っ掛らなくなるので[safety-dance](https://github.com/rust-secure-code/safety-dance)にも多分参加できます。

また"validation"も含めて簡易に実装できるようにする、[validated-slice](https://crates.io/crates/validated-slice)というクレート（作者は@lo48576氏）があるみたいです。

ちなみにこの例、**本気で**`Path` & `PathBuf`のように振る舞うnewtypeを作ろうと思うと山のような[メソッド](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#methods)と[トレイト](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#implementations)を実装しなければなりません。しかも不変条件を加味して調節しなければならないので辛いです。私もすこし前[Haskellのpath](https://www.stackage.org/package/path)のような[typed\_path](https://github.com/qryxip/typed_path)というクレートを作ろうとしたのですが1コミットもしないままローカルに眠っています（(`str` | `OsStr`) × (絶対パス | 制限無し) × (`file_name`が存在 | 制限無し) × (セパレータをネイティブに | `/`に | 制限無し)という制約を考えてました）。 やるんだったら[`url`](https://docs.rs/url)のように`Buf`版だけ用意するのを検討することをおすすめします。

今のところ`Path`(`Buf`)のnewtypeを提供するクレートは以下のものがあります。

- [path\_abs](https://crates.io/crates/path_abs)
- [relative-path](https://crates.io/crates/relative-path)
- [canonical-path](https://crates.io/crates/canonical-path)

```diff
+use ref_cast::RefCast
 use std::ffi::OsStr;

 /// An absolute path.
+#[derive(RefCast)]
 #[repr(transparent)]
 pub(crate) struct AbsPath(OsStr);

 impl AbsPath {
     fn unchecked(s: &OsStr) -> &Self {
-        unsafe { &*(s as *const OsStr as *const AbsPath) }
+        Self::ref_cast(s)
     }
 }
```

### dimensioned

[![crates.io](https://img.shields.io/crates/v/dimensioned)](https://crates.io/crates/dimensioned) [![docs.rs](https://docs.rs/dimensioned/badge.svg)](https://docs.rs/dimensioned) [![license](https://img.shields.io/crates/l/dimensioned)](https://crates.io/crates/dimensioned) [![downloads](https://img.shields.io/crates/d/dimensioned)](https://crates.io/crates/dimensioned)

物理量を表現できます。

```rust
use dimensioned::si;
use static_assertions::{assert_impl_all, assert_not_impl_any};

use std::ops::{Add, Div};

assert_eq!((3.0 * si::M / (2.0 * si::S)).to_string(), "1.5 m*s^-1");

assert_impl_all!(si::Meter<f64>: Div<si::Second<f64>, Output = si::MeterPerSecond<f64>>);
assert_not_impl_any!(si::Meter<f64>: Add<si::Second<f64>>);
```

### ascii

[![crates.io](https://img.shields.io/crates/v/ascii)](https://crates.io/crates/ascii) [![docs.rs](https://docs.rs/ascii/badge.svg)](https://docs.rs/ascii) [![license](https://img.shields.io/crates/l/ascii)](https://crates.io/crates/ascii) [![downloads](https://img.shields.io/crates/d/ascii)](https://crates.io/crates/ascii)

ASCII文字列を表現する<code>[AsciiChar](https://docs.rs/ascii/1/ascii/enum.AsciiChar.html)</code>, <code>[AsciiStr](https://docs.rs/ascii/1/ascii/struct.AsciiStr.html)</code>, <code>[AsciiString](https://docs.rs/ascii/1/ascii/struct.AsciiString.html)</code>を提供します。

それぞれの表現は`u8`, `[u8]`, `Vec<u8>`でチェック以外のオーバーヘッドはありません。 これらはASCII文字列を扱うにあたって(`u8`, `[u8]`, `Vec<u8>`)と(`char`, `str`, `String`)の両方の長所を持ちます。

```rust
use ascii::{AsciiChar, AsciiString};

let mut s = "abcde\n".parse::<AsciiString>()?;
s[2] = AsciiChar::C;
assert_eq!(s, "abCde\n");
assert_eq!(s.trim_end(), "abCde");
```

### unicase

[![crates.io](https://img.shields.io/crates/v/unicase)](https://crates.io/crates/unicase) [![docs.rs](https://docs.rs/unicase/badge.svg)](https://docs.rs/unicase) [![license](https://img.shields.io/crates/l/unicase)](https://crates.io/crates/unicase) [![downloads](https://img.shields.io/crates/d/unicase)](https://crates.io/crates/unicase)

case-insensitiveに2つの文字列を等値判定する関数と、それを`PartialEq`に使うnewtypeを提供します。

```rust
use unicase::UniCase;

let s1 = UniCase::new("aaa");
let s2 = UniCase::new("AAA");

assert_eq!(s1, s2);
```

### ordered-float

[![crates.io](https://img.shields.io/crates/v/ordered-float)](https://crates.io/crates/ordered-float) [![docs.rs](https://docs.rs/ordered-float/badge.svg)](https://docs.rs/ordered-float) [![license](https://img.shields.io/crates/l/ordered-float)](https://crates.io/crates/ordered-float) [![downloads](https://img.shields.io/crates/d/ordered-float)](https://crates.io/crates/ordered-float)

`Ord` (`: Eq`)を実装する<code>[NotNan](https://docs.rs/ordered-float/1/ordered_float/struct.NotNan.html)\<\_: [Float](https://docs.rs/num-traits/0.2/num_traits/float/trait.Float.html)\></code>と<code>[OrderedFloat](https://docs.rs/ordered-float/1/ordered_float/struct.OrderedFloat.html)\<\_: Float\></code>を提供します。

Rustの比較演算子用のインターフェイスには<code>[Eq](https://doc.rust-lang.org/stable/std/cmp/trait.Eq.html)</code>, <code>[Ord](https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html)</code>の他に<code>[PartialEq](https://doc.rust-lang.org/stable/std/cmp/trait.PartialEq.html)</code>, <code>[PartialOrd](https://doc.rust-lang.org/stable/std/cmp/trait.PartialOrd.html)</code>があります。具体的な要請はリンク先を参照してください。比較演算子には`PartialEq`と`PartialOrd`が使われます。

何故このような区分があるのかというと一つは浮動小数点数のためです。`f32`, `f64`は`PartialEq`, `PartialOrd`を実装していますが`Eq`, `Ord`は実装していません。つまりソート等が行なえません。というのもIEEE 754の浮動小数点数においては`==`の反射律すら成り立たないからです。他の言語においても配列のソートや順序を使うデータ構造の構築に`NaN`のような値を混ぜるとその結果は保証されません。[C++に至っては鼻から悪魔が出てきます](https://qnighy.hatenablog.com/entry/20100715/1279160054)。Rustではこのような関数やデータ構造に要素がtotal orderであることを要求することで『浮動小数点数をソートしたら何か変』という事態を防いでいます。

さて、我々Rustユーザーがソート等にどうやって浮動小数点数を使うのかというと... このうち関数については`.foo()`に対して大抵`.foo_by(impl FnMut(..) -> std::cmp::Ordering)`のようなものが共に用意されているのでこれを使えばどうにかすることができます。例えばソートに関しては雑にこのようなことができます。この場合、`NaN`が混じっていると`.unwrap()`の部分でpanicします。

```rust
let mut xs = vec![2.0, 1.0, 0.0];
xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
```

`max`や`min`も同様に`Iterator::max_by`を使うかあるいは`f64::max`で`fold`すれば良いです。

```rust
use std::f64;

static XS: &[f64] = &[0.0, 1.0, 2.0];

let max = XS.iter().copied().fold(f64::NEG_INFINITY, f64::max);
```

これが<code>[BTreeMap](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html)</code>や<code>[BinaryHeap](https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html)</code>等のデータ構造に使うとなるとこうはいきません。`f32`/`f64`に対するnewtypeが必要になります。そこでこのクレートの出番です。

```rust
use std::collections::BinaryHeap;

let mut queue = BinaryHeap::<f64>::new();

// error[E0599]: no function or associated item named `new` found for type `std::collections::BinaryHeap<f64>` in the current scope
//  --> src/lib.rs:6:36
//   |
// 5 | let mut queue = BinaryHeap::<f64>::new();
//   |                                    ^^^ function or associated item not found in `std::collections::BinaryHeap<f64>`
//   |
//   = note: the method `new` exists but the following trait bounds were not satisfied:
//           `f64 : std::cmp::Ord`
```

`NotNan<_>`は名の通りです。四則演算の結果`NaN`になったのなら整数型と同様にpanicします。ただしこちらはrelease buildでもチェックされます。

実際に使う際ですが、`f64`から`NotNan<f64>`に変換するには`NotNan::new(x).unwrap()`とする必要があります。 これは少々冗長です。 ただ`NotNan<f64>`は`FromStr`を実装していて、また四則演算の右辺には中身の型が許されているので`NatNan::new`を呼ぶ回数は少ないと思われます。

```rust
use ordered_float::NotNan;

let x = "42.0".parse::<NotNan<_>>().unwrap();
let half: NotNan<_> = x / 2.0;
let plus_one: NotNan<_> = x + 1.0;
```

リテラルが必要になる場合にはマクロを一行用意すると良いでしょう。

```rust
macro_rules! notnan(($lit:literal $(,)?) => (NotNan::new($lit).unwrap())); // NaNのリテラルは無い

let y = if p(x) { x } else { notnan!(1.0) };
```

`OrderedFloat<_>`は`NaN`を許容しますがそれを「最大の値であり、自身と等しい」としています。

こちらは`f64`からの変換は容易ですが`NotNan`と違い四則演算自体ができません。<code>[std::cmp::Reverse](https://doc.rust-lang.org/stable/std/cmp/struct.Reverse.html)</code>のようなものだと思いましょう。

### im

[![crates.io](https://img.shields.io/crates/v/im)](https://crates.io/crates/im) [![docs.rs](https://docs.rs/im/badge.svg)](https://docs.rs/im) [![license](https://img.shields.io/crates/l/im)](https://crates.io/crates/im) [![downloads](https://img.shields.io/crates/d/im)](https://crates.io/crates/im)

`std::collections::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, vec::Vec}`のimmutable data版を提供します。

```diff
-let mut map = maplit::hashmap!();
-map.insert("foo", 42);
+let map = im::hashmap!();
+let map = map.update("foo", 42);
```

OCamlやHaskell等を使っている方は馴染み深いのではないでしょうか。それぞれの中身は[こんな感じ](https://docs.rs/im/14.1.0/im/#lists)のようです。

ただしAPIは`std`のものに寄せられており、たびたび`&mut self`が要求されます。

```rust
let mut xs = im::vector![1, 2, 3];
xs.push_back(4);
```

[im](https://crates.io/crates/im)と[im-rc](https://crates.io/crates/im-rc)に分けられていますがその違いは前者は<code>[Arc](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html)</code>、後者は<code>[Rc](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html)</code>を使っていることです。
im-rcのデータ型は<code>[Sync](https://doc.rust-lang.org/stable/std/marker/trait.Sync.html)</code>でも<code>[Send](https://doc.rust-lang.org/stable/std/marker/trait.Send.html)</code>でもなく、複数のスレッドから参照するのはもちろん、他スレッドにmoveすることもできません。

ちなみに`Arc`を`Rc`にすることで得られる恩恵は"20-25% increase in general performance"だそうです。

### indexmap

[![crates.io](https://img.shields.io/crates/v/indexmap)](https://crates.io/crates/indexmap) [![docs.rs](https://docs.rs/indexmap/badge.svg)](https://docs.rs/indexmap) [![license](https://img.shields.io/crates/l/indexmap)](https://crates.io/crates/indexmap) [![downloads](https://img.shields.io/crates/d/indexmap)](https://crates.io/crates/indexmap)

<code>[IndexMap](https://docs.rs/indexmap/1/indexmap/map/struct.IndexMap.html)</code>, <code>[IndexSet](https://docs.rs/indexmap/1/indexmap/map/struct.IndexSet.html)</code>とそれらを生成する[maplit](#maplit)風のコンストラクタ用マクロ<code>[indexmap!](https://docs.rs/indexmap/1/indexmap/macro.indexmap.html)</code>, <code>[indexset!](https://docs.rs/indexmap/1/indexmap/macro.indexset.html)</code>を提供します。

Javaの<code>[LinkedHashMap](https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html)</code>, C#の<code>[OrderedDictionary](https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized.ordereddictionary?view=netframework-4.8)</code>, Pythonの<code>[OrderedDict](https://docs.python.org/3.8/library/collections.html#collections.OrderedDict)</code>のようなものです。

「`Vec<(K, V)>`にしたいけど`K`の重複が無いことを示したい」というとき等に便利です。また[serde](https://crates.io/crates/serde)（特に"ser"の方）と相性がいいです。

```rust
use indexmap::IndexMap;

static JSON: &str = r#"{"c":3,"b":2,"a":1}"#;

let map = serde_json::from_str::<IndexMap<String, u32>>(JSON)?;
assert_eq!(serde_json::to_string(&map)?, JSON);
```

## 今のRustでは不可能な抽象化を擬似的に表現する

### typenum

[![crates.io](https://img.shields.io/crates/v/typenum)](https://crates.io/crates/typenum) [![docs.rs](https://docs.rs/typenum/badge.svg)](https://docs.rs/typenum) [![license](https://img.shields.io/crates/l/typenum)](https://crates.io/crates/typenum) [![downloads](https://img.shields.io/crates/d/typenum)](https://crates.io/crates/typenum)

「型パラメータとしての整数」を表現します。

[4桁以下なら定数が揃っていますが](https://docs.rs/typenum/1/typenum/consts/index.html)それより大きい値は2つの既存の値を`+-*/`したりビットで表現することで生み出します。

### generic-array

[![crates.io](https://img.shields.io/crates/v/generic-array)](https://crates.io/crates/generic-array) [![docs.rs](https://docs.rs/generic-array/badge.svg)](https://docs.rs/generic-array) [![license](https://img.shields.io/crates/l/generic-array)](https://crates.io/crates/generic-array) [![downloads](https://img.shields.io/crates/d/generic-array)](https://crates.io/crates/generic-array)

`[T; _]`のように振る舞う、長さを<code>[typenum::UInt](https://docs.rs/typenum/1/typenum/uint/struct.UInt.html)</code>で表現する<code>[GenericArray\<T, \_\>](https://docs.rs/generic-array/0.13/generic_array/struct.GenericArray.html)</code>を提供します。

ちなみに`GenericArray<T, _>: IntoIterator<Item = T>`です。（これを書いているときのRust 1.40の時点では`[T; _]: IntoIterator`ではありません。）

## `std`の挙動を改善する

### crossbeam

[![crates.io](https://img.shields.io/crates/v/crossbeam)](https://crates.io/crates/crossbeam) [![docs.rs](https://docs.rs/crossbeam/badge.svg)](https://docs.rs/crossbeam) [![license](https://img.shields.io/crates/l/crossbeam)](https://crates.io/crates/crossbeam) [![downloads](https://img.shields.io/crates/d/crossbeam)](https://crates.io/crates/crossbeam)

並行処理を行なう低レベルのライブラリです。

[rayon](https://crates.io/crates/rayon)（並列処理用のライブラリ）, [tokio](https://crates.io/crates/tokio)（非同期処理用のライブラリ）に使われています。crossbeamが提供する機能はそれらより低レベルで、<code>[std::sync](https://doc.rust-lang.org/stable/std/sync/index.html)</code>の改善に焦点をあてています。`std::sync` + `std::thread`で苦労したのなら使うと幸せになれるかもしれません。

- [MPSC (Multi-Producer Single-Consumer) channel](https://doc.rust-lang.org/stable/std/sync/mpsc/index.html)の欠点を解消し、パフォーマンスも向上した[MP **M** C (Multi-Producer **Multi** -Consumer) channle](https://docs.rs/crossbeam/0.7/crossbeam/channel/index.html)
- [MPMC queue](https://docs.rs/crossbeam/0.7/crossbeam/queue/index.html)
- [work-stealing deque](https://docs.rs/crossbeam/0.7/crossbeam/deque/index.html)
- [GC](https://docs.rs/crossbeam/0.7/crossbeam/epoch/index.html)
- [複数のスレッドをspawnしてその場でそれらの終了を待つ、`'static`を要求しない関数](https://docs.rs/crossbeam/0.7/crossbeam/fn.scope.html)

など提供するものは多岐にわたります。

実際に使うときは[bloat](https://raphlinus.github.io/rust/2019/08/21/rust-bloat.html)を避けるため、個別のsubcrate (crossbeam-\*)を使うと良いでしょう。

See also:

- [MultiProducer-MultiConsumer (MPMC) channel using crossbeam-channel - Qiita](https://qiita.com/termoshtt/items/b4561180894104c1c4c2)
- [Lock-free Rust: Crossbeam in 2019 - stjepang.github.io](https://stjepang.github.io/2019/01/29/lock-free-rust-crossbeam-in-2019.html)

```diff
-let (tx, rx) = std::sync::mpsc::channel();
+let (tx, rx) = crossbeam_channel::unbounded();
 tx.send(42)?;
 assert_eq!(rx.recv()?, 42);
```

### libm

[![crates.io](https://img.shields.io/crates/v/libm)](https://crates.io/crates/libm) [![docs.rs](https://docs.rs/libm/badge.svg)](https://docs.rs/libm) [![license](https://img.shields.io/crates/l/libm)](https://crates.io/crates/libm) [![downloads](https://img.shields.io/crates/d/libm)](https://crates.io/crates/libm)

libmのRust実装です。

[最近になってからコンパイラに使われるようにようになったみたいです](https://github.com/rust-lang/libm/issues/195#issuecomment-508161017)。（丸め方法等を除いて）プラットフォームに依らない挙動をしていて、[数値を扱うクレートに結構使われています](https://crates.io/crates/libm/reverse_dependencies)。

```diff
-let val = 10f64.powf(-9.0);
+let val = libm::pow(10.0, -9.0);
 assert_eq!(error.to_string(), "0.000000001");
```

### remove\_dir\_all

[![crates.io](https://img.shields.io/crates/v/remove_dir_all)](https://crates.io/crates/remove_dir_all) [![docs.rs](https://docs.rs/remove_dir_all/badge.svg)](https://docs.rs/remove_dir_all) [![license](https://img.shields.io/crates/l/remove_dir_all)](https://crates.io/crates/remove_dir_all) [![downloads](https://img.shields.io/crates/d/remove_dir_all)](https://crates.io/crates/remove_dir_all)

Windows用に改善した<code>[std::fs::remove\_dir\_all](https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html)</code>を提供します。Windows以外には`std::fs::remove_dir_all`をそのままre-exportしてます。

```diff
-std::fs::remove_dir_all("./dir")?;
+remove_dir_all::remove_dir_all("./dir")?;
```

### which

[![crates.io](https://img.shields.io/crates/v/which)](https://crates.io/crates/which) [![docs.rs](https://docs.rs/which/badge.svg)](https://docs.rs/which) [![license](https://img.shields.io/crates/l/which)](https://crates.io/crates/which) [![downloads](https://img.shields.io/crates/d/which)](https://crates.io/crates/which)

実行ファイルを探します。

Windowsでは[rust-lang/rust#37519](https://github.com/rust-lang/rust/issues/37519)があるのでそれを回避する目的で使えます。

注意するべき点として、デフォルトでエラーが<code>[failure::Fail](https://docs.rs/failure/0.1/failure/trait.Fail.html)</code>です。`default-features = false`で`std::error::Error`になりますが依存クレートのアップデートで壊れる可能性が付き纏います。 使うときはこのようにすれば良いでしょう。

```rust
use anyhow::anyhow;

let rustup = which::which("rustup")
    .map_err(|e| anyhow!("{}", e.kind()).context("failed to find `rustup`"))?;
```

### dunce

[![crates.io](https://img.shields.io/crates/v/dunce)](https://crates.io/crates/dunce) [![docs.rs](https://docs.rs/dunce/badge.svg)](https://docs.rs/dunce) [![license](https://img.shields.io/crates/l/dunce)](https://crates.io/crates/dunce) [![downloads](https://img.shields.io/crates/d/dunce)](https://crates.io/crates/dunce)

file pathを正規化するためのAPIとして、`std`には<code>[std::fs::canonicalize](https://doc.rust-lang.org/stable/std/fs/fn.canonicalize.html)</code>とそのショートカットの<code>[Path::canonicalize](https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.canonicalize)</code>があります。

ただしWindows上では、この`canonicalize`は`\\?\C:\foo\bar`のような"UNC path"を返します。 そしてマイクロソフト製のものを含め、多くのソフトウェアはUNC pathを扱うことができません。 **Rustの`std::fs`も同様です。**

[std::fs::canonicalize returns UNC paths on Windows, and a lot of software doesn't support UNC paths · Issue #42869 · rust-lang/rust](https://github.com/rust-lang/rust/issues/42869)

このクレートは[問題の無いときに限り](https://docs.rs/dunce/1.0.0/src/dunce/lib.rs.html#296-315)UNC pathを通常のものに変換する<code>[simplified](https://docs.rs/dunce/1/dunce/fn.simplified.html)</code>と、それを用いた<code>[canonicalize](https://docs.rs/dunce/1.0.0/dunce/fn.canonicalize.html)</code>の2つの関数を提供します。 Windows上でなければ`simplified`は何も行ないません。

```diff
-let path = path.canonicalize()?;
+let path = dunce::canonicalize(path)?;
```

## テストに役立つ

### pretty\_assertions

[![crates.io](https://img.shields.io/crates/v/pretty_assertions)](https://crates.io/crates/pretty_assertions) [![docs.rs](https://docs.rs/pretty_assertions/badge.svg)](https://docs.rs/pretty_assertions) [![license](https://img.shields.io/crates/l/pretty_assertions)](https://crates.io/crates/pretty_assertions) [![downloads](https://img.shields.io/crates/d/pretty_assertions)](https://crates.io/crates/pretty_assertions)

`pretty_assertions::{assert_eq!, assert_ne!}`を提供します。

これらが失敗したとき、メッセージが<code>[Debug](https://doc.rust-lang.org/stable/std/fmt/trait.Debug.html)</code>のpretty-printed表示のカラフルなdiffで表示されます。

`str`に対しては下の[difference](#difference)を使うことをおすすめします。

```diff
-assert_eq!(4, 2 + 2);
+pretty_assertions::assert_eq!(4, 2 + 2);
```

### difference

[![crates.io](https://img.shields.io/crates/v/difference)](https://crates.io/crates/difference) [![docs.rs](https://docs.rs/difference/badge.svg)](https://docs.rs/difference) [![license](https://img.shields.io/crates/l/difference)](https://crates.io/crates/difference) [![downloads](https://img.shields.io/crates/d/difference)](https://crates.io/crates/difference)

`str`のdiffが取れる関数のほか、それを使ったマクロ <code>[assert\_diff!](https://docs.rs/difference/2/difference/macro.assert_diff.html)</code>を提供します。

```diff
+use difference::assert_diff;
+
 static EXPECTED: &str = "foo\nbar\n";
 static ACTUAL: &str = "foo\nbar\n";
 ​
-assert_eq!(EXPECTED, ACTUAL);
+assert_diff!(EXPECTED, ACTUAL, "\n", 0);
```

### static\_assertions

[![crates.io](https://img.shields.io/crates/v/static_assertions)](https://crates.io/crates/static_assertions) [![docs.rs](https://docs.rs/static_assertions/badge.svg)](https://docs.rs/static_assertions) [![license](https://img.shields.io/crates/l/static_assertions)](https://crates.io/crates/static_assertions) [![downloads](https://img.shields.io/crates/d/static_assertions)](https://crates.io/crates/static_assertions)

コンパイル時の"assertion"を行なうマクロを多数提供します。

```rust
use static_assertions::{assert_cfg, assert_eq_align, assert_eq_size, const_assert_eq};

assert_cfg!(
    any(unix, windows),
    "There is only support for Unix or Windows",
);
assert_eq_size!(i64, u64);
assert_eq_align!([i32; 4], i32);
const_assert_eq!(1, 1);
```

### approx

[![crates.io](https://img.shields.io/crates/v/approx)](https://crates.io/crates/approx) [![docs.rs](https://docs.rs/approx/badge.svg)](https://docs.rs/approx) [![license](https://img.shields.io/crates/l/approx)](https://crates.io/crates/approx) [![downloads](https://img.shields.io/crates/d/approx)](https://crates.io/crates/approx)

`f32`や`f64`の等値判定が楽にできます。

ところでこれを使って<code>[PartialEq](https://doc.rust-lang.org/stable/std/cmp/trait.PartialEq.html)</code>を実装したくなりますが実は`PartialEq`も推移律は要求されるので良くありません。approxは`PartialEq`の代わりに絶対誤差(+ 相対誤差)の指定の元で等値判定する<code>[AbsDiffEq](https://docs.rs/approx/0.3/approx/trait.AbsDiffEq.html)</code>と<code>[RelativeEq](https://docs.rs/approx/0.3/approx/trait.RelativeEq.html)</code>というトレイトを提供しています。こちらを実装しましょう。

```rust
use approx::{abs_diff_eq, relative_eq};

abs_diff_eq!(1.0, 1.0);
relative_eq!(1.0, 1.0);
```

### version-sync

[![crates.io](https://img.shields.io/crates/v/version-sync)](https://crates.io/crates/version-sync) [![docs.rs](https://docs.rs/version-sync/badge.svg)](https://docs.rs/version-sync) [![license](https://img.shields.io/crates/l/version-sync)](https://crates.io/crates/version-sync) [![downloads](https://img.shields.io/crates/d/version-sync)](https://crates.io/crates/version-sync)

READMEを含むドキュメントに書かれている現在のパッケージ（`$CARGO_PKG_NAME`）を指しているバージョンのうち、現在のバージョン（`$CARGO_PKG_VERSION`）と異なるものを検出してくれます。

### assert_cmd

[![crates.io](https://img.shields.io/crates/v/assert_cmd)](https://crates.io/crates/assert_cmd) [![docs.rs](https://docs.rs/assert_cmd/badge.svg)](https://docs.rs/assert_cmd) [![license](https://img.shields.io/crates/l/assert_cmd)](https://crates.io/crates/assert_cmd) [![downloads](https://img.shields.io/crates/d/assert_cmd)](https://crates.io/crates/assert_cmd)

`bin`クレートの入力→出力を確かめる`integration-test`に使えます。

```rust
use predicates::Predicate;
use std::{str, time::Duration};

#[test]
fn test() -> std::result::Result<(), assert_cmd::cargo::CargoError> {
    assert_cmd::Command::cargo_bin("myapp")?
        .args(&["--noconfirm", "--config", "./config.toml"])
        .timeout(Duration::from_secs(10))
        .write_stdin(&b"input\n"[..])
        .assert()
        .success()
        .stdout(str_predicate(|s| s.starts_with("output\n")))
        .stderr("");

    Ok(())
}

fn str_predicate(p: impl Fn(&str) -> bool) -> impl Predicate<[u8]> {
    predicates::function::function(move |s| matches!(str::from_utf8(s), Ok(s) if p(s)))
}
```

### tempfile

[![crates.io](https://img.shields.io/crates/v/tempfile)](https://crates.io/crates/tempfile) [![docs.rs](https://docs.rs/tempfile/badge.svg)](https://docs.rs/tempfile) [![license](https://img.shields.io/crates/l/tempfile)](https://crates.io/crates/tempfile) [![downloads](https://img.shields.io/crates/d/tempfile)](https://crates.io/crates/tempfile)

名の通りです。 一時ファイルと一時ディレクトリを生成できます。

[assert\_cmd](#assert_cmd)と併用して`bin`クレートのテストにも使うことができます。

```rust
#[cfg(test)]
mod tests {
    use std::{
        fs::File,
        io::{self, Write as _},
        path::Path,
    };
    use tempfile::{NamedTempFile, TempDir, TempPath};

    #[test]
    fn tempfile() -> io::Result<()> {
        // 一時ファイル。

        let mut tempfile: File = tempfile::tempfile()?; // should be automatically removed by the OS
        writeln!(tempfile, "aaaaa")
    }

    #[test]
    fn named_tempfile() -> anyhow::Result<()> {
        // 一時ファイルとそのパス。 `NamedTempFile`と`TempPath`からなる。

        let mut named_tempfile = NamedTempFile::new()?;
        writeln!(named_tempfile, "bbbbb")?;

        let (_, temp_path): (File, TempPath) = named_tempfile.into_parts();
        let _: &Path = temp_path.as_ref();

        if false {
            temp_path.persist("./result.txt")?;
        }

        Ok(())
    }

    #[test]
    fn tempdir() -> io::Result<()> {
        // 一時ディレクトリ。 一応`Drop`時に対象のディレクトリの消去を試みるが、Windows等のために明示的に`close`する方が良いように思える。

        let tempdir: TempDir = tempfile::tempdir()?;

        let tempdir_path: &Path = tempdir.path();
        let tempdir_path = tempdir_path.to_owned();
        assert!(tempdir_path.is_dir());

        tempdir.close()?;
        assert!(!tempdir_path.exists());
        Ok(())
    }

    #[test]
    fn spooled_tempfile() -> io::Result<()> {
        // ある大きさまでファイルシステムにアクセスせずにin memoryに保存する、一時ファイルのように振る舞うオブジェクト。

        let mut spooled_tempfile = tempfile::spooled_tempfile(10);

        write!(spooled_tempfile, "0123456789")?;
        assert!(!spooled_tempfile.is_rolled());

        write!(spooled_tempfile, "a")?;
        assert!(spooled_tempfile.is_rolled());

        Ok(())
    }
}
```

### test-case

[![crates.io](https://img.shields.io/crates/v/test-case)](https://crates.io/crates/test-case) [![docs.rs](https://docs.rs/test-case/badge.svg)](https://docs.rs/test-case) [![license](https://img.shields.io/crates/l/test-case)](https://crates.io/crates/test-case) [![downloads](https://img.shields.io/crates/d/test-case)](https://crates.io/crates/test-case)

ある関数をテストする際、このように`assert_eq!`を並べることがあると思います。

```rust
fn equiv_mod(a: u32, b: u32, m: u32) -> bool {
    (a % m) == (b % m)
}

#[cfg(test)]
mod tests {
    use super::equiv_mod;

    #[test]
    fn test_equiv_mod_10() {
        assert_eq!(equiv_mod(0, 0, 10), true);
        assert_eq!(equiv_mod(0, 10, 10), true);
        assert_eq!(equiv_mod(1, 2, 10), false);
    }
}
```

そしてそれを関数やマクロでまとめることもあると思います。

```rust
#[cfg(test)]
mod tests {
    use super::equiv_mod;

    #[test]
    fn test_equiv_mod_10() {
        macro_rules! test(($($a:expr, $b:expr => $expected:expr,)*) => {
            $(
                {
                    let (a, b) = ($a, $b);
                    assert_eq!(equiv_mod(a, b, 10), $expected, "`equiv_mod({}, {}, 10)`", a, b);
                }
            )*
        });

        test! {
            0, 0  => true,
            0, 10 => true,
            1, 2  => false,
        }
    }
}
```

`test-case`はそのような単純なassertを簡潔に書けるようにするマクロです。

```rust
#[cfg(test)]
mod tests {
    use super::equiv_mod;
    use test_case::test_case;

    #[test_case(0, 0 => true; "0_equiv_0_mod_10")]
    #[test_case(1, 11 => true; "1_equiv_11_mod_10")]
    #[test_case(1, 2 => false; "1_not_equiv_2_mod_10")]
    fn test_equiv_mod_10(a: u32, b: u32) -> bool {
        equiv_mod(a, b, 10)
    }
}
```

`test_case::test_case!`は記述したテストケースをこのように個別のテストに展開します。

```
running 3 tests
test tests::test_equiv_mod_10::_0_equiv_0_mod_10 ... ok
test tests::test_equiv_mod_10::_1_equiv_11_mod_10 ... ok
test tests::test_equiv_mod_10::_1_not_equiv_2_mod_10 ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

### rusty-fork

[![crates.io](https://img.shields.io/crates/v/rusty-fork)](https://crates.io/crates/rusty-fork) [![docs.rs](https://docs.rs/rusty-fork/badge.svg)](https://docs.rs/rusty-fork) [![license](https://img.shields.io/crates/l/rusty-fork)](https://crates.io/crates/rusty-fork) [![downloads](https://img.shields.io/crates/d/rusty-fork)](https://crates.io/crates/rusty-fork)

ユニットテストを別プロセスで走らせることができるマクロです。

プロセスがabort等で終了しても他のテストが走り続けます。 またテストに対してタイムアウトを設定することができます。

```rust
#[cfg(test)]
mod tests {
    use rusty_fork::rusty_fork_test;
    use std::{env, fs};

    rusty_fork_test! {
        #![rusty_fork(timeout_ms = 1000)]

        #[test]
        fn test1() {
            test_set_current_dir("./dir-a")
        }

        #[test]
        fn test2() {
            test_set_current_dir("./dir-b")
        }

        #[test]
        fn test3() {
            test_set_current_dir("./dir-c")
        }
    }

    fn test_set_current_dir(dir_file_name: &str) {
        let dir = env::current_dir().unwrap().join(dir_file_name);
        fs::create_dir_all(&dir).unwrap();

        env::set_current_dir(&dir).unwrap();
        assert_eq!(env::current_dir().unwrap(), dir);
    }
}
```

### trybuild

[![crates.io](https://img.shields.io/crates/v/trybuild)](https://crates.io/crates/trybuild) [![docs.rs](https://docs.rs/trybuild/badge.svg)](https://docs.rs/trybuild) [![license](https://img.shields.io/crates/l/trybuild)](https://crates.io/crates/trybuild) [![downloads](https://img.shields.io/crates/d/trybuild)](https://crates.io/crates/trybuild)

コンパイルエラーのメッセージをassertするためのクレートです。

マクロ以外にも複雑な型境界を持つ普通の関数にも使えます。

```rust
use trybuild::TestCases;

#[test]
fn ui() {
    TestCases::new().compile_fail("tests/ui/**/*.rs");
}
```

使い方はREADMEの画像を見た方がわかりやすいでしょう。

> ![`trybuild`のREADMEの画像](https://user-images.githubusercontent.com/1940490/57186575-79418e80-6e96-11e9-9478-c9b3dc10327f.png)

テスト対象の`.rs`ファイルをディレクトリに入れ、走らせることでファイルパスがマスクされた`.stderr`ファイルが生成されます。 これを`.rs`ファイルと同じ場所に放り込めばテストが出来上がります。

> ![`trybuild`のREADMEの画像](https://user-images.githubusercontent.com/1940490/57186579-7cd51580-6e96-11e9-9f19-54dcecc9fbba.png)

`TRYBUILD=overwrite`と環境変数をセットした場合、`.stderr`ファイルは最初から同じディレクトリに生成されます。

### insta

[![crates.io](https://img.shields.io/crates/v/insta)](https://crates.io/crates/insta) [![docs.rs](https://docs.rs/insta/badge.svg)](https://docs.rs/insta) [![license](https://img.shields.io/crates/l/insta)](https://crates.io/crates/insta) [![downloads](https://img.shields.io/crates/d/insta)](https://crates.io/crates/insta)

`Debug`表記やJSON/YAML/RONの文字列で`assert_eq!`を行います。

[trybuild](#trybuild)と同じようにテストが書かれた`.rs`ファイルと同ディレクトリに`snapshots/{name}___snapshots.snap`というファイルが生成され、それが比較対象になります。

操作をインタラクティブに行うために`cargo-insta`というものが用意されているのでそれを使うのが良いでしょう。

```rust:tests/test.rs
use insta::assert_debug_snapshot;

#[test]
fn test_snapshots() {
    let value = vec![1, 2, 3];
    assert_debug_snapshot!(value);
}
```

```text
$ cargo insta test --review
```

![cargo-insta.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245660/979306df-9ea5-16d2-a4c8-df576cbf0b26.png)

## パフォーマンスの向上

### take\_mut

[![crates.io](https://img.shields.io/crates/v/take_mut)](https://crates.io/crates/take_mut) [![docs.rs](https://docs.rs/take_mut/badge.svg)](https://docs.rs/take_mut) [![license](https://img.shields.io/crates/l/take_mut)](https://crates.io/crates/take_mut) [![downloads](https://img.shields.io/crates/d/take_mut)](https://crates.io/crates/take_mut)

Rustでは`&mut T`の値にはそのまま`(T) -> T`の関数を適応することができません。<code>[Copy](https://doc.rust-lang.org/stable/std/marker/trait.Copy.html)</code>でもない限り何らかの壊れていない値を代わりに詰めておく必要があります。良く使われる方法が<code>[std::mem::replace](https://doc.rust-lang.org/stable/std/mem/fn.replace.html)</code>（またはRust 1.40で安定化された<code>[std::mem::take](https://doc.rust-lang.org/stable/std/mem/fn.take.html)</code>）でダミーの値を詰めることですがそのような生成に副作用を伴わず軽量な値が常に用意できるとは限りません。

<code>[take\_mut::take](https://docs.rs/take_mut/0.2/take_mut/fn.take.html)</code>ならダミーの値を用意しなくても`(T) -> T`の関数を適応できます。返せなくなったとき、すなわちpanicした場合プログラムをabortさせます。

あとパニックしたときのリカバリを設定できる<code>[take\_or\_resover](https://docs.rs/take_mut/0.2/take_mut/fn.take_or_recover.html)</code>やスコープ内で`RefCell`のように[move操作を実行時に判定](https://docs.rs/take_mut/0.2.2/take_mut/scoped/index.html#example)する<code>[scope](https://docs.rs/take_mut/0.2/take_mut/scoped/fn.scope.html)</code>という関数もあります。

See also: [Rustのパニック機構](https://qnighy.hatenablog.com/entry/2018/02/18/223000)

```diff
 use either::Either;

 let mut data: Either<LargeData, LargeData> = todo!();
 if let Either::Left(data) = &mut data {
-    *data = convert(data.clone());
+    take_mut::take(data, convert);
 }

 fn convert(_: LargeData) -> LargeData {
     todo!()
 }
```

### buf\_redux

[![crates.io](https://img.shields.io/crates/v/buf_redux)](https://crates.io/crates/buf_redux) [![docs.rs](https://docs.rs/buf_redux/badge.svg)](https://docs.rs/buf_redux) [![license](https://img.shields.io/crates/l/buf_redux)](https://crates.io/crates/buf_redux) [![downloads](https://img.shields.io/crates/d/buf_redux)](https://crates.io/crates/buf_redux)

`std::io::{BufReader, BufWriter, LineWriter}`と入れ替えるだけで速くなるみたいです。

```diff
-use std::io::{BufReader, BufWriter, LineWriter};
+use buf_redux::{BufReader, BufWriter, LineWriter};
```

### stable\_deref\_trait

[![crates.io](https://img.shields.io/crates/v/stable_deref_trait)](https://crates.io/crates/stable_deref_trait) [![docs.rs](https://docs.rs/stable_deref_trait/badge.svg)](https://docs.rs/stable_deref_trait) [![license](https://img.shields.io/crates/l/stable_deref_trait)](https://crates.io/crates/stable_deref_trait) [![downloads](https://img.shields.io/crates/d/stable_deref_trait)](https://crates.io/crates/stable_deref_trait)

このような構造体`Text`と`Word`を考えてみます。

```rust
use std::str::FromStr;

struct Text(Vec<Word>);

enum Word {
    Plain(String),
    Number(String),
    Whitespace(String),
    Lf,
}

impl Text {
    fn diff(&self, other: &Self) -> Result<(), Diff> {
        todo!()
    }
}

impl FromStr for Text {
    type Err = anyhow::Error;

    fn from_str(_: &str) -> anyhow::Result<Self> {
        todo!("parse with `nom` or `combine` or something")
    }
}
```

ここで`String`を沢山作るのは良くないと考えて`Word`をこのようにするとします。

```rust
enum Word<'a> {
    Plain(&'a str),
    Number(&'a str),
    Whitespace(&'a str),
    Lf,
}
```

<code>[Box::leak](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.leak)</code>でリークするのも良くないと考えて`Word`にライフタイムパラメータを持たせるとします。そうすると`Text`はこうなります。

```rust
struct Text<'a>(Vec<Word<'a>);
```

そうするとテキスト全体を表わす`String`の置き場所が困るので以下のようにしたいです。

```rust
struct Text(String, Vec<Word<'this>);
```

ここで**自己参照**することで問題を解決します。ここからは**unsafe**な操作になります。自己参照というと[pin](https://doc.rust-lang.org/stable/std/pin/index.html)がありますが今回はこれを使わなくても安全性を確保できます。まず[**細心の注意を払い**](https://doc.rust-lang.org/stable/nomicon/transmutes.html)<code>[std::mem::transmute](https://doc.rust-lang.org/stable/std/mem/fn.transmute.html)</code>でライフタイムパラメータを強制的に`'static`にします。ここでmutableな操作と自身のライフタイムを伴わない形での`&str`の持ち出しを防ぐため`mod`を切って『安全ではない』範囲を最小にします。

```rust
use self::inner::TextInner;

struct Text(TextInner);

enum Word<'a> {
    Plain(&'a str),
    Number(&'a str),
    Whitespace(&'a str),
    Lf,
}

mod inner {
    use super::Word;

    use std::mem;

    pub(super) struct TextInner {
        string: String,
        words: Box<[Word<'static>]>, // 実際は`'static`ではない!
    }

    impl TextInner {
        // `impl FnOnce(&str) -> Box<[Word]>`は`impl for<'a> FnOnce(&'a str) -> Box<[Word<'a>]>`の略。
        // `&str`や`Word`を外に持ち出すことはできない。自己参照でなくても良く使われる。
        pub(super) fn new(string: String, words: impl FnOnce(&str) -> Box<[Word]>) -> Self {
            // - `TextInner`はimmutable
            // - 各`&str`は`&'static str`として流出することはない。
            unsafe {
                Self {
                    words: mem::transmute(words(&string)),
                    string,
                }
            }
        }

        pub(super) fn string(&self) -> &str {
            &self.string
        }

        pub(super) fn words<'a>(&'a self) -> &[Word<'a>] {
            &self.words
        }
    }
}
```

あとの問題は`TextInner`がmoveしたときに`string: String`からの`&str`が壊れないかです。ここでこのクレートと[static\_assertions](#static_assertions)の出番です。これらを使って安心を得ます。

```diff
+use stable_deref_trait::StableDeref;
+use static_assertions::assert_impl_all;
+
+assert_impl_all!(String: StableDeref<Target = str>);
```

<code>[StableDeref](https://docs.rs/stable_deref_trait/1/stable_deref_trait/trait.StableDeref.html)</code>は（unsafeな操作でライフタイムを誤魔化しながら）自身がmoveしても`&Deref::Target`が壊れないものだけに実装されているunsafe traitです。`String`は無理矢理moveしても`&<String as Deref>::Target`（= `&str`）は壊れないので`String: StableDeref`です。ここで`&String`は壊れることに注意してください。上の例で`&str`の代わりに`&String`を持つとアウトです。

また<code>[CloneStableDeref](https://docs.rs/stable_deref_trait/1/stable_deref_trait/trait.CloneStableDeref.html)</code>は`StableDeref`のサブセットで、`clone`しても問題ないもの（`&_`, <code>[Rc\<\_\>](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html)</code>, <code>[Arc\<\_\>](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html)</code>）に対して実装されています。

### rental

[![crates.io](https://img.shields.io/crates/v/rental)](https://crates.io/crates/rental) [![docs.rs](https://docs.rs/rental/badge.svg)](https://docs.rs/rental) [![license](https://img.shields.io/crates/l/rental)](https://crates.io/crates/rental) [![downloads](https://img.shields.io/crates/d/rental)](https://crates.io/crates/rental)

[stable\_deref\_trait](#stable_deref_trait)で紹介した方法を自動でやるマクロです。`mod`ごと生成します。またコンストラクタのフィールドの順番も問題無いように並びかえてくれます。

```rust
#[macro_use]
extern crate rental;

rental! {
    mod inner {
        use super::Word;

        #[rental]
        pub(super) struct TextInner {
            string: String,
            words: Box<[Word<'string>]>,
        }
    }
}
```

### owning_ref

[![crates.io](https://img.shields.io/crates/v/owning_ref)](https://crates.io/crates/owning_ref) [![docs.rs](https://docs.rs/owning_ref/badge.svg)](https://docs.rs/owning_ref) [![license](https://img.shields.io/crates/l/owning_ref)](https://crates.io/crates/owning_ref) [![downloads](https://img.shields.io/crates/d/owning_ref)](https://crates.io/crates/owning_ref)

`Object: StableDeref`と`&PartOfObjectDeref`の組を`OwningRef<Object, PartOfObjectDeref>`または`OwningRefMut<〃, 〃>`として持てます。ただし"ref"の側は`&_`/`&mut _`である必要があり、上の`Text`, `Word<'_>`の例等では使えません。

```rust
use anyhow::anyhow;
use once_cell::sync::Lazy;
use owning_ref::OwningRef;
use regex::Regex;

let pair = OwningRef::new("  foo  ".to_owned()).try_map(|s| {
    static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("([a-z]+)").unwrap());
    REGEX
        .captures(&s)
        .map(|caps| caps.get(1).unwrap().as_str())
        .ok_or_else(|| anyhow!("not matched"))
})?;

assert_eq!(&*pair, "foo");
assert_eq!(pair.as_owner(), "  foo  ");
```

### smallvec

[![crates.io](https://img.shields.io/crates/v/smallvec)](https://crates.io/crates/smallvec) [![docs.rs](https://docs.rs/smallvec/badge.svg)](https://docs.rs/smallvec) [![license](https://img.shields.io/crates/l/smallvec)](https://crates.io/crates/smallvec) [![downloads](https://img.shields.io/crates/d/smallvec)](https://crates.io/crates/smallvec)

C++の<code>[boost::container::small\_vector](https://www.boost.org/doc/libs/1_71_0/doc/html/boost/container/small_vector.html)</code>のようなものです。

ある長さまで要素を『直に』持ち、残りを`Vec`のようにヒープアロケートします。

「大体は要素数1だけど複数ある場合も考えなくてはならない」といった場合にフィットします。

```diff
+use smallvec::SmallVec;
+
 use std::iter;

 let probably_single_values = (0..100)
     .map(|i| generate_values(i).collect())
-    .collect::<Vec<Vec<_>>>();
+    .collect::<Vec<SmallVec<[_; 1]>>>();
```

### arrayvec

[![crates.io](https://img.shields.io/crates/v/arrayvec)](https://crates.io/crates/arrayvec) [![docs.rs](https://docs.rs/arrayvec/badge.svg)](https://docs.rs/arrayvec) [![license](https://img.shields.io/crates/l/arrayvec)](https://crates.io/crates/arrayvec) [![downloads](https://img.shields.io/crates/d/arrayvec)](https://crates.io/crates/arrayvec)

C++の<code>[boost::container::static\_vector](https://www.boost.org/doc/libs/1_71_0/doc/html/boost/container/static_vector.html)</code>のようなものです。

こちらはヒープアロケーションを行なわず一定数までしか要素を持てません。

no-std環境の他「本当に高々\<コンパイル時定数\>個の要素しか持たない」といった場合にも使えます。

```diff
-let mut at_most_100 = vec![];
+use arrayvec::ArrayVec;
+
+let mut at_most_100 = ArrayVec::<[_; 100]>::new();
 at_most_100.push(42);
```

類似クレート:

- [stackvector](https://crates.io/crates/stackvector) [![downloads](https://img.shields.io/crates/d/stackvector)](https://crates.io/crates/stackvector)

### arraydeque

[![crates.io](https://img.shields.io/crates/v/arraydeque)](https://crates.io/crates/arraydeque) [![docs.rs](https://docs.rs/arraydeque/badge.svg)](https://docs.rs/arraydeque) [![license](https://img.shields.io/crates/l/arraydeque)](https://crates.io/crates/arraydeque) [![downloads](https://img.shields.io/crates/d/arraydeque)](https://crates.io/crates/arraydeque)

[arrayvec](#arrayvec)の<code>[VecDeque](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html)</code>版のようなものです。

[容量が無いときにエラーにするか反対側の要素を削除（排出）するかを選べます](https://docs.rs/arraydeque/0.4/arraydeque/behavior/index.html)。

```rust
use arraydeque::ArrayDeque;

let mut deque = ArrayDeque::<[_; 10]>::new();
deque.push_front(1)?;
deque.push_back(1)?;

let mut deque = ArrayDeque::<[_; 10], arraydeque::Wrapping>::new();
assert!(deque.push_front(1).is_none());
assert!(deque.push_back(1).is_none());
```

### enum-map

[![crates.io](https://img.shields.io/crates/v/enum-map)](https://crates.io/crates/enum-map) [![docs.rs](https://docs.rs/enum-map/badge.svg)](https://docs.rs/enum-map) [![license](https://img.shields.io/crates/l/enum-map)](https://crates.io/crates/enum-map) [![downloads](https://img.shields.io/crates/d/enum-map)](https://crates.io/crates/enum-map)

unit variantのみからなる`enum`をキーとする、中身が`[_; $num_variants]`のマップを作れます。

```diff
-use maplit::btreemap;
+use enum_map::{enum_map, Enum};
 ​
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Enum)]
 enum Key {
     A,
     B,
     C,
 }
 ​
-let map = btreemap! {
+let map = enum_map! {
     Key::A => 1,
     Key::B => 2,
     Key::C => 3,
 };
```

### enumset

[![crates.io](https://img.shields.io/crates/v/enumset)](https://crates.io/crates/enumset) [![docs.rs](https://docs.rs/enumset/badge.svg)](https://docs.rs/enumset) [![license](https://img.shields.io/crates/l/enumset)](https://crates.io/crates/enumset) [![downloads](https://img.shields.io/crates/d/enumset)](https://crates.io/crates/enumset)

[enum-map](#enum-map)のset版のようなものです。（作者は別です）

中身は`u8`, `u16`, `u32`, `u64`, `u128`のうち全variantが収まる最小のもので表現されるビット列です。

```diff
-use maplit::btreeset;
+use enumset::EnumSetType;
 ​
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
+#[derive(EnumSetType)]
 enum Value {
     A,
     B,
     C,
 }
 ​
-let set = btreeset!(Value::A, Value::B);
-assert!(set.contains(&Value::A));
-assert!(set.contains(&Value::B));
-assert!(!set.contains(&Value::C));
+let set = Value::A | Value::B;
+assert!(set.contains(Value::A));
+assert!(set.contains(Value::B));
+assert!(!set.contains(Value::C));
```

### phf

[![crates.io](https://img.shields.io/crates/v/phf)](https://crates.io/crates/phf) [![docs.rs](https://docs.rs/phf/badge.svg)](https://docs.rs/phf) [![license](https://img.shields.io/crates/l/phf)](https://crates.io/crates/phf) [![downloads](https://img.shields.io/crates/d/phf)](https://crates.io/crates/phf)

コンパイル時に生成できるhash mapとhash setです。

```diff
-use maplit::hashmap;
-use once_cell::sync::Lazy;
-use std::collections::HashMap;
+use phf::phf_map;
 ​
-static MAP: Lazy<HashMap<&str, i32>> = Lazy::new(|| {
-    hashmap!(
-        "foo" => 1,
-        "bar" => 2,
-    )
-});
+static MAP: phf::Map<&str, i32> = phf_map!(
+    "foo" => 1,
+    "bar" => 2,
+);

 assert_eq!(MAP["foo"], 1);
 assert_eq!(MAP["bar"], 2);
```

## コードの見た目を美しくする

### indoc

[![crates.io](https://img.shields.io/crates/v/indoc)](https://crates.io/crates/indoc) [![docs.rs](https://docs.rs/indoc/badge.svg)](https://docs.rs/indoc) [![license](https://img.shields.io/crates/l/indoc)](https://crates.io/crates/indoc) [![downloads](https://img.shields.io/crates/d/indoc)](https://crates.io/crates/indoc)

インデントされた文字列リテラルを**文字列リテラルのまま**unindentするマクロです。

```diff
+use indoc::indoc;
 ​
-static S: &str = r"---
-foo: 42
-bar: {}
-";
+static S: &str = indoc!(
+    "
+    ---
+    foo: 42
+    bar: {}
+    "
+);
```

raw string literalの書き方が気に入らない場合に綺麗な書き方ができます。

またbyte string literalにも対応しています。

```rust
static S: &[u8] = indoc!(b"foo");
```

unindentの処理(`(&str) -> String`)自体は[unindent](https://crates.io/crates/unindent)というクレートで提供されています。