76 releases
0.18.0 | Jun 15, 2024 |
---|---|
0.17.5 | Dec 16, 2023 |
0.17.4 | May 28, 2022 |
0.17.1 | Feb 17, 2022 |
0.1.0 | Nov 27, 2019 |
#11 in #edn
263 downloads per month
Used in 5 crates
125KB
2.5K
SLoC
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
A crate to parse and emit EDN (Extensible Data Notation)
- MSRV (minimal supported rust version) is stable minus 2 versions. Once stable (1.0.0), the plan is to indefinitely maintain the MSRV.
- Current library maintainer is Kevin Nakamura (@Grinkers)
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
std
: Implements (de)serialization for Hashmap and HashSet; Also some floating point functionality.sets
: Implements (de)serialization for EDN sets. Depends onordered-float
.json
: Implements json->edn and edn->json conversions. Depends onregex
.
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 viaedn-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 viaedn-derive
crate.
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:
- This function requires feature
json
to be activated. To enable this feature add to yourCargo.toml
dependencies the following lineedn-rs = { version = 0.17.4", features = ["json"] }
.
use edn_rs::json_to_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": "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 featurejson
to be activated. To enable this feature add to yourCargo.toml
dependencies the following lineedn-rs = { version = 0.17.4", features = ["json"] }
.
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
- Define
struct
to map EDN infoEdnNode
- Define EDN types,
EdnType
- Edn Type into primitive:
Edn::Bool(true).into() -> true
. This was done byto_float
,to_bool
,to_int
,to_vec
. - implement
futures::Future
trait toEdn
-
to_string()
forEdn
. -
to_debug()
forEdn
.
- Edn Type into primitive:
- Parse EDN data
from_str
:- nil
""
- String
"\"string\""
- Numbers
"324352"
,"3442.234"
,"3/4"
- Keywords
:a
- Symbol
sym-bol-s
- Vector
"[1 :2 \"d\"]"
- List
"(1 :2 \"d\")"
- Set
"#{1 2 3}"
- Map
"{:a 1 :b 2 }"
- Tag
#inst \"yyyy-mm-ddTHH:MM:ss\"
,#uuid \"<some-uuid>\"
as string data (no custom reader support) - Nested structures
"{:a \"2\" :b [true false] :c #{:A {:a :b} nil}}"
- nil
- Simple data structures in one another
edn!
:- Vec in Vec
"[1 2 [:3 \"4\"]]"
- Set in Vec
"[1 2 #{:3 \"4\"}]"
- List in List
"(1 2 (:3 \"4\"))"
- List in Set
"'#{1 2 (:3 \"4\")}"
- Maps in general
"{:a 2 :b {:3 \"4\"}}"
,"{:a 2 :b [:3 \"4\"]}"
- Vec in Vec
- Multiple simple data structures in one another (Map and Set in a vector)
- Multi deepen data structures (Map in a Set in a List in a Vec in a Vec)
- Navigate through Edn Data
- Navigate through Sets. DOne by
set_iter
- Navigate through Sets. DOne by
- Json to Edn
- Json String to EDN String
- macro to process Structs and Enums to EDN
- trait Deserialize EDN to Struct
- trait Serialize struct to EDN
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
-
derive Serialize
-
edn_rs::to_string
-
derive Deserialize
-
let val: YourStruct = edn_rs::from_str(&str)
Dependencies
~0–560KB