erased_serdeで学ぶobject safeじゃないtraitをtrait objectで使う方法

この記事は[Rust Advent Calendar 2021 カレンダー2](https://qiita.com/advent-calendar/2021/rust)の10日目の記事です。

# trait objectとobject safety
みなさんtrait objectを使っていますか？
もちろんパフォーマンスのことなどを考えると、できるだけenum dispatchなどを使う方がいいのですが、利便性やapiの都合、パフォーマンスがいらない場合などではまあ便利だとおもいます。

あるtraitをtrait objectとして使う場合、traitがobject safetyという規則に従ったものでないといけません。この中に

- traitのメソッドがジェネリックなパラメータを持ってはいけない
- traitがSelf:Sizedを要求してはいけない

というのがあります。

```rust
trait ObjectSafe1{
    // object safe なメソッド
    fn safe_method_1(&self, value : i32) -> i32;
}

//object safeなメソッドだけなのでobject safeなtrait
trait ObjectSafe2<T>{
    // object safe なメソッド
    fn safe_method_2(&self, t : T) -> T;
}

//object safeでないメソッドがあるのでobject safeでないtrait
trait NotObjectSafe{
    // object safe でないメソッド
    fn not_safe_method_3<T>(&self, t : T) -> T;
    // 実はここにwhere Self : Sizedとつければobject safeにはなるが、
    // dynはSizedではないのでdynした時点でメソッドとして使えなくなる。
}

//sized を要求するのでobject safeでない
trait NotObjectSafe2 : Sized{
    fn method_4(self, value : i32) -> i32;
}

struct S;
impl ObjectSafe1 for S {
    fn safe_method_1(&self, value : i32) -> i32 { /*省略*/ }
}
impl ObjectSafe2<i32> for S {
    fn safe_method_2(&self, t : i32) -> i32 { /*省略*/ }
}
impl NotObjectSafe1 for S {
    fn not_safe_method_3<T>(&self, t : T) -> T  { /*省略*/ }
}
impl NotObjectSafe2 for S {
    fn method_4(self, value : i32) -> i32  { /*省略*/ }
}

fn test(){
    let x : Box<dyn ObjectSafe1> = Box::new(S);
    x.safe_method_1(1);
    let x : Box<dyn ObjectSafe2<i32>> = Box::new(S);
    x.safe_method_2(2);
    //let x : Box<dyn NotObjectSafe1> = Box::new(S); compile error
    // let x : Box<dyn NotObjectSafe2> = Box::new(S);
}
```
以上のように`NotObjectSafe`というトレイトはtrait objectにしようとするとcompile errorとなります。
このような例として[serde](https://docs.rs/serde/latest/serde/)の`Serialize`、`Serializer`があります。

```rust
// serde::Serialize
pub trait Serialize {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer;
}

// serde::Serializer
pub trait Serializer: Sized {
    /*省略*/
}
```
とうぜんこれもobject safeでないためtrait object にはできません。

# erased_serde

そんな`serde::Serialize`に対してトレイトオブジェクト化できるようにしたのが[erased_serde](https://docs.rs/erased-serde/latest/erased_serde/index.html)です。

ではどうやってobject safetyを回避したのでしょうか。

その方法は単純で、object safeなtraitを別に用意し、そのtrait object(の参照)に対して元のtraitをimplしてやることによって達成してます。

まずobject safetyなmethodを定義します。

```rust 
// erased_serde::Serialize
pub trait Serialize {
    fn erased_serialize(&self, v: &mut dyn Serializer) -> Result<Ok, Error>;
}

// erased_serde::Serializer
pub trait Serializer { /*省略*/ }
```

そしてそれらのtrait objectにたいして元のtraitをimplします。

```rust
//実際にはともに +Send, +Sync, +Send+Syncに対しても定義している 

impl<'a> serde::Serializer for &'a mut dyn erased_serde::Serializer { /*省略*/ }

impl<'erased> serde::Serialize for dyn Serialize + 'erased { /*省略*/ }

//serde::Serialzieをerased_serde::Serialzieでつかえるようにwrapする関数
impl dyn Serializer {
   pub fn erase<S : serde::Serialzie>(serializer: S) -> Serializer<S>
}
```

これによってtraitを少しwrapしてやることによいってtrait objectとして使えるようにしています。

よって似たようにobject safeでないtraitでも少しの工夫でtrait objectにできます。

# 参考文献
object safetyの定義
https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md

asyncなiteratorをboxed dynで使う方法についての英語記事、
これのmacroがあったらいいなという提案をしている。
https://smallcultfollowing.com/babysteps//blog/2021/10/15/dyn-async-traits-part-6/