serdeで値だけのstructをシリアライズしたい。なぜならTwitterAPIv2のレスポンスがそうだから。

# 追記(2022/03/16)
勉強会で発表したこの資料ですが、もっとうまいやり方を教わりました。正解のプログラムは以下の通りです。以前の記事もシリアライズを自前でやる時に役に立ちそうなので残しておきます。

```rust:main.rs
use anyhow::{Context, Result};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct UserID(String);
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct IntVal(i64);
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct AryVal(Vec<f64>);

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
struct User {
    id1: UserID,
    id2: UserID,
    name: String,
    val1: IntVal,
    val2: IntVal,
    ary: AryVal,
}

fn main() -> Result<()> {
    let string = r#"{
        "id1": "12345",
        "id2": "67890",
        "name": "aaa",
        "val1": 123,
        "val2": 456,
        "ary": [1.1, 2.2, 3.3]
    }"#;

    let user: User = serde_json::from_str(&string).context("fail deserialize")?;
    println!("{:?}", user);
    println!("{}", serde_json::to_string(&user).context("fail serialize")?);
    Ok(())
}
```

# 目的
TwitterAPIv2の[openapi.json](https://api.twitter.com/2/openapi.json)からレスポンスの型を作ろうと思います。
例えばUserオブジェクトにはid: UserIDというプロパティがあり、UserIDはStringという型であることがわかります。また同様にUserNameもStringです。これを単純にstructであらわすと以下のようになります。

```rust
#[Serilize, Deserialize]
pub struct UserID {
    inner: String
}

#[Serilize, Deserialize]
pub struct UserName {
    inner: String
}

#[Serilize, Deserialize]
pub struct User {
    id: UserID,
    name: String,
    username: UserName
}
```
[GET /2/users/me](https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me)レスポンスは以下のようになります。
```json
{
  "data": {
    "id": "2244994945",
    "name": "TwitterDev",
    "username": "Twitter Dev"
  }
}
```
これは上記structでは戻せないです。期待しているJSONは以下のようになります
```json
{
  "data": {
    "id": UserID: {inner: "2244994945"},
    "name": "TwitterDev",
    "username": UserName: {inner: "Twitter Dev"}
  }
}
```

まっさきに`#[serde(flatten)]`を考えましたが、これだとキーがidではなくinnerを期待してしまいうまくいきません。innerをidにしたところで`id1: UserID, id2 :UserID`のような違うキーに対応できません。

ここでは`#[serde(with = "module")]`を使って自前でシリアライザーを書いてみます。ざっとTwitterAPIのopenapi.jsonを見たところstring, integer, array(number)だけサポートすればよさそうです。

# プログラム

```rust:Cargo.toml
[package]
name = "playground"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.55"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
```

```rust:main.rs
use anyhow::{Context, Result};
use serde::{Serialize, Deserialize};

mod ary_val;
mod int_val;
mod user_id;

use crate::user_id::UserID;
use crate::int_val::IntVal;
use crate::ary_val::AryVal;

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
struct User {
    #[serde(with = "user_id")]
    id1: UserID,
    #[serde(with = "user_id")]
    id2: UserID,
    name: String,
    #[serde(with = "int_val")]
    val1: IntVal,
    #[serde(with = "int_val")]
    val2: IntVal,
    #[serde(with = "ary_val")]
    ary: AryVal,
}

fn main() -> Result<()> {
    let string = r#"{
        "id1": "12345",
        "id2": "67890",
        "name": "aaa",
        "val1": 123,
        "val2": 456,
        "ary": [1.1, 2.2, 3.3]
    }"#;

    let user: User = serde_json::from_str(&string).context("fail deserialize")?;
    println!("{:?}", user);
    println!("{}", serde_json::to_string(&user).context("fail serialize")?);
    Ok(())
}
```

```rust:user_id.rs
use serde::{Deserialize, Serializer, Deserializer};

#[derive(Debug, Clone, Default)]
pub struct UserID {
    inner: String
}

pub fn serialize<S>(value: &UserID, s: S) -> Result<S::Ok, S::Error> where S: Serializer {
    s.serialize_str(&format!("{}", value.inner))
}

pub fn deserialize<'de, D>(d: D) -> Result<UserID, D::Error> where D: Deserializer<'de> {
    let s = String::deserialize(d)?;
    Ok(UserID{inner: s})
}
```

```rust:int_val.rs
use std::num::IntErrorKind;

use serde::{Deserialize, Serializer, Deserializer};

#[derive(Debug, Clone, Default)]
pub struct IntVal {
    inner: u64
}

pub fn serialize<S>(value: &IntVal, s: S) -> Result<S::Ok, S::Error> where S: Serializer {
    s.serialize_str(&format!("{}", value.inner))
}

pub fn deserialize<'de, D>(d: D) -> Result<IntVal, D::Error> where D: Deserializer<'de> {
    let s = u64::deserialize(d)?;
    Ok(IntVal{inner: s})
}
```

```rust:ary_val.rs
use serde::{Serializer, Deserializer, de::{Visitor, SeqAccess}};

#[derive(Debug, Clone, Default)]
pub struct AryVal {
    inner: Vec<f64>
}

struct AryValDeserializer;

// https://stackoverflow.com/questions/62610076/how-to-deserialize-a-sequence-into-a-custom-type-with-serdes-seqdeserializer
impl<'de> Visitor<'de> for AryValDeserializer {
    type Value = Vec<f64>;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("AryValDeserializer u64 sequence.")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        let mut new_obj = vec![];
         while let Some(key) = seq.next_element()? {
            new_obj.push(key);
        }

        Ok(new_obj)
    }
}

pub fn serialize<S>(value: &AryVal, s: S) -> Result<S::Ok, S::Error> where S: Serializer {
    let dst: Vec<String> = value.inner.iter().map(|x| x.to_string()).collect();
    s.serialize_str(&format!("[{}]", dst.join(",")))
}

pub fn deserialize<'de, D>(d: D) -> Result<AryVal, D::Error> where D: Deserializer<'de> {
    let res = d.deserialize_seq(AryValDeserializer)?;

    Ok(AryVal{inner: res})
}
```

```text:結果
User { 
id1: UserID { inner: "12345" }, 
id2: UserID { inner: "67890" }, 
name: "aaa", 
val1: IntVal { inner: 123 }, 
val2: IntVal { inner: 456 }, 
ary: AryVal { inner: [1.1, 2.2, 3.3] } }

{"id1":"12345","id2":"67890","name":"aaa","val1":"123","val2":"456","ary":"[1.1,2.2,3.3]"}
```

# まとめ
最後のary_val.rsはStack Overflowの[How to deserialize a sequence into a custom type with Serde's SeqDeserializer?](https://stackoverflow.com/questions/62610076/how-to-deserialize-a-sequence-into-a-custom-type-with-serdes-seqdeserializer)という記事を参考にしました。

TwitterAPIv2のレスポンスは他にもオブジェクト型が参照していたり、内部で持っていたりと色々複雑ですが、今回の記事の部分が一番やっかいだったので70%くらいはクリアーしたように気になっています。