[Rust]自作Errorを作りたくて`std::io::Error`を読んでみた！

# Error型自作の実践編を書きました
記事は[こちら](https://qiita.com/mutuya/items/b09881839c4e02b2f485)です。よかったらご覧ください。

# `Error`を自作したい！
Threadから独自の`Error`を含んだ`Result`を返したくなった！

私は今まで`Result<T,String>`で誤魔化してきた。しかし、それはもうやめだ！

0からは、さすがにどうすればいいかわからないので、初めに[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)を読んで見る。

# [`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)を読む
> [`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)トレイトとは、エラーの値を表す基本的な型であることを示しているトレイトです。エラーを表す型は、自分自身を説明できるように、[`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)と[`Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html)を実装していなくてはなりません。

> このトレイトが持つ[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)メソッドは一般的に'アブストラクト・バウンダー'[^1]を超えたときに使われます。もし、あるモジュールが、低レベルのモジュールで発生したエラーによって引き起こされたエラーを報告するとき、[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)メソッドによって、その低レベルのエラーへアクセスすることができます。これによって高レベルのモジュールは独自の`Error`を提供しながら、デバックのための実装を[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)のチェーンによって明らかにすることができます。

（以上、[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)の俺的意訳）

ざっくりいうと「[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)は`Result<T,E>`のEに用いられるような型であることを示し、このトレイトの持つ[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)メソッドを用いるとエラーをさかのぼることができる（さかのぼれるようにしなければならない）。」ということ。

[^1]: ごめんなさい。なんて訳せばいいのかわからなかった。全文読んだら、なんとなく言いたいことはわかると思います。

### [`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)の非推奨なメソッド
次の２つのメソッドは非推奨あつかいになっています。

- [`description`](https://doc.rust-lang.org/std/error/trait.Error.html#method.description)
- [`cause`](https://doc.rust-lang.org/std/error/trait.Error.html#method.cause)

[`description`](https://doc.rust-lang.org/std/error/trait.Error.html#method.description)はエラーの説明を文字列で返すメソッドですが、説明が必要なときはこれを使わず、[`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)や[`to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)メソッドを使うことを推奨しています。

[`cause`](https://doc.rust-lang.org/std/error/trait.Error.html#method.cause)は[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)に置き換えられるという形で非推奨になりました。

[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)には4つのメソッドがあり、その内、1つがNightlyで2つが非推奨。よって実際に書くのは1つだけですね！

# [`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)はわかったけど、どう実装すればいいの？
Error自作の肝である[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)についてはわかりました。しかし、どう実装すればいいのかわかりません。

そのため[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)を読んで勉強します。

# [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)の定義

[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)に関わる重要そうな定義を見ていく。

以下、[ここ](https://doc.rust-lang.org/src/std/io/error.rs.html)から重要そうな場所の抜粋。

```rust
enum Repr {
    Os(i32),
    Simple(ErrorKind),
    Custom(Box<Custom>),
}

struct Custom {
    kind: ErrorKind,
    error: Box<dyn error::Error + Send + Sync>,
}


pub struct Error {
    repr: Repr,
}

impl Error {
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
    where
        E: Into<Box<dyn error::Error + Send + Sync>>
    {
        Self::_new(kind, error.into())
    }
    
    fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
        Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
    }
}

impl Debug for Error { // something }

impl Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.repr {
            Repr::Os(code) => {
                let detail = sys::os::error_string(code);
                write!(fmt, "{} (os error {})", detail, code)
            }
            Repr::Custom(ref c) => c.error.fmt(fmt),
            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
        }
    }
}

impl error::Error for Error{
    fn description(&self) -> &str {
        match self.repr {
            Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
            Repr::Custom(ref c) => c.error.description(),
        }
    }

    fn cause(&self) -> Option<&dyn error:Error> {
        match self.repr {
            Repr::Os(..) => None
            Repr::Simple(..) => None,
            Repr::Custom(ref c) => c.error.cause(),
        }
    }

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Simple(..) => None,
            Repr::Custom(ref c) => c.error.source(),
        }
    }
}

enum ErrorKind{
    NotFound,
    PermissionDenied,
    // etc
}

impl ErrorKind {
    pub(crate) fn as_str(&self) -> &'static str {
        // エラーの種類ごとにmatchで、そのエラーの概要を
        // 表す文字列に変えて返す。
    }
}

impl From<ErrorKind> for Error { 
    fn from(kind: ErrorKind) -> Error {
        Error { repr: Repr::Simple(kind) }
    }
}
```

### [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)が表す種類
実装を見ると[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)は大雑把に*Os*、*Simple*、*Custom*の3種類のエラーを表すことがわかります。

詳しく見ていませんが**私が想像する**に

|   種類    |               説明                |
|:--------:|:--------------------------------:|
|   *Os*   | OSレベルのエラーを表す               |
| *Simple* | std::ioの関数内で発生したエラーを表す |
| *Custom* | 上2つ以外の独特なエラーを表す         |

だと、**予想**しました。

### *Os*を表す[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)の作成
*Os*を表す[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)を作るには[`last_os_error`](https://doc.rust-lang.org/std/io/struct.Error.html#method.last_os_error)か[`from_raw_os_error`](https://doc.rust-lang.org/std/io/struct.Error.html#method.from_raw_os_error)を実行します。

この種のエラーについては、Error自作の基本にかかわらないため、スルーします。[^2]

[^2]: もっと言えば、実装自体が難しくないため、説明しなくてもだいたい読めばわかると思います。


### *Simple*を表す[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)の作成

*Simple*を表す[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)は`From<ErrorKind>`が実装されてるので、これを用います。

```rust
// 実装
impl From<ErrorKind> for Error { 
    fn from(kind: ErrorKind) -> Error {
        Error { repr: Repr::Simple(kind) }
    }
}

// 例
let error = Error::from(ErrorKind::NotFound);
```


### *Custom*を表す[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)の作成
*Custom*を表す[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)は[`new`](https://doc.rust-lang.org/std/io/struct.Error.html#method.new)から作られます。

```rust
//実装
impl Error {
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
    where
        E: Into<Box<dyn error::Error + Send + Sync>>
    {
        Self::_new(kind, error.into())
    }
    
    fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
        Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
    }
}

// 例　文字列からエラーを作成する
let custom_error = Error::new(ErrorKind::Other, "oh no!");

// 例　他のエラーからエラーを作成する
let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
```

[`new`](https://doc.rust-lang.org/std/io/struct.Error.html#method.new)を読んでみると、次のようなことが書かれています。

> 任意のエラー内容と同様の既知の種類のエラーからI/Oエラーを作成します。

>この関数は一般的にOSから来たオリジナルではないI/Oエラーを作るために使用されます。`error`の引数は、この型に含まれる任意の内容が入れられます。

（以上、[`new`](https://doc.rust-lang.org/std/io/struct.Error.html#method.new)の俺的意訳）

なるほど。つまり、OSからのエラーなどの低レベルから連鎖してきたエラーなら、[`new`](https://doc.rust-lang.org/std/io/struct.Error.html#method.new)を使って作成ということですね。

そして`Custom`は、低層からのエラーと自身のいる層のエラー、の両方を含むものだよ。と。

#### 補足：`Into<Box<dyn error::Error + Send + Sync>>`のブランケット実装
`Box<dyn Error + Send + Sync + 'a>`は[`他のError`](https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3CE%3E-1)や[`&str`](https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3C%26%27_%20str%3E-6)から`From`で作成することができます。（[`他のError`](https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3CE%3E-1)や[`&str`](https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3C%26%27_%20str%3E-6)はリンクになってます。）

すなわち、[`他のError`](https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3CE%3E-1)や[`&str`](https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3C%26%27_%20str%3E-6)には`Into<Box<dyn error::Error + Send + Sync>>`がブランケット実装されているのです。

これによって例のような[`new`](https://doc.rust-lang.org/std/io/struct.Error.html#method.new)ができるわけですね。

# 改めて[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)を考える
ここで、ちょっと[`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)の[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)実装部分を読んで、[`description`](https://doc.rust-lang.org/std/error/trait.Error.html#method.description)、[`cause`](https://doc.rust-lang.org/std/error/trait.Error.html#method.cause)、[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)について復習します。

実装は次の通りです。

```rust
impl error::Error for Error{
    fn description(&self) -> &str {
        match self.repr {
            Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
            Repr::Custom(ref c) => c.error.description(),
        }
    }

    fn cause(&self) -> Option<&dyn error:Error> {
        match self.repr {
            Repr::Os(..) => None
            Repr::Simple(..) => None,
            Repr::Custom(ref c) => c.error.cause(),
        }
    }

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Simple(..) => None,
            Repr::Custom(ref c) => c.error.source(),
        }
    }
}
```

確かに、[`cause`](https://doc.rust-lang.org/std/error/trait.Error.html#method.cause)、[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)も同じような実装になっています。

また[`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)の実装を見てみると

```rust
impl Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.repr {
            Repr::Os(code) => {
                let detail = sys::os::error_string(code);
                write!(fmt, "{} (os error {})", detail, code)
            }
            Repr::Custom(ref c) => c.error.fmt(fmt),
            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
        }
    }
}
```

となっており、[`description`](https://doc.rust-lang.org/std/error/trait.Error.html#method.description)と同じ働きをしているのがわかります。

# まとめ
自作Error（[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)を実装した自作の型）を作るには

1. 対応したいエラーが、他のエラーによって誘起されるかどうか考える。 

2. エラーの種類を表す型(`ErrorKind`等)を作成する。
    -> もし他のエラーから誘起されるのなら誘起元のエラーを格納できるようにする。

3. 上の2番で作ったものを格納する自作Errorを定義する。

4. 自作Errorに[`error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)を実装する。
    -> もし他のエラーに誘起されるのなら[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)で誘起元のエラーを返せるようにする。
    -> （[`source`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source)にはデフォルトの実装が定義されているため誘起されないなら不要）

5. [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)や[`Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html)を実装する。
    -> このとき自作Errorの説明が返されるように実装する。

6. おわり。♪(((^-^)八(^∇^)))♪