naomijub / edn-rs

[DEPRECATED]: Crate to parse and emit EDN
https://crates.io/crates/edn-rs
MIT License
81 stars 14 forks source link

DEPRECATION WARNING

Development is currently halted for this project. No new features are under development, but also no breaking changes. If you have a critical issue, we might take a look. You may find Grinkers/clojure-reader as a suitable alternative, it has been built by one of our maintainers @Grinkers.

edn-rs

codecov

A crate to parse and emit EDN (Extensible Data Notation)

Full integration examples:

Usage

Default

Includes features std and sets.

[dependencies]
edn-rs = "0.17.4"

no_std

To use edn-rs without any additional dependencies, disable default features. edn-rs still relies on alloc. In no_std environments, you must supply your own #[global_allocator].

[dependencies]
edn-rs = { version = "0.17.4", default-features = false }

Optional features

Quick reference

Parse an EDN token into a Edn with edn! macro:

use edn_rs::{
    edn, Edn, List
};

fn main() {
    let edn = edn!((sym 1.2 3 false :f nil 3/4));
    let expected = Edn::List(
        List::new(
            vec![
                Edn::Symbol("sym".to_string()),
                Edn::Double(1.2.into()),
                Edn::Int(3),
                Edn::Bool(false),
                Edn::Key(":f".to_string()),
                Edn::Nil,
                Edn::Rational("3/4".to_string())
            ]
        )
    );

    println!("{:?}", edn);
    assert_eq!(edn, expected);
}

Parse an EDN String with Edn::from_str:

use edn_rs::{
    set, map,
    Edn, Map, Vector, Set,
};
use std::str::FromStr;

fn main() -> Result<(), String> {
    let edn_str = "{:a \"2\" :b [true false] :c #{:A {:a :b} nil}}";
    // std::str::FromStr
    let edn: Edn = Edn::from_str(edn_str);

    assert_eq!(
        edn,
        Edn::Map(Map::new(
            map!{
                ":a".to_string() => Edn::Str("2".to_string()),
                ":b".to_string() => Edn::Vector(Vector::new(vec![Edn::Bool(true), Edn::Bool(false)])),
                ":c".to_string() => Edn::Set(Set::new(
                    set!{
                        Edn::Map(Map::new(map!{":a".to_string() => Edn::Key(":b".to_string())})),
                        Edn::Key(":A".to_string()),
                        Edn::Nil}))}
        ))
    );

    assert_eq!(edn[":b"][0], Edn::Bool(true));

    Ok(())
}

To navigate through Edn data you can just use get and get_mut:

use edn_rs::{
    edn,
    Edn, List, Map
};

fn main() {
    let edn = edn!((sym 1.2 3 {false :f nil 3/4}));

    println!("{:?}", edn);
    assert_eq!(edn[1], edn!(1.2));
    assert_eq!(edn[1], Edn::Double(1.2f64.into()));
    assert_eq!(edn[3]["false"], edn!(:f));
    assert_eq!(edn[3]["false"], Edn::Key(":f".to_string()));
}

Serializes Rust Types into EDN with edn-derive::Serialize

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use edn_rs::{
    map, set, hmap, hset
};
use edn_derive::Serialize;

#[derive(Debug, Clone, Serialize)]
struct ExampleEdn {
    btreemap: BTreeMap<String, Vec<String>>,
    btreeset: BTreeSet<i64>,
    hashmap: HashMap<String, Vec<String>>,
    hashset: HashSet<i64>,
    tuples: (i32, bool, char),
    nothing: (),
}

fn main() {
    let edn = ExampleEdn {
        btreemap: map!{"this is a key".to_string() => vec!["with".to_string(), "many".to_string(), "keys".to_string()]},
        btreeset: set!{3i64, 4i64, 5i64},
        hashmap: hmap!{"this is a key".to_string() => vec!["with".to_string(), "many".to_string(), "keys".to_string()]},
        hashset: hset!{3i64},
        tuples: (3i32, true, 'd'),
        nothing: (),
    };

    println!("{}", edn_rs::to_string(edn));
    // { :btreemap {:this-is-a-key [\"with\", \"many\", \"keys\"]}, :btreeset #{3, 4, 5}, :hashmap {:this-is-a-key [\"with\", \"many\", \"keys\"]}, :hashset #{3}, :tuples (3, true, \\d), :nothing nil, }
}

Deserializes Strings into Rust Types:

For now you have to implement the conversion yourself with the Deserialize trait. Soon you'll be able to have that implemented for you via edn-derive crate.


use edn_rs::{Deserialize, Edn, EdnError};

[derive(Debug, PartialEq)]

struct Person { name: String, age: u64, }

impl Deserialize for Person { fn deserialize(edn: &Edn) -> Result<Self, EdnError> { Ok(Self { name: edn_rs::from_edn(&edn[":name"])?, age: edn_rs::from_edn(&edn[":age"])?, }) } }

fn main() -> Result<(), EdnError> { let edn_str = "{:name \"rose\" :age 66}"; let person: Person = edn_rs::from_str(edn_str)?;

assert_eq!(
    person,
    Person {
        name: "rose".to_string(),
        age: 66,
    }
);

println!("{:?}", person);
// Person { name: "rose", age: 66 }

let bad_edn_str = "{:name \"rose\" :age \"some text\"}";
let person: Result<Person, EdnError> = edn_rs::from_str(bad_edn_str);

assert_eq!(
    person,
    Err(EdnError::Deserialize(
        "couldn't convert `some text` into `uint`".to_string()
    ))
);

Ok(())

}


**Deserializes Edn types into Rust Types**:
* Deserialization to `std::collection::*` is currently unsafe.

> For now you have to implement the conversion yourself with the `Deserialize` trait. Soon you'll be able to have that implemented for you via `edn-derive` crate.
 ```rust
use edn_rs::{map, Deserialize, Edn, EdnError, Map};

#[derive(Debug, PartialEq)]
struct Person {
    name: String,
    age: u64,
}

impl Deserialize for Person {
    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
        Ok(Self {
            name: edn_rs::from_edn(&edn[":name"])?,
            age: edn_rs::from_edn(&edn[":age"])?,
        })
    }
}

fn main() -> Result<(), EdnError> {
    let edn = Edn::Map(Map::new(map! {
        ":name".to_string() => Edn::Str("rose".to_string()),
        ":age".to_string() => Edn::UInt(66)
    }));
    let person: Person = edn_rs::from_edn(&edn)?;

    println!("{:?}", person);
    // Person { name: "rose", age: 66 }

    assert_eq!(
        person,
        Person {
            name: "rose".to_string(),
            age: 66,
        }
    );

    let bad_edn = Edn::Map(Map::new(map! {
        ":name".to_string() => Edn::Str("rose".to_string()),
        ":age".to_string() => Edn::Str("some text".to_string())
    }));
    let person: Result<Person, EdnError> = edn_rs::from_edn(&bad_edn);

    assert_eq!(
        person,
        Err(EdnError::Deserialize(
            "couldn't convert `\"some text\"` into `uint`".to_string()
        ))
    );

    Ok(())
}

Emits EDN format from a Json:

fn main() { let json = String::from(r#"{"hello": "world"}"#); let edn = String::from(r#"{:hello "world"}"#);

println!("{:?}", json_to_edn(json.clone()));
assert_eq!(edn, json_to_edn(json));

let complex_json = String::from(r#"{
        "people":
        [
            {
                "name": "eva",
                "age": 22
            },
            {
                "name": "Julia",
                "age": 32.0
            }
        ],
        "country or origin": "Brazil",
        "queerentener": true,
        "brain": null
    }"#);

println!("{:?}", json_to_edn(complex_json.clone()).replace("  ", "").replace("\n", " "));
// "{ :people  [ { :name \"eva\", :age 22 }, { :name \"Julia\", :age 32.0 } ], :country-or-origin \"Brazil\", :queerentener true, :brain nil }"

}


 **Emits a JSON** from type `edn_rs::Edn`.
 * The associated emthod is `to_json(&self)` and it requires feature `json` to be activated. To enable this feature add to your `Cargo.toml`  dependencies the following line `edn-rs = { version = 0.17.4", features = ["json"] }`.

```rust
use std::str::FromStr;
fn complex_json() {
    let edn = "{
        :people-list [
            { :first-name \"eva\", :age 22 },
            { :first-name \"Julia\", :age 32.0 }
        ],
        :country-or-origin \"Brazil\",
        :queerentener true,
        :brain nil }";
    let parsed_edn : edn_rs::Edn = edn_rs::Edn::from_str(edn).unwrap();
    let actual_json = parsed_edn.to_json();
    let expected = String::from(
        "{\"brain\": null,
          \"countryOrOrigin\": \"Brazil\",
          \"peopleList\": [
              {\"age\": 22, \"firstName\": \"eva\"},
              {\"age\": 32.0, \"firstName\": \"Julia\"}
            ],
          \"queerentener\": true}",
    );
    assert_eq!(
        actual_json,
        expected
    );
}

to_string/to_debug

to_debug emits a Debug version of Edn type.

use edn_rs::edn::{Edn, Vector};

let edn = Edn::Vector(Vector::new(vec![Edn::Int(5), Edn::Int(6), Edn::Int(7)]));
let expected = "Vector(Vector([Int(5), Int(6), Int(7)]))";

assert_eq!(edn.to_debug(), expected);

to_string emits a valid edn.

use edn_rs::edn::{Edn, Vector};

let edn = Edn::Vector(Vector::new(vec![Edn::Int(5), Edn::Int(6), Edn::Int(7)]));
let expected = "[5, 6, 7, ]";

assert_eq!(edn.to_string(), expected);

Larger to_string example:

fn complex_ok() -> Result<(), EdnError> {
    use std::str::FromStr;
    let edn_str = "{ :list [{:name \"rose\" :age 66 :cool true}, {:name \"josh\" :age 33 :cool false}, {:name \"eva\" :age 296 :cool true}] }";

    let edn = Edn::from_str(edn_str)?;
    println!("{:?}", edn.to_string());
    // "{:list: [{:age 66, :cool true, :name \"rose\", }, {:age 33, :cool false, :name \"josh\", }, {:age 296, :cool true, :name \"eva\", }, ], }"

    Ok(())
}

Edn-rs Current Features

edn-derive

edn-derive is a proc-macro crate to (De)serialize Edn values, currently it is beta and it can be found at crates.io or at github.

Usage

Just add to your Cargo.toml the following:

[dependencies]
edn-derive = "<version>"
edn-rs = "0.17.4"

Examples

Serialize

use edn_derive::Serialize;

#[derive(Serialize)]
pub struct Person {
    name: String,
    age: u64,
}

fn main() {
    let person = Person {
        name: "joana".to_string(),
        age: 290000,
    };
    assert_eq!(
        edn_rs::to_string(person),
        "{ :name \"joana\", :age 290000, }"
    );
}

Deserialization

use edn_derive::Deserialize;
use edn_rs::EdnError;

// The `Debug` and `PartialEq` are only necessary because of `assert_eq`, you don't need them
#[derive(Deserialize, Debug, PartialEq)]
pub struct Person {
    name: String,
    age: u64,
}

fn main() -> Result<(), EdnError> {
    let edn_person = "{ :name \"joana\", :age 290000, }";

    let person: Person = edn_rs::from_str(edn_person)?;

    assert_eq!(
        person,
        Person {
            name: "joana".to_string(),
            age: 290000,
        }
    );

    Ok(())
}

Current Features