Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Double is now f64, leveraging rust's IEEE-754 + optional feature "sets" #114

Merged
merged 3 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
run: cargo test --example edn_to_json --features "json"
- name: example_async
run: cargo run --example async --features "async"
- name: example_no_sets
run: cargo run --example struct_from_str --no-default-features

fmt:
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ edition = "2018"

[features]
async = ["futures"]
default = ["sets"]
json = ["regex"]
sets = ["ordered-float"]

[dependencies]
regex = { version = "1", optional = true }
futures = { version = "0.3.5", optional = true }
ordered-float = { version = "4.1", default-features = false, optional = true }

[dev-dependencies]
tokio = { version = "1.33", features = ["full"] }
Expand Down
55 changes: 32 additions & 23 deletions src/deserialize/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use crate::edn::{Edn, Error};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::collections::{BTreeMap, HashMap};
#[cfg(feature = "sets")]
use std::collections::{BTreeSet, HashSet};
use std::convert::TryFrom;
use std::str::FromStr;

pub mod parse;

#[cfg(feature = "sets")]
use ordered_float::OrderedFloat;

/// public trait to be used to `Deserialize` structs.
///
/// # Errors
Expand Down Expand Up @@ -71,25 +76,16 @@ impl Deserialize for () {
}
}

macro_rules! impl_deserialize_float {
( $( $name:ty ),+ ) => {
$(
impl Deserialize for $name
{
fn deserialize(edn: &Edn) -> Result<Self, Error> {
edn
.to_float()
.ok_or_else(|| build_deserialize_error(&edn, "float"))
.map(|u| u as $name)
}
}
)+
};
#[cfg(feature = "sets")]
impl Deserialize for OrderedFloat<f64> {
fn deserialize(edn: &Edn) -> Result<Self, Error> {
edn.to_float()
.ok_or_else(|| build_deserialize_error(edn, "edn_rs::Double"))
.map(std::convert::Into::into)
}
}

impl_deserialize_float!(f32, f64);

impl Deserialize for crate::Double {
impl Deserialize for f64 {
fn deserialize(edn: &Edn) -> Result<Self, Error> {
edn.to_float()
.ok_or_else(|| build_deserialize_error(edn, "edn_rs::Double"))
Expand Down Expand Up @@ -176,6 +172,7 @@ where
.ok_or_else(|| Error::Iter(format!("Could not create iter from {edn:?}")))?
.map(|e| Deserialize::deserialize(e))
.collect::<Result<Self, Error>>()?),
#[cfg(feature = "sets")]
Edn::Set(_) => Ok(edn
.iter_some()
.ok_or_else(|| Error::Iter(format!("Could not create iter from {edn:?}")))?
Expand Down Expand Up @@ -275,6 +272,7 @@ where
}
}

#[cfg(feature = "sets")]
impl<T, H> Deserialize for HashSet<T, H>
where
T: std::cmp::Eq + std::hash::Hash + Deserialize,
Expand All @@ -299,6 +297,7 @@ where
}
}

#[cfg(feature = "sets")]
impl<T> Deserialize for BTreeSet<T>
where
T: std::cmp::Eq + std::hash::Hash + std::cmp::Ord + Deserialize,
Expand Down Expand Up @@ -448,7 +447,9 @@ pub fn from_edn<T: Deserialize>(edn: &Edn) -> Result<T, Error> {
#[cfg(test)]
mod test {
use super::*;
use crate::edn::{List, Map, Set, Vector};
#[cfg(feature = "sets")]
use crate::edn::Set;
use crate::edn::{List, Map, Vector};
use crate::{hmap, hset, map, set};

#[test]
Expand All @@ -460,6 +461,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn deser_btreeset_with_error() {
let edn = "#{\"a\", 5, \"b\"}";
let err: Result<BTreeSet<u64>, Error> = from_str(edn);
Expand Down Expand Up @@ -506,6 +508,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn from_str_list_with_set() {
let edn = "(1 -10 \"2\" 3.3 :b #{true \\c})";

Expand Down Expand Up @@ -536,6 +539,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn from_str_complex_map() {
let edn = "{:a \"2\" :b [true false] :c #{:A {:a :b} nil}}";

Expand Down Expand Up @@ -641,6 +645,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn test_more_sym() {
let edn: Edn = Edn::from_str("(a \\b \"c\" 5 #{hello world})").unwrap();
let expected = Edn::List(List::new(vec![
Expand Down Expand Up @@ -730,6 +735,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn deser_btreeset() {
let set = Edn::Set(Set::new(set! {
Edn::UInt(4),
Expand All @@ -745,19 +751,22 @@ mod test {
assert_eq!(deser_set, expected);
}

#[cfg(feature = "sets")]
#[test]
fn deser_hashset() {
use ordered_float::OrderedFloat;

let set = Edn::Set(Set::new(set! {
Edn::Double(4.6.into()),
Edn::Double(5.6.into()),
Edn::Double(6.6.into())
}));
let expected = hset! {
crate::Double::from(4.6),
crate::Double::from(5.6),
crate::Double::from(6.6),
OrderedFloat(4.6f64),
OrderedFloat(5.6f64),
OrderedFloat(6.6f64),
};
let deser_set: std::collections::HashSet<crate::Double> = from_edn(&set).unwrap();
let deser_set: std::collections::HashSet<OrderedFloat<f64>> = from_edn(&set).unwrap();
assert_eq!(deser_set, expected);
}

Expand Down
52 changes: 48 additions & 4 deletions src/deserialize/parse.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use crate::edn::{Edn, Error, List, Map, Set, Vector};
use std::collections::{BTreeMap, BTreeSet};
#[cfg(feature = "sets")]
use crate::edn::Set;
use crate::edn::{Edn, Error, List, Map, Vector};
use std::collections::BTreeMap;
#[cfg(feature = "sets")]
use std::collections::BTreeSet;

const DELIMITERS: [char; 8] = [',', ']', '}', ')', ';', '(', '[', '{'];

Expand Down Expand Up @@ -413,6 +417,7 @@ fn read_list(chars: &mut std::iter::Enumerate<std::str::Chars>) -> Result<Edn, E
}
}

#[cfg(feature = "sets")]
fn read_set(chars: &mut std::iter::Enumerate<std::str::Chars>) -> Result<Edn, Error> {
let _discard_brackets = chars.next();
let i = chars
Expand All @@ -438,6 +443,13 @@ fn read_set(chars: &mut std::iter::Enumerate<std::str::Chars>) -> Result<Edn, Er
}
}

#[cfg(not(feature = "sets"))]
fn read_set(_chars: &mut std::iter::Enumerate<std::str::Chars>) -> Result<Edn, Error> {
Err(Error::ParseEdn(
"Could not parse set due to feature not being enabled".to_string(),
))
}

fn read_namespaced_map(chars: &mut std::iter::Enumerate<std::str::Chars>) -> Result<Edn, Error> {
let i = chars
.clone()
Expand Down Expand Up @@ -524,7 +536,9 @@ fn read_if_not_container_end(
#[cfg(test)]
mod test {
use super::*;
use crate::edn::{Double, Map, Set};
use crate::edn::Map;
#[cfg(feature = "sets")]
use crate::edn::Set;
use crate::{map, set};

#[test]
Expand Down Expand Up @@ -639,20 +653,26 @@ mod test {

#[test]
fn parse_number() {
use crate::edn;
let mut uint = "143".chars().enumerate();
let mut int = "-435143".chars().enumerate();
let mut f = "-43.5143".chars().enumerate();
let mut r = "43/5143".chars().enumerate();
let mut big_f64 = "999999999999999999999.0".chars().enumerate();
assert_eq!(parse_edn(uint.next(), &mut uint).unwrap(), Edn::UInt(143));
assert_eq!(parse_edn(int.next(), &mut int).unwrap(), Edn::Int(-435143));
assert_eq!(
parse_edn(f.next(), &mut f).unwrap(),
Edn::Double(Double::from(-43.5143))
Edn::Double(edn::Double::from(-43.5143))
);
assert_eq!(
parse_edn(r.next(), &mut r).unwrap(),
Edn::Rational("43/5143".to_string())
);
assert_eq!(
parse_edn(big_f64.next(), &mut big_f64).unwrap(),
Edn::Double(edn::Double::from(1e21f64))
);
}

#[test]
Expand Down Expand Up @@ -847,6 +867,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_set() {
let mut edn = "#{true \\c 3 }".chars().enumerate();

Expand All @@ -861,6 +882,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_set_with_commas() {
let mut edn = "#{true, \\c, 3,four, }".chars().enumerate();

Expand All @@ -876,6 +898,21 @@ mod test {
}

#[test]
#[cfg(not(feature = "sets"))]
fn parse_set_without_set_feature() {
let mut edn = "#{true, \\c, 3,four, }".chars().enumerate();
let res = parse(edn.next(), &mut edn);

assert_eq!(
res,
Err(Error::ParseEdn(
"Could not parse set due to feature not being enabled".to_string()
))
)
}

#[test]
#[cfg(feature = "sets")]
fn parse_comment_in_set() {
let mut edn = "#{true ; bool true in a set\n \\c 3 }".chars().enumerate();

Expand All @@ -890,6 +927,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_true_false_nil_with_comments_in_set() {
let mut edn = "#{true;this is true\nfalse;this is false\nnil;this is nil\n}"
.chars()
Expand All @@ -902,6 +940,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_comment_in_set_end() {
let mut edn = "#{true \\c 3; int 3 in a set\n}".chars().enumerate();

Expand All @@ -916,6 +955,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_complex() {
let mut edn = "[:b ( 5 \\c #{true \\c 3 } ) ]".chars().enumerate();

Expand All @@ -937,6 +977,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_comment_complex() {
let mut edn = "[:b ( 5 \\c #{true \\c; char c in a set\n3 } ) ]"
.chars()
Expand Down Expand Up @@ -987,6 +1028,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_edn_with_inst() {
let mut edn =
"#{ :a :b {:c :d :date #inst \"2020-07-16T21:53:14.628-00:00\" ::c ::d} nil}"
Expand Down Expand Up @@ -1049,6 +1091,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_discard_space_invalid() {
let mut edn = "#_ ,, #{hello, this will be discarded} #_{so will this} #{this is invalid"
.chars()
Expand Down Expand Up @@ -1350,6 +1393,7 @@ mod test {
}

#[test]
#[cfg(feature = "sets")]
fn parse_tagged_set() {
let mut edn = "#domain/model #{1 2 3}".chars().enumerate();
let res = parse(edn.next(), &mut edn).unwrap();
Expand Down
Loading
Loading