Rust で JSONを読み書きする方法がさっぱり分からん☆（＾～＾）萎えた☆（＾～＾）

## 2020-03-01(Sun) 書き直し

次のような JSONファイル を読み込みたいとしよう。

linear-regression-wars.json:  

```json
{
    "fightingNations": [
        {
            "name": "Kifuwara-kingdom-1",
            "win": 1230,
            "draw": 0,
            "lose": 770,
            "tanks": {
                "tako2000": {
                    "number": 50,
                    "magazine": "grape5x3-hole3"
                },
                "tako3000": {
                    "number": 200,
                    "magazine": "grape2x4-hole1"
                },
                "tako5000": {
                    "number": 20,
                    "magazine": "grape5x3-hole3"
                }
            }
        },
        {
            "name": "Oton-kingdom-1",
            "win": 770,
            "draw": 0,
            "lose": 1230,
            "tanks": {
                "tako2000": {
                    "number": 50,
                    "magazine": "grape5x3-hole3"
                },
                "tako3000": {
                    "number": 200,
                    "magazine": "grape2x4-hole1"
                },
                "tako5000": {
                    "number": 20,
                    "magazine": "grape5x3-hole3"
                }
            }
        }
    ]
}
```

`Cargo.toml` には例えば次のように書いてくれだぜ。  

```toml
[dependencies]
serde = { version = "^1.0.101", features = ["derive"] }
serde_json = "^1.0.41"
```

`main.rs` は次のように書いてくれだぜ。  

```rust
//!
//! [[Rust] Serdeのシリアライズ/デシリアライズを試してみる](https://dev.classmethod.jp/server-side/language/rust-serde-getting-started/)
//! [Rust】serde_jsonの使い方](https://www.amusement-creators.info/post/articles/advent_calendar/2019/02_0/)
//! [Serialize fields as camelCase](https://serde.rs/attr-rename.html)
//!
extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

#[serde(rename_all = "camelCase")]
#[derive(Deserialize, Debug)]
struct LinearRegressionWars {
    fighting_nations: Vec<FightingNation>,
}

#[derive(Deserialize, Debug)]
struct FightingNation {
    name: String,
    win: u32,
    draw: u32,
    lose: u32,
    tanks: HashMap<String, Tank>,
}

#[derive(Deserialize, Debug)]
struct Tank {
    number: u16,
    magazine: String,
}

fn main() {
    // Open file.
    let mut file = match File::open("./linear-regression-wars.json") {
        Ok(n) => n,
        Err(err) => panic!("File open error. {:?}", err),
    };

    // Read file.
    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(n) => n,
        Err(err) => panic!("File open error. {:?}", err),
    };

    // Desirialize.
    let linear_regression_wars = match serde_json::from_str::<LinearRegressionWars>(&contents) {
        Ok(n) => n,
        Err(err) => panic!("File open error. {:?}", err),
    };

    for fighting_nation in linear_regression_wars.fighting_nations {
        println!("name={}", fighting_nation.name);
        println!(
            "    tank number={}",
            fighting_nation.tank["tako2000"].number
        );
    }

    println!("Info    | Finished.");
}
```

Output:  

```Plain
name=Kifuwara-kingdom-1
    tank number=50
name=Oton-kingdom-1
    tank number=50
Info    | Finished.
```

とりあえず　こんな感じ。  

## ここから下は古い記事

新しい方法も追いかけてないし、古い方法でも真似する。

```toml:Cargo.toml
[dependencies]
serde = "1.0"
serde_json = "1.0"
```

とりあえず　シリアライズ、デシリアライズの略という `serde` クレートを使う。
たまには

```Shell
cargo update
```

でもしろだぜ。
とりあえず　読み書きしたい JSON を用意しろだぜ☆
わたしは　コンピューター囲碁で使ったことがある JSON を用意する。

```json:config.json
{
    "comment": "AI竜星戦2018用設定ファイル",
    "boardSize": 19,
    "boardInit": [
        "+++++++++++++++++++",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+                 +",
        "+++++++++++++++++++"
    ],
    "sente": "black",
    "rule": "jungo",
    "komiJungo": 6.5,
	"outFile": "C:/MuzudhoDrive/projects_cpp/cgfgoban109_for_kifuwarabe2018_ローカルテスト環境/out.txt",
	"inFile": "C:/MuzudhoDrive/projects_cpp/cgfgoban109_for_kifuwarabe2018_ローカルテスト環境/in.txt"
}
```

これを読み込んで　オブジェクトに一発で入れたいわけだぜ。

```rust:config_file.rs
/// 設定ファイル

/// 参考: https://github.com/serde-rs/json |シリアライズ、デシリアライズ。
extern crate serde_json;
use serde_json::Value;

use std::fs::File;
use std::io::Read;

pub struct Config {
    /// コメント。
    pub comment: String,

    /// 何路盤。
    pub board_size: usize,

    /// 大会用 out.txt 局面ファイルへのパス。
    pub out_path: String,

    /// 大会用 in.txt 局面ファイルへのパス。
    pub in_path: String,
}
impl Config {
    pub fn load(path:&str) -> Config {

        let mut file = match File::open(path) {
            Ok(n) => n,
            Err(err) => panic!("File open error. {:?}", err),
        };

        let mut contents = String::new();
        match file.read_to_string(&mut contents) {
            Ok(n) => n,
            Err(err) => panic!("File open error. {:?}", err),
        };

        // https://docs.serde.rs/serde_json/value/enum.Value.html
        let document: Value = match serde_json::from_str(&contents) {
            Ok(n) => n,
            Err(err) => panic!("File open error. {:?}", err),
        };

        Config {
            comment: match document["comment"].as_str() {
                Some(n) => n.to_string(),
                None => "".to_string(),
            },

            board_size: match document["boardSize"].as_i64() {
                Some(n) => n as usize, // FIXME 変換方法が分からん☆（＾～＾）as使う☆（＾～＾）
                None => 19usize,
            },

            out_path: match document["outFile"].as_str() {
                Some(n) => n.to_string(),
                None => "".to_string(),
            },

            in_path: match document["inFile"].as_str() {
                Some(n) => n.to_string(),
                None => "".to_string(),
            },
        }
    }
}
```

よく分からんので　こんな感じに書いている。
こんなんでいいのか、さっぱり分からん。