Near Stable no breaking changes expected.
Crate to parse and emit EDN
* This lib does not make effort to conform the EDN received to EDN Spec. The lib that generated this EDN should be responsible for this. For more information on Edn Spec please visit: https://github.com/edn-format/edn.
Current example usage in:
* crate transistor
;
* atm-crux
;
* Rust/Clojure FFI. Deserialize Clojure Edn into Rust Struct;
Cargo.toml
toml
[dependencies]
edn-rs = "0.16.5"
edn-rs
agains Clojure Edn| Method\Lang | Rust --release | Rust --debug | Clojure | |- |- |- |- | | parse string | 77.57µs | 266.479µs | 4.712235 milis | | get-in/navigate (3 blocks) | 4.224µs | 22.861µs | 26.333 µs | | Deserialize to struct | 110.358µs | 357.054µs | 4.712235 milis | | parse with criterium | 11.348µs | - | 23.230µs|
Parse an EDN token into a Edn
with edn!
macro:
```rust
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".tostring()), Edn::Double(1.2.into()), Edn::Int(3), Edn::Bool(false), Edn::Key(":f".tostring()), Edn::Nil, Edn::Rational("3/4".to_string()) ] ) );
println!("{:?}", edn);
assert_eq!(edn, expected);
} ```
Parse an EDN String with Edn::from_str
:
```rust
use edn_rs::{
set, map,
Edn, Map, Vector, Set,
};
use std::str::FromStr;
fn main() -> Result<(), String> { let ednstr = "{:a \"2\" :b [true false] :c #{:A {:a :b} nil}}"; // std::str::FromStr let edn: Edn = Edn::fromstr(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
:
```rust 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 ser_struct!
or use edn-derive::Serialize
```rust
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use ednrs::{
serstruct, map, set, hmap, hset
};
fn main() {
serstruct!{
#[derive(Debug, Clone)]
struct Edn {
btreemap: BTreeMap
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 viaedn-derive
crate. ```rust use edn_rs::{Deserialize, Edn, EdnError};
struct Person { name: String, age: usize, }
impl Deserialize for Person {
fn deserialize(edn: &Edn) -> Result
fn main() -> Result<(), EdnError> { let ednstr = "{:name \"rose\" :age 66}"; let person: Person = ednrs::fromstr(ednstr)?;
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:
For now you have to implement the conversion yourself with the
Deserialize
trait. Soon you'll be able to have that implemented for you viaedn-derive
crate. ```rust use edn_rs::{map, Deserialize, Edn, EdnError, Map};
struct Person { name: String, age: usize, }
impl Deserialize for Person {
fn deserialize(edn: &Edn) -> Result
fn main() -> Result<(), EdnError> { let edn = Edn::Map(Map::new(map! { ":name".tostring() => Edn::Str("rose".tostring()), ":age".tostring() => Edn::UInt(66) })); let person: Person = ednrs::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:
* This function requires feature json
to be activated. To enable this feature add to your Cargo.toml
dependencies the following line edn-rs = { version = 0.16.5", features = ["json"] }
.
```rust use ednrs::jsonto_edn;
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": "otavio",
"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 \"otavio\", :age 22 }, { :name \"Julia\", :age 32.0 } ], :country-or-origin \"Brazil\", :queerentener true, :brain nil }"
} ```
tostring/todebug
to_debug
emits a Debug version of Edn
type.
```rust
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)]))";
asserteq!(edn.todebug(), expected); ```
to_string
emits a valid edn.
```rust
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, ]";
asserteq!(edn.tostring(), expected); ```
Larger to_string
example:
```rust
fn complexok() -> Result<(), EdnError> {
use std::str::FromStr;
let ednstr = "{ :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(())
} ```
async/await
with Edn typeEdn supports futures
by using the feature async
. To enable this feature add to your Cargo.toml
dependencies the following line edn-rs = { version = 0.16.5", features = ["async"] }
and you can use futures as in the following example.
```rust use edn_rs::{edn, Double, Edn, Vector}; use futures::prelude::; use futures::Future; use tokio::prelude::;
async fn foo() -> impl Future
async fn main() { let edn = foo().await.await;
println!("{}", edn.to_string());
assert_eq!(edn, edn!([1 1.5 "hello" :key]));
assert_eq!(edn[1].to_float(), Some(1.5f64));
} ```
The objective of foo
is to show that Edn
can be wrapped with a Future
. If you want to return an Edn
from an async
function just use:
rust
async fn foo() -> Edn {
edn!([1 1.5 "hello" :key])
}
struct
to map EDN info EdnNode
EdnType
Edn::Bool(true).into() -> true
. This was done by to_float
, to_bool
, to_int
, to_vec
.futures::Future
trait to Edn
to_string()
for Edn
.to_debug()
for Edn
.from_str
:
""
"\"string\""
"324352"
, "3442.234"
, "3/4"
:a
sym-bol-s
with a maximum of 200 chars"[1 :2 \"d\"]"
"(1 :2 \"d\")"
"#{1 2 3}"
"{:a 1 :b 2 }"
#inst \"yyyy-mm-ddTHH:MM:ss\"
"{:a \"2\" :b [true false] :c #{:A {:a :b} nil}}"
edn!
:
"[1 2 [:3 \"4\"]]"
"[1 2 #{:3 \"4\"}]"
"(1 2 (:3 \"4\"))"
"'#{1 2 (:3 \"4\")}"
"{:a 2 :b {:3 \"4\"}}"
, "{:a 2 :b [:3 \"4\"]}"
set_iter
edn-derive
edn-derive
is a proc-macro crate to (De)serialize Edn values, currently it is pre-alpha and it can be found at crates.io
or at github
.
Just add to your Cargo.toml
the following:
toml
[dependencies]
edn-derive = "<version>"
edn-rs = "0.16.5"
Serialize ```rust use edn_derive::Serialize;
pub struct Person { name: String, age: usize, }
fn main() { let person = Person { name: "joana".tostring(), age: 290000, }; asserteq!( ednrs::tostring(person), "{ :name \"joana\", :age 290000, }" ); } ```
Deserialization ```rust use ednderive::Deserialize; use ednrs::EdnError;
// The Debug
and PartialEq
are only necessary because of assert_eq
, you don't need them
pub struct Person { name: String, age: usize, }
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(())
} ```
derive Serialize
edn_rs::to_string
derive Deserialize
let val: YourStruct = edn_rs::from_str(&str)