#edn #serialization #serde

edn-format

Rust的EDN(可扩展数据表示)实现

11个稳定版本

3.3.0 2023年10月3日
3.2.3 2022年2月27日
3.2.2 2021年12月30日
2.0.0 2021年12月28日
1.1.1 2021年12月27日

#1278 in 解析器实现

43 每月下载量
用于 flex_process

MIT 许可证

105KB
2.5K SLoC

Run Tests codecov

edn-format

此crate为Rust提供了EDN格式的实现。

目的是提供比现有的ednedn-rscrate更完整的API。

[dependencies]
edn-format = "3.3.0"

示例用法

往返数据

let data = "{:person/name    \"bob\"\
             :person/age      35\
             :person/children #{\"sally\" \"suzie\" \"jen\"}}";
let parsed = parse_str(data).expect("Should be valid");

println!("{:?}", parsed);
// Map({Keyword(Keyword { namespace: Some("person"), name: "age" }): Integer(35), Keyword(Keyword { namespace: Some("person"), name: "name" }): String("bob"), Keyword(Keyword { namespace: Some("person"), name: "children" }): Set({String("jen"), String("sally"), String("suzie")})})

println!("{}", emit_str(&parsed));
// {:person/age 35 :person/name "bob" :person/children #{"jen" "sally" "suzie"}}

从用户定义的结构体进行往返

您可能会注意到,仅使用此库中的功能来编写序列化和反序列化您自己的数据结构的代码可能会非常冗长。

EDN的语义比JSON丰富得多,提供类似serde支持是我故意选择不去解决的问题。

这既有优点也有缺点,但我选择专注于优点,即您至少可以明确控制序列化结构的格式。

#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
    hobbies: Vec<String>,
}

impl Into<Value> for Person {
    fn into(self) -> Value {
        Value::TaggedElement(
            Symbol::from_namespace_and_name("my.project", "person"),
            Box::new(Value::Map(BTreeMap::from([
                (
                    Value::from(Keyword::from_name("name")),
                    Value::from(self.name),
                ),
                (
                    Value::from(Keyword::from_name("age")),
                    Value::from(self.age as i64),
                ),
                (
                    Value::from(Keyword::from_name("hobbies")),
                    Value::Vector(
                        self.hobbies
                            .into_iter()
                            .map(|hobby| Value::from(hobby))
                            .collect(),
                    ),
                ),
            ]))),
        )
    }
}

impl TryFrom<Value> for Person {
    type Error = ();

    fn try_from(value: Value) -> Result<Self, Self::Error> {
        match value {
            Value::TaggedElement(tag, element) => {
                if tag == Symbol::from_namespace_and_name("my.project", "person") {
                    match *element {
                        Value::Map(map) => {
                            if let (
                                Some(Value::String(name)),
                                Some(Value::Integer(age)),
                                Some(Value::Vector(hobbies)),
                            ) = (
                                map.get(&Value::from(Keyword::from_name("name"))),
                                map.get(&Value::from(Keyword::from_name("age"))),
                                map.get(&Value::from(Keyword::from_name("hobbies"))),
                            ) {
                                let mut hobby_strings = vec![];
                                for hobby in hobbies {
                                    if let Value::String(hobby) = hobby {
                                        hobby_strings.push(hobby.clone())
                                    }
                                    else {
                                        return Err(())
                                    }
                                }
                                Ok(Person {
                                    name: name.clone(),
                                    age: *age as u32,
                                    hobbies: hobby_strings
                                })
                            } else {
                                Err(())
                            }
                        }
                        _ => Err(()),
                    }
                } else {
                    Err(())
                }
            }
            // I'm sure this error handling strategy isn't going
            // to win many awards
            _ => Err(()),
        }
    }
}


fn example() {
    let bob = Person {
        name: "bob".to_string(),
        age: 23,
        hobbies: vec!["card games".to_string(), "motorcycles".to_string()],
    };

    let serialized = emit_str(&bob.into());
    println!("{}", serialized);
    // #my.project/person {:age 23 :name "bob" :hobbies ["card games" "motorcycles"]}
    let deserialized = parse_str(&serialized).map(|value| Person::try_from(value));
    println!("{:?}", deserialized)
    // Ok(Ok(Person { name: "bob", age: 23, hobbies: ["card games", "motorcycles"] }))
}

解析数据迭代器

use edn_format::{Parser, ParserOptions};

let parser = Parser::from_iter("123 456 [] [[]]".chars(), ParserOptions::default());
for element in parser {
    println!("{}", element.expect("expected valid element"));
}

// 123
// 456
// []
// [[]]

依赖关系

~2.7–3.5MB
~70K SLoC