1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rust の serde で複数形式の Serialize/Deserialize を実装するときのコピペ用実装例 + map/map_or の参考おまけ付き

Last updated at Posted at 2022-05-07
// note: derive(Serialize, Deserialize) とかするための `use` は T (Rustで扱う型) にだけ付ければよいです。
// これを使いたい場合は `cargo add serde -F derive` (`cargo install cargo-edit`してある環境)
// Cargo.toml の `[dependencies]` に `serde = { version = "*", features = [ "derive" ] }` しておきます。
#[derive(Serialize, Deserialize)]
struct Neko(String); // またはお好みで複雑にして読み替えて下さい。

/// (A): file や http など 👉  MyInterimStorage  👉 T (Rustで扱う型)
/// (B): file や http など 👈 (MyInterimStorage) 👈 T (Rustで扱う型)
/// のように変換前の中間貯蔵庫を使いたい場合の実装です。このまま使わない場合も、
/// 必要に応じてシリアライズ部分だけ、デシリアライズ部分だけを fn として使うなど
/// お好みでどうぞ。※この実装例の(B)ルートでは content_type の参照をしているだけです。
#[derive(Debug, Clone)] // ← お好みで
pub struct MyInterimStorage
{
 pub content_type: String, // ← Content-Type とか mime や mime-guess で形式判定する用
 pub serialized_data: Vec<u8> // ← file や http などで受け取ったバイナリーを入れる
}

impl<'de> MyInterimStorage // ← こういう中間データ貯蔵庫を使う場合はここで <'de> ライフタイムを入れておく
{
 /// 形式に基づいてデシリアライズします。こっちに <'de> が必要
 pub fn deserialize<T>(&'de self) -> Option<T>
 where
  T: Deserialize<'de> + std::fmt::Debug
 {
  // content_type::APPLICATION_MSGPACK などは const な &str を定義しているだけです。
  // mod content_type { const APPLICATION_MSGPACK: &str = "application/msgpack" }
  // のように。必要に応じて定義するといいです。
  // (mime crateは非constなので必要な分だけさっと定義書けばいいと思います。)
  match self.content_type.as_str()
  {
   // たいていの serde 対応実装はこのパターンで binary を読めます。
   content_type::APPLICATION_MSGPACK => rmp_serde ::from_slice(self.serialized_data.as_slice()).ok(),
   content_type::APPLICATION_TOML    => toml      ::from_slice(self.serialized_data.as_slice()).ok(),
   content_type::APPLICATION_JSON    => serde_json::from_slice(self.serialized_data.as_slice()).ok(),
   // その他、YAMLとかRONとか必要に応じてどうぞ: https://serde.rs/
   _ => None
  }
 }

 /// 形式に基づいてシリアライズします。こちらはライフタイム管理不要です。
 pub fn serialize<T>(&self, from: T) -> Option<Vec<u8>>
 where
  T: Serialize + std::fmt::Debug
 {
  match self.content_type.as_str()
  {
   content_type::APPLICATION_MSGPACK => rmp_serde ::to_vec(&from).ok(),
   content_type::APPLICATION_TOML    => toml      ::to_vec(&from).ok(),
   content_type::APPLICATION_JSON    => serde_json::to_vec(&from).ok(),
   _ => None
  }
 }

 // おまけ実装例 (1): 中身を形式に基づいてデシリアライズ👉Fで変換👉元と同じ形式でシリアライズの組み合わせの実装例 
 pub fn map<T, F>(&'de self, fun: F) -> Option<Vec<u8>>
 where
  T: Deserialize<'de> + Serialize + std::fmt::Debug,
  F: Fn(T) -> Option<T>
 {
  let src = self.deserialize::<T>()?;
  let dst = fun(src);
  let r = self.serialize(dst);
  r
 }

 // おまけ実装例 (2): (1) の途中でデシリアライズに失敗したときにデフォルト値に挿げ替えてシリアライズする版
 pub fn map_or<T, F>(&'de self, fun: F, default: T) -> Option<Vec<u8>>
 where
  T: Deserialize<'de> + Serialize + std::fmt::Debug,
  F: Fn(T) -> Option<T>
 {
  let r = self.deserialize::<T>().and_then(fun).unwrap_or(default);
  self.serialize(r)
 }
}

久しぶりにQiitaへ。フォロー頂いている方への生存 ping を兼ねて🤣

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?