chikuchikugonzalezの雑記帳

趣味とか日記とかメモとか(∩゚д゚)

Rustでserde_codegenを使わずにシリアライズしたかった

RustでJSON/YAMLとかにシリアライズしたい場合、たぶん今なら serde を使えばいいんじゃないかと思ってるんだけど、
serde-rs.github.io

ちょっと不便だなーって思うところがあって。それは

  • serde_codegen だとビルドスクリプトに書くことになるので、複数バイナリとか cargo test とかに対応しきれない
  • かといってマクロを使うと Nightly ビルドじゃないと動かない

といったところ。なので、ふと

serde_codegenが生成しているのと同じことするの書けばいいんじゃね?

などと考えたのが失敗だった _("_´ω`)_

シリアライズできたコード

一応シリアライズのほうはできた。

extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

#[derive(Debug)]
struct Hello {
    foo: String,
    bar: i32,
    baz: Vec<i32>,
}

struct HelloVisitor<'a> {
    state: usize,
    value: &'a Hello,
}

impl<'a> serde::ser::MapVisitor for HelloVisitor<'a> {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error> where S: serde::Serializer {
        match self.state {
            0 => {
                self.state += 1;
                return Ok(Some(try!(serializer.serialize_struct_elt("foo", &self.value.foo))));
            }
            1 => {
                self.state += 1;
                return Ok(Some(try!(serializer.serialize_struct_elt("bar", &self.value.bar))));
            }
            2 => {
                self.state += 1;
                return Ok(Some(try!(serializer.serialize_struct_elt("baz", &self.value.baz))));
            }
            _ => {
                return Ok(None);
            }
        }
    }

    fn len(&self) -> Option<usize> {
        return Some(3);
    }
}

impl serde::Serialize for Hello {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer {
        return serializer.serialize_struct("hello", HelloVisitor{
            state: 0,
            value: self,
        });
    }
}

//impl serde::Deserialize for Hello {
//    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
//    }
//}

fn main() {
    let hello1 = Hello{
        foo: "フッカツダー!!(゚∀゚ )三 三( ゚∀゚)フッカツダー!!".to_string(),
        bar: 10,
        baz: vec![7, 8, 10],
    };

    // Encode
    let json = serde_json::to_string(&hello1).unwrap();
    let yaml = serde_yaml::to_string(&hello1).unwrap();

    println!("---- JSON ----\n{}\n", json);
    println!("---- YAML ----\n{}\n", yaml);

    //// Decode
    //let hello2j: Hello = serde_json::from_str(&json).unwrap();
    //let hello2y: Hello = serde_yaml::from_str(&yaml).unwrap();
    //println!("---- JSON ----\n{:?}\n", hello2j);
    //println!("---- YAML ----\n{:?}\n", hello2y);
}

で、上記コード中のデシリアライズのほうが謎すぎて断念した(´;ω;`)
生成されたコードを見てもどうやって実装されてるのかがよくわからん有様であった

もっとこう、Goのencoding/jsonみたいにできねぇかなぁ…