💾

Rustで簡単にstructを保存するtraitを作る

に公開

概要

  • structをserdeを用いてjsonやtomlにシリアライズする
  • シリアライズされた文字列をfsなどでファイルに保存する
  • 保存されたファイルからデシアライズして、読み出す

Code

以下のコードはtoml用。<P: AsRef<Path>>はtrait全体でまとめても良いかも。

Cargo.toml
[dependencies]
serde = {version = "1.0.219", features = ["derive"]}
toml = "0.9.5"
storable.rs
// serdeはシリアライズとデシアライズのため
use serde::{Serialize, de::DeserializeOwned};
// io関連
use std::{
    fs::{self, OpenOptions},
    io::{self, Write},
    path::Path,
};
// tomlをパースするため
use toml::{from_str, to_string_pretty};

#[derive(Debug)]
pub enum Error {
    IoE(io::Error),
    ParTomlE(toml::ser::Error),
    DesTomlE(toml::de::Error),
}

pub trait Storable {
    /// pathは保存先
    /// new_createは新規作成を許可するかどうか。OpenOptionsの.create()にそのまま渡される
    fn save<P: AsRef<Path>>(&self, path: P, new_create: bool) -> Result<(), Error>
    where
        // Selfは`Serialize`と`Deserialize`をderiveなどで付与している必要がある
        Self: Serialize + DeserializeOwned,
    {
        let s = to_string_pretty(self).map_err(Error::ParTomlE)?;
        let mut f = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(new_create)
            .open(path)
            .map_err(Error::IoE)?;
        f.write_all(s.as_bytes()).map_err(Error::IoE)
    }
    // 戻り値はSelf
    fn load<P: AsRef<Path>>(path: P) -> Result<Self, Error>
    where
        Self: Serialize + DeserializeOwned,
    {
        let file_content = fs::read_to_string(path).map_err(Error::IoE)?;
        from_str::<Self>(&file_content).map_err(Error::DesTomlE)
    }
}

Example

ex.rust
#[derive(Debug, Serialize, Deserialize)]
struct Person {
    name: String,
    age: u32,
    os: Os,
}

impl Storable for Person {}

#[derive(Debug, Serialize, Deserialize)]
enum Os {
    Mac,
    Linux,
    Windows,
}

fn main() {
    let mike = Person {
        name: "Mike".to_string(),
        age: 20,
        os: Os::Linux,
    };
    mike.save("./users/mike.toml", true).unwrap();

    let loaded_mike = Person::load("./users/mike.toml").unwrap();

    println!("{loaded_mike:?}");
}

Exampleのコードはunwrapしまくりなので注意。jsonの場合はserde_jsonを使うとほぼ同じ手順で行ける。

GitHubで編集を提案

Discussion