Rust serdeを使ってJSONの読み書きテスト

# 概要
Rust を使ってJsonファイルの読み書きについてのメモ。
とりあえず `serde` が有力らしいので使っています。


## 更新履歴
| 日付 | 内容 |
|:----|:-----|
|2022/12/21| 初版 |

## 参考
以下の記事を参考にいたしました、ありがとうございます。
[Crate serde_json](https://docs.rs/serde_json/latest/serde_json/)
[Serdeのシリアライズ/デシリアライズを試してみる](https://dev.classmethod.jp/articles/rust-serde-getting-started/)
[RustでstructをJSONにシリアライズしてファイルに保存する](https://swiswiswift.com/2021-12-02/)


## 環境
Rust 1.65.0 (897e37553 2022-11-02)
serde 1.0
serde_json 1.0


# 実装


## 準備
```toml:Cargo.toml
[package]
name = "test01"
version = "0.1.0"
edition = "2021"

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


## 読み込みテスト
以下、読み込みテスト用のJSONファイル
`String`, `i32`, `Vec<u32>`, `Struct` からなるテストデータです。

```json:test_input.json
[
  {
    "Name": "Kiwi",
    "Id": 3,
    "ItemIdList": [
      2000,
      2001
    ],
    "RotData": {
      "Pitch": 0.0,
      "Roll": 0.0,
      "Yaw": 0.0
    }
  },
  {
    "Name": "Orange",
    "Id": 4,
    "ItemIdList": [
      2002,
      2003
    ],
    "RotData": {
      "Pitch": 1.0,
      "Roll": 50.2,
      "Yaw": 66.5
    }
  }
]

```

読み込み用コード。
JSON構造に対応した構造体を用意、スネークケースではないため警告が出てしまうのを抑止するためにアトリビュート `#[allow(non_snake_case)]` を付与。

```rust:main.rs
use serde::{Serialize, Deserialize};
use std::fs;
use std::io::prelude::*;

// テストパラメータ構造体1
#[derive(Serialize, Deserialize, Debug)]
#[allow(non_snake_case)]
struct Rotator{
    Pitch:f32,
    Roll:f32,
    Yaw:f32,
}

// テストパラメータ構造体2
#[derive(Serialize, Deserialize, Debug)]
#[allow(non_snake_case)]
struct CharaParam {
    Name: String,
    Id: i32,
    ItemIdList: Vec<u32>,
    RotData:Rotator,
}

//--------------------------------
// メイン処理
fn main() {
    // デシリアライズ
    let input_fn = fs::read_to_string("test_input.json")
        .expect("JSON Read Failed.");
    let deserialized: Vec<CharaParam> = serde_json::from_str(&input_fn).unwrap();

    // データ表示
    for data in &deserialized {
        println!("{:?}", data);
    }
}
```

### 結果
```text:output
CharaParam { Name: "Kiwi", Id: 3, ItemIdList: [2000, 2001], RotData: Rotator { Pitch: 0.0, Roll: 0.0, Yaw: 0.0 } }
CharaParam { Name: "Orange", Id: 4, ItemIdList: [2002, 2003], RotData: Rotator { Pitch: 1.0, Roll: 50.2, Yaw: 66.5 } }
```


## 書き込みテスト
書き込み用コード。
JSONに対応した構造体を用意し、データもソース直に用意。

```rust:main.rs
use serde::{Serialize, Deserialize};
use std::fs::File;
use std::io::prelude::*;

// テストパラメータ構造体1
#[derive(Serialize, Deserialize, Debug)]
#[allow(non_snake_case)]
struct Rotator{
    Pitch:f32,
    Roll:f32,
    Yaw:f32,
}

// テストパラメータ構造体2
#[derive(Serialize, Deserialize, Debug)]
#[allow(non_snake_case)]
struct CharaParam {
    Name: String,
    Id: i32,
    ItemIdList: Vec<u32>,
    RotData:Rotator,
}

//--------------------------------
// メイン処理
fn main() {
    // シリアライズ

    // データ作成
    let chara00 = CharaParam{Name:String::from("Apple"), Id:0x01, ItemIdList:vec![1000, 1001], RotData:Rotator{Pitch:0.0, Roll:0.0, Yaw:32.0} };
    let chara01 = CharaParam{Name:String::from("Banana"), Id:0x02, ItemIdList:vec![1002, 1003], RotData:Rotator{Pitch:0.0, Roll:-70.0, Yaw:66.0} };

    let mut param_list:Vec<CharaParam> = Vec::new();
    param_list.push(chara00);
    param_list.push(chara01);

    // ファイル出力
    let output_fn = String::from("test_output.json");
    let result = output_json( &output_fn,param_list);
    match result {
        Ok(..) => { println!("Json Output Finished. [{}]", output_fn) }
        Err(err) => { println!("Error! : {}", err) }
    }
}

// jsonファイル書き出し
fn output_json(output_fn: &str, charaparam_list: Vec<CharaParam>) -> std::io::Result<()> {
    // シリアライズ
    let serialized: String = serde_json::to_string(&charaparam_list).unwrap();

    // ファイル出力
    let mut file = File::create(output_fn)?;
    file.write_all(serialized.as_bytes())?;
    Ok(())
}
```

### 結果
整形できなかったため、別ツールで別途整形。

```json:test_output.json
[
  {
    "Name": "Apple",
    "Id": 1,
    "ItemIdList": [
      1000,
      1001
    ],
    "RotData": {
      "Pitch": 0,
      "Roll": 0,
      "Yaw": 32
    }
  },
  {
    "Name": "Banana",
    "Id": 2,
    "ItemIdList": [
      1002,
      1003
    ],
    "RotData": {
      "Pitch": 0,
      "Roll": -70,
      "Yaw": 66
    }
  }
]

```



# まとめ
Rust勉強中、とりあえずJSONの読み書きができた。
ただ JSONの整形ができなかったため別途jq (https://stedolan.github.io/jq/) を使ったので多少の消化不良感。