use ordered_float::OrderedFloat;
use std::cmp::{Ord, PartialOrd};
use std::collections::{BTreeMap, BTreeSet};
use utils::index::Index;
#[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),
Nil,
Empty,
}
#[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())
}
}
#[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())
}
}
#[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())
}
}
#[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())
}
}
pub type Double = OrderedFloat<f64>;
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) => s.to_string(),
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::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.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.into_inner()),
Edn::Rational(r) => rational_to_double(&r),
_ => None,
}
}
pub fn to_int(&self) -> Option<isize> {
match self {
Edn::Key(k) => k.parse::<isize>().ok(),
Edn::Str(s) => s.parse::<isize>().ok(),
Edn::Int(i) => Some(i.to_owned() as isize),
Edn::Double(d) => Some(d.to_owned().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) => Some(i.to_owned() as usize),
Edn::UInt(i) => Some(i.to_owned()),
Edn::Double(d) => Some(d.to_owned().round() as usize),
Edn::Rational(r) => 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_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>>(),
),
_ => None,
}
}
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,
}
}
pub(crate) fn parse_word(word: String) -> Edn {
match word {
w if w.starts_with(":") => Edn::Key(w),
w if w.starts_with("\\") && w.len() == 2 => Edn::Char(w.chars().last().unwrap()),
w if w.starts_with("\"") && w.ends_with("\"") => Edn::Str(w.replace("\"", "")),
w if w.parse::<bool>().is_ok() => Edn::Bool(w.parse::<bool>().unwrap()),
w if w == "nil" || w == "Nil" => Edn::Nil,
w if w.contains("/") && w.split("/").all(|d| d.parse::<f64>().is_ok()) => {
Edn::Rational(w)
}
w if w.parse::<usize>().is_ok() => Edn::UInt(w.parse::<usize>().unwrap()),
w if w.parse::<isize>().is_ok() => Edn::Int(w.parse::<isize>().unwrap()),
w if w.parse::<f64>().is_ok() => Edn::Double(OrderedFloat(w.parse::<f64>().unwrap())),
w => Edn::Symbol(w),
}
}
}
impl std::str::FromStr for Edn {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::deserialize::parse_edn(s)
}
}
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
}
#[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);
}
#[derive(Debug, PartialEq)]
pub enum Error {
ParseEdnError(String),
}
impl From<String> for Error {
fn from(s: String) -> Self {
Error::ParseEdnError(s)
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
match self {
Error::ParseEdnError(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::ParseEdnError(s) => write!(f, "{}", &s),
}
}
}