use crate::deserialize::parse::{self, MaybeReplaceExt};
use std::cmp::{Ord, PartialOrd};
use std::collections::{BTreeMap, BTreeSet};
use utils::index::Index;
#[cfg(feature = "async")]
use core::pin::Pin;
#[cfg(feature = "async")]
use futures::task;
#[cfg(feature = "async")]
use futures::task::Poll;
#[doc(hidden)]
pub mod utils;
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Edn {
Vector(Vector),
Set(Set),
Map(Map),
List(List),
Key(String),
Symbol(String),
Str(String),
Int(isize),
UInt(usize),
Double(Double),
Rational(String),
Char(char),
Bool(bool),
Inst(String),
Nil,
Empty,
}
#[cfg(feature = "async")]
impl futures::future::Future for Edn {
type Output = Edn;
fn poll(self: Pin<&mut Self>, _cx: &mut task::Context) -> Poll<Self::Output> {
if !self.to_string().is_empty() {
let pinned = self.to_owned();
Poll::Ready(pinned)
} else {
Poll::Pending
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Vector(Vec<Edn>);
impl Vector {
pub fn new(v: Vec<Edn>) -> Vector {
Vector(v)
}
pub fn empty() -> Vector {
Vector(Vec::new())
}
}
#[cfg(feature = "async")]
impl futures::future::Future for Vector {
type Output = Vector;
#[allow(unused_comparisons)]
fn poll(self: Pin<&mut Self>, _cx: &mut task::Context) -> Poll<Self::Output> {
if self.0.len() >= 0 {
let pinned = self.to_owned();
Poll::Ready(pinned)
} else {
Poll::Pending
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct List(Vec<Edn>);
impl List {
pub fn new(v: Vec<Edn>) -> List {
List(v)
}
pub fn empty() -> List {
List(Vec::new())
}
}
#[cfg(feature = "async")]
impl futures::future::Future for List {
type Output = List;
#[allow(unused_comparisons)]
fn poll(self: Pin<&mut Self>, _cx: &mut task::Context) -> Poll<Self::Output> {
if self.0.len() >= 0 {
let pinned = self.to_owned();
Poll::Ready(pinned)
} else {
Poll::Pending
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Set(BTreeSet<Edn>);
impl Set {
pub fn new(v: BTreeSet<Edn>) -> Set {
Set(v)
}
pub fn empty() -> Set {
Set(BTreeSet::new())
}
}
#[cfg(feature = "async")]
impl futures::future::Future for Set {
type Output = Set;
#[allow(unused_comparisons)]
fn poll(self: Pin<&mut Self>, _cx: &mut task::Context) -> Poll<Self::Output> {
if self.0.len() >= 0 {
let pinned = self.to_owned();
Poll::Ready(pinned)
} else {
Poll::Pending
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Map(BTreeMap<String, Edn>);
impl Map {
pub fn new(m: BTreeMap<String, Edn>) -> Map {
Map(m)
}
pub fn empty() -> Map {
Map(BTreeMap::new())
}
}
#[cfg(feature = "async")]
impl futures::future::Future for Map {
type Output = Map;
#[allow(unused_comparisons)]
fn poll(self: Pin<&mut Self>, _cx: &mut task::Context) -> Poll<Self::Output> {
if self.0.len() >= 0 {
let pinned = self.to_owned();
Poll::Ready(pinned)
} else {
Poll::Pending
}
}
}
#[derive(Clone, Ord, Debug, Eq, PartialEq, PartialOrd, Hash)]
pub struct Double(i64, u64);
impl From<f64> for Double {
fn from(f: f64) -> Double {
let f_as_str = format!("{}", f);
let f_split = f_as_str.split(".").collect::<Vec<&str>>();
Double(
f_split[0].parse::<i64>().unwrap(),
f_split
.get(1)
.unwrap_or(&"0")
.chars()
.rev()
.collect::<String>()
.parse::<u64>()
.unwrap(),
)
}
}
#[cfg(feature = "async")]
impl futures::future::Future for Double {
type Output = Double;
fn poll(self: Pin<&mut Self>, _cx: &mut task::Context) -> Poll<Self::Output> {
if !self.to_string().is_empty() {
let pinned = self.to_owned();
Poll::Ready(pinned)
} else {
Poll::Pending
}
}
}
impl std::fmt::Display for Double {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}.{}",
self.0,
self.1.to_string().chars().rev().collect::<String>()
)
}
}
impl Double {
fn to_float(&self) -> f64 {
format!(
"{}.{}",
self.0,
self.1.to_string().chars().rev().collect::<String>()
)
.parse::<f64>()
.unwrap()
}
}
impl core::fmt::Display for Vector {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"[{}]",
self.0
.iter()
.map(|i| format!("{}, ", i))
.fold(String::new(), |mut acc, i| {
acc.push_str(&i);
acc
})
)
}
}
impl core::fmt::Display for List {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"({})",
self.0
.iter()
.map(|i| format!("{}, ", i))
.fold(String::new(), |mut acc, i| {
acc.push_str(&i);
acc
})
)
}
}
impl core::fmt::Display for Set {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"#{{{}}}",
self.0
.iter()
.map(|i| format!("{}, ", i))
.fold(String::new(), |mut acc, i| {
acc.push_str(&i);
acc
})
)
}
}
impl core::fmt::Display for Map {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{{{}}}",
self.0.iter().map(|(k, v)| format!("{} {}, ", k, v)).fold(
String::new(),
|mut acc, i| {
acc.push_str(&i);
acc
}
)
)
}
}
impl core::fmt::Display for Edn {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let text = match self {
Edn::Vector(v) => format!("{}", v),
Edn::Set(s) => format!("{}", s),
Edn::Map(m) => format!("{}", m),
Edn::List(l) => format!("{}", l),
Edn::Symbol(sy) => sy.to_string(),
Edn::Key(k) => k.to_string(),
Edn::Str(s) => format!("{:?}", s),
Edn::Int(i) => format!("{}", i),
Edn::UInt(u) => format!("{}", u),
Edn::Double(d) => format!("{}", d),
Edn::Rational(r) => r.to_string(),
Edn::Bool(b) => format!("{}", b),
Edn::Char(c) => format!("{}", c),
Edn::Inst(t) => format!("{}", t),
Edn::Nil => String::from("nil"),
Edn::Empty => String::from(""),
};
write!(f, "{}", text)
}
}
impl Edn {
pub fn to_float(&self) -> Option<f64> {
match self {
Edn::Key(k) => k.replace(":", "").parse::<f64>().ok(),
Edn::Str(s) => s.parse::<f64>().ok(),
Edn::Int(i) => to_double(i).ok(),
Edn::UInt(u) => to_double(u).ok(),
Edn::Double(d) => Some(d.to_float()),
Edn::Rational(r) => rational_to_double(&r),
_ => None,
}
}
pub fn to_int(&self) -> Option<isize> {
match self {
Edn::Key(k) => k.replace(":", "").parse::<isize>().ok(),
Edn::Str(s) => s.parse::<isize>().ok(),
Edn::Int(i) => Some(i.to_owned() as isize),
Edn::UInt(u) if *u <= isize::MAX as usize => Some(u.to_owned() as isize),
Edn::Double(d) => Some(d.to_owned().to_float().round() as isize),
Edn::Rational(r) => Some(rational_to_double(&r).unwrap_or(0f64).round() as isize),
_ => None,
}
}
pub fn to_uint(&self) -> Option<usize> {
match self {
Edn::Str(s) => s.parse::<usize>().ok(),
Edn::Int(i) if i > &0 => Some(i.to_owned() as usize),
Edn::UInt(i) => Some(i.to_owned()),
Edn::Double(d) if d.to_float() > 0f64 => Some(d.to_owned().to_float().round() as usize),
Edn::Rational(r) if !r.contains("-") => {
Some(rational_to_double(&r).unwrap_or(0f64).round() as usize)
}
_ => None,
}
}
pub fn to_bool(&self) -> Option<bool> {
match self {
Edn::Bool(b) => Some(*b),
Edn::Str(s) => s.parse::<bool>().ok(),
Edn::Symbol(s) => s.parse::<bool>().ok(),
_ => None,
}
}
pub fn to_char(&self) -> Option<char> {
match self {
Edn::Char(c) => Some(*c),
_ => None,
}
}
pub fn to_vec(&self) -> Option<Vec<String>> {
match self {
Edn::Vector(_) => Some(
self.iter()
.unwrap()
.map(|e| e.to_string())
.collect::<Vec<String>>(),
),
Edn::List(_) => Some(
self.iter()
.unwrap()
.map(|e| e.to_string())
.collect::<Vec<String>>(),
),
Edn::Set(_) => Some(
self.iter()
.unwrap()
.map(|e| e.to_string())
.collect::<Vec<String>>(),
),
_ => None,
}
}
pub fn to_int_vec(&self) -> Option<Vec<isize>> {
match self {
Edn::Vector(_) if !self.iter().unwrap().any(|e| e.to_int().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_int().unwrap())
.collect::<Vec<isize>>(),
),
Edn::List(_) if !self.iter().unwrap().any(|e| e.to_int().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_int().unwrap())
.collect::<Vec<isize>>(),
),
Edn::Set(_) if !self.iter().unwrap().any(|e| e.to_int().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_int().unwrap())
.collect::<Vec<isize>>(),
),
_ => None,
}
}
pub fn to_uint_vec(&self) -> Option<Vec<usize>> {
match self {
Edn::Vector(_) if !self.iter().unwrap().any(|e| e.to_uint().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_uint().unwrap())
.collect::<Vec<usize>>(),
),
Edn::List(_) if !self.iter().unwrap().any(|e| e.to_uint().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_uint().unwrap())
.collect::<Vec<usize>>(),
),
Edn::Set(_) if !self.iter().unwrap().any(|e| e.to_uint().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_uint().unwrap())
.collect::<Vec<usize>>(),
),
_ => None,
}
}
pub fn to_float_vec(&self) -> Option<Vec<f64>> {
match self {
Edn::Vector(_) if !self.iter().unwrap().any(|e| e.to_float().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_float().unwrap())
.collect::<Vec<f64>>(),
),
Edn::List(_) if !self.iter().unwrap().any(|e| e.to_float().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_float().unwrap())
.collect::<Vec<f64>>(),
),
Edn::Set(_) if !self.iter().unwrap().any(|e| e.to_float().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_float().unwrap())
.collect::<Vec<f64>>(),
),
_ => None,
}
}
pub fn to_bool_vec(&self) -> Option<Vec<bool>> {
match self {
Edn::Vector(_) if !self.iter().unwrap().any(|e| e.to_bool().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_bool().unwrap())
.collect::<Vec<bool>>(),
),
Edn::List(_) if !self.iter().unwrap().any(|e| e.to_bool().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_bool().unwrap())
.collect::<Vec<bool>>(),
),
Edn::Set(_) if !self.iter().unwrap().any(|e| e.to_bool().is_none()) => Some(
self.iter()
.unwrap()
.map(|e| e.to_bool().unwrap())
.collect::<Vec<bool>>(),
),
_ => None,
}
}
pub fn to_debug(&self) -> String {
format!("{:?}", self)
}
pub fn get<I: Index>(&self, index: I) -> Option<&Edn> {
index.index_into(self)
}
pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Edn> {
index.index_into_mut(self)
}
pub fn iter(&self) -> Option<std::slice::Iter<'_, Edn>> {
match self {
Edn::Vector(v) => Some(v.0.iter()),
Edn::List(l) => Some(l.0.iter()),
_ => None,
}
}
pub fn set_iter(&self) -> Option<std::collections::btree_set::Iter<'_, Edn>> {
match self {
Edn::Set(s) => Some(s.0.iter()),
_ => None,
}
}
pub fn map_iter(&self) -> Option<std::collections::btree_map::Iter<'_, String, Edn>> {
match self {
Edn::Map(m) => Some(m.0.iter()),
_ => None,
}
}
}
impl std::str::FromStr for Edn {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let clean = String::from(s.maybe_replace("#{", "@").trim_start());
let mut tokens = parse::tokenize(&clean);
let edn = parse::parse(tokens.next(), &mut tokens)?;
Ok(edn)
}
}
fn to_double<T>(i: T) -> Result<f64, std::num::ParseFloatError>
where
T: std::fmt::Debug,
{
format!("{:?}", i).parse::<f64>()
}
fn rational_to_double(r: &str) -> Option<f64> {
if r.split('/').count() == 2 {
let vals = r
.split('/')
.map(ToString::to_string)
.map(|v| v.parse::<f64>())
.map(Result::ok)
.collect::<Option<Vec<f64>>>()?;
return Some(vals[0] / vals[1]);
}
None
}
#[derive(Debug, PartialEq)]
pub enum Error {
ParseEdn(String),
Deserialize(String),
Iter(String),
}
impl From<String> for Error {
fn from(s: String) -> Self {
Error::ParseEdn(s)
}
}
impl From<std::num::ParseIntError> for Error {
fn from(s: std::num::ParseIntError) -> Self {
Error::ParseEdn(s.to_string())
}
}
impl From<std::num::ParseFloatError> for Error {
fn from(s: std::num::ParseFloatError) -> Self {
Error::ParseEdn(s.to_string())
}
}
impl From<std::str::ParseBoolError> for Error {
fn from(s: std::str::ParseBoolError) -> Self {
Error::ParseEdn(s.to_string())
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
match self {
Error::ParseEdn(s) => &s,
Error::Deserialize(s) => &s,
Error::Iter(s) => &s,
}
}
fn cause(&self) -> Option<&dyn std::error::Error> {
Some(self)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::ParseEdn(s) => write!(f, "{}", &s),
Error::Deserialize(s) => write!(f, "{}", &s),
Error::Iter(s) => write!(f, "{}", &s),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parses_rationals() {
assert_eq!(rational_to_double("3/4").unwrap(), 0.75f64);
assert_eq!(rational_to_double("25/5").unwrap(), 5f64);
assert_eq!(rational_to_double("15/4").unwrap(), 3.75f64);
assert_eq!(rational_to_double("3 4"), None);
assert_eq!(rational_to_double("3/4/5"), None);
assert_eq!(rational_to_double("text/moretext"), None);
}
#[test]
fn iterator() {
let v = Edn::Vector(Vector::new(vec![Edn::Int(5), Edn::Int(6), Edn::Int(7)]));
let sum = v
.iter()
.unwrap()
.filter(|e| e.to_int().is_some())
.map(|e| e.to_int().unwrap())
.sum();
assert_eq!(18isize, sum);
}
#[test]
fn to_vec() {
let edn = Edn::Vector(Vector::new(vec![Edn::Int(5), Edn::Int(6), Edn::Int(7)]));
let v = vec![String::from("5"), String::from("6"), String::from("7")];
assert_eq!(edn.to_vec().unwrap(), v);
}
#[test]
fn double_deals_with_decimal_zeros() {
let double = Double::from(-3.0000564f64);
assert_eq!(double.to_float(), -3.0000564f64);
}
#[test]
fn double_deals_without_decimal_zeros() {
let double = Double::from(45843.835832564f64);
assert_eq!(double.to_float(), 45843.835832564f64);
}
#[test]
fn to_char() {
let c = Edn::Char('c');
let symbol = Edn::Symbol("d".to_string());
assert_eq!(c.to_char().unwrap(), 'c');
assert_eq!(symbol.to_char(), None);
}
#[test]
fn to_int_vec() {
let edn = Edn::Vector(Vector::new(vec![Edn::Int(5), Edn::Int(6), Edn::Int(7)]));
let v = vec![5isize, 6isize, 7isize];
assert_eq!(edn.to_int_vec().unwrap(), v);
}
#[test]
fn to_uint_vec() {
let edn = Edn::Vector(Vector::new(vec![Edn::UInt(5), Edn::UInt(6), Edn::UInt(7)]));
let v = vec![5usize, 6usize, 7usize];
assert_eq!(edn.to_uint_vec().unwrap(), v);
}
#[test]
fn to_float_vec() {
let edn = Edn::Vector(Vector::new(vec![
Edn::Double(5.5.into()),
Edn::Double(6.6.into()),
Edn::Double(7.7.into()),
]));
let v = vec![5.5f64, 6.6f64, 7.7f64];
assert_eq!(edn.to_float_vec().unwrap(), v);
}
#[test]
fn to_bool_vec() {
let edn = Edn::Vector(Vector::new(vec![
Edn::Bool(true),
Edn::Bool(true),
Edn::Bool(false),
]));
let v = vec![true, true, false];
assert_eq!(edn.to_bool_vec().unwrap(), v);
}
#[test]
fn to_bool_vec_with_non_bool_is_none() {
let edn = Edn::Vector(Vector::new(vec![
Edn::Bool(true),
Edn::Int(5),
Edn::Bool(false),
]));
assert_eq!(edn.to_bool_vec(), None);
}
#[test]
fn edn_to_string() {
let edn = Edn::Map(Map::new(
map! {":a".to_string() => Edn::Key(":something".to_string()),
":b".to_string() => Edn::Bool(false), ":c".to_string() => Edn::Nil},
));
assert_eq!(edn.to_string(), "{:a :something, :b false, :c nil, }");
}
#[test]
fn edn_to_debug() {
let edn = Edn::Map(Map::new(
map! {":a".to_string() => Edn::Key(":something".to_string()),
":b".to_string() => Edn::Bool(false), ":c".to_string() => Edn::Nil},
));
let expected = "Map(Map({\":a\": Key(\":something\"), \":b\": Bool(false), \":c\": Nil}))";
assert_eq!(edn.to_debug(), expected);
}
#[test]
fn negative_isize_to_usize() {
let neg_i = Edn::Int(-10);
assert_eq!(neg_i.to_uint(), None);
}
#[test]
fn max_usize_to_uint() {
let max_u = Edn::UInt(usize::MAX);
assert_eq!(max_u.to_int(), None);
}
#[test]
fn positive_isize_to_usize() {
let max_i = Edn::Int(isize::MAX);
assert_eq!(max_i.to_uint(), Some(isize::MAX as usize));
}
#[test]
fn small_usize_to_isize() {
let small_u = Edn::UInt(10);
assert_eq!(small_u.to_int(), Some(10));
}
}