use bytemuck::TransparentWrapper; use std::borrow::{Cow, Borrow}; use std::cmp::Ordering; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::vec::Vec; pub use std::collections::BTreeSet as Set; pub use std::collections::BTreeMap as Map; pub mod float; pub mod signed_integer; pub use float::Float; pub use float::Double; pub use signed_integer::SignedInteger; /// The kinds of `Value` from the specification. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ValueClass { Atomic(AtomClass), Compound(CompoundClass), Embedded, } /// The kinds of `Atom` from the specification. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum AtomClass { Boolean, Float, Double, SignedInteger, String, ByteString, Symbol, } /// The kinds of `Compound` from the specification. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum CompoundClass { Record, Sequence, Set, Dictionary, } pub trait Domain: Debug + Eq + Hash + Ord + Clone {} #[derive(Debug)] pub struct OutOfRange; pub trait Value: Debug { fn value_class(&self) -> ValueClass; fn as_boolean(&self) -> Option { None } fn as_float(&self) -> Option { None } fn as_double(&self) -> Option { None } fn is_signed_integer(&self) -> bool { false } fn as_signed_integer(&self) -> Option { None } fn as_string(&self) -> Option> { None } fn as_bytestring(&self) -> Option> { None } fn as_symbol(&self) -> Option> { None } fn is_record(&self) -> bool { false } fn label(&self) -> &dyn Value { panic!("Not a record") } fn is_sequence(&self) -> bool { false } fn len(&self) -> usize { panic!("Has no length") } fn index(&self, _i: usize) -> &dyn Value { panic!("Not indexable") } fn iter(&self) -> Box> + '_> { panic!("Not iterable") } fn is_set(&self) -> bool { false } fn has(&self, _v: &dyn Value) -> bool { false } fn is_dictionary(&self) -> bool { false } fn get(&self, _k: &dyn Value) -> Option<&dyn Value> { None } fn entries(&self) -> Box, &dyn Value)> + '_> { panic!("Not a dictionary") } fn is_embedded(&self) -> bool { false } fn embedded(&self) -> Cow<'_, D> { panic!("Not an embedded value") } fn annotations(&self) -> Option<&[Box>]> { None } } pub fn value>(v: &V) -> &dyn Value { v } pub fn owned + 'static>(v: V) -> Box> { Box::new(v) } impl<'a, D: Domain, V: Value + ?Sized> Value for &'a V { fn value_class(&self) -> ValueClass { (*self).value_class() } fn as_boolean(&self) -> Option { (*self).as_boolean() } fn as_float(&self) -> Option { (*self).as_float() } fn as_double(&self) -> Option { (*self).as_double() } fn is_signed_integer(&self) -> bool { (*self).is_signed_integer() } fn as_signed_integer(&self) -> Option { (*self).as_signed_integer() } fn as_string(&self) -> Option> { (*self).as_string() } fn as_bytestring(&self) -> Option> { (*self).as_bytestring() } fn as_symbol(&self) -> Option> { (*self).as_symbol() } fn is_record(&self) -> bool { (*self).is_record() } fn label(&self) -> &dyn Value { (*self).label() } fn is_sequence(&self) -> bool { (*self).is_sequence() } fn len(&self) -> usize { (*self).len() } fn index(&self, i: usize) -> &dyn Value { (*self).index(i) } fn iter(&self) -> Box> + '_> { (*self).iter() } fn is_set(&self) -> bool { (*self).is_set() } fn has(&self, v: &dyn Value) -> bool { (*self).has(v) } fn is_dictionary(&self) -> bool { (*self).is_dictionary() } fn get(&self, k: &dyn Value) -> Option<&dyn Value> { (*self).get(k) } fn entries(&self) -> Box, &dyn Value)> + '_> { (*self).entries() } fn is_embedded(&self) -> bool { (*self).is_embedded() } fn embedded(&self) -> Cow<'_, D> { (*self).embedded() } fn annotations(&self) -> Option<&[Box>]> { (*self).annotations() } } impl Value for Box> { fn value_class(&self) -> ValueClass { self.as_ref().value_class() } fn as_boolean(&self) -> Option { self.as_ref().as_boolean() } fn as_float(&self) -> Option { self.as_ref().as_float() } fn as_double(&self) -> Option { self.as_ref().as_double() } fn is_signed_integer(&self) -> bool { self.as_ref().is_signed_integer() } fn as_signed_integer(&self) -> Option { self.as_ref().as_signed_integer() } fn as_string(&self) -> Option> { self.as_ref().as_string() } fn as_bytestring(&self) -> Option> { self.as_ref().as_bytestring() } fn as_symbol(&self) -> Option> { self.as_ref().as_symbol() } fn is_record(&self) -> bool { self.as_ref().is_record() } fn label(&self) -> &dyn Value { self.as_ref().label() } fn is_sequence(&self) -> bool { self.as_ref().is_sequence() } fn len(&self) -> usize { self.as_ref().len() } fn index(&self, i: usize) -> &dyn Value { self.as_ref().index(i) } fn iter(&self) -> Box> + '_> { self.as_ref().iter() } fn is_set(&self) -> bool { self.as_ref().is_set() } fn has(&self, v: &dyn Value) -> bool { self.as_ref().has(v) } fn is_dictionary(&self) -> bool { self.as_ref().is_dictionary() } fn get(&self, k: &dyn Value) -> Option<&dyn Value> { self.as_ref().get(k) } fn entries(&self) -> Box, &dyn Value)> + '_> { self.as_ref().entries() } fn is_embedded(&self) -> bool { self.as_ref().is_embedded() } fn embedded(&self) -> Cow<'_, D> { self.as_ref().embedded() } fn annotations(&self) -> Option<&[Box>]> { self.as_ref().annotations() } } impl<'a, D: Domain> Hash for dyn Value + 'a { fn hash(&self, state: &mut H) { match self.value_class() { ValueClass::Atomic(a) => match a { AtomClass::Boolean => self.as_boolean().unwrap().hash(state), AtomClass::Float => self.as_float().unwrap().to_bits().hash(state), AtomClass::Double => self.as_double().unwrap().to_bits().hash(state), AtomClass::SignedInteger => self.as_signed_integer().unwrap().hash(state), AtomClass::String => self.as_string().unwrap().hash(state), AtomClass::ByteString => self.as_bytestring().unwrap().hash(state), AtomClass::Symbol => self.as_symbol().unwrap().hash(state), } ValueClass::Compound(c) => match c { CompoundClass::Sequence | CompoundClass::Set => { state.write_usize(self.len()); for v in self.iter() { v.hash(state) } } CompoundClass::Record => { self.label().hash(state); state.write_usize(self.len()); for v in self.iter() { v.hash(state) } } CompoundClass::Dictionary => { state.write_usize(self.len()); for (k, v) in self.entries() { k.hash(state); v.hash(state); } } } ValueClass::Embedded => self.embedded().hash(state), } } } fn iters_eq<'a, D: Domain>( mut i1: Box> + 'a>, mut i2: Box> + 'a>, ) -> bool { loop { match i1.next() { None => return i2.next().is_none(), Some(v1) => match i2.next() { None => return false, Some(v2) => if v1 != v2 { return false; }, } } } } impl<'a, D: Domain> PartialEq for dyn Value + 'a { fn eq(&self, other: &Self) -> bool { let cls = self.value_class(); if cls != other.value_class() { return false; } match cls { ValueClass::Atomic(a) => match a { AtomClass::Boolean => self.as_boolean().unwrap() == other.as_boolean().unwrap(), AtomClass::Float => Float(self.as_float().unwrap()) == Float(other.as_float().unwrap()), AtomClass::Double => Double(self.as_double().unwrap()) == Double(other.as_double().unwrap()), AtomClass::SignedInteger => self.as_signed_integer().unwrap() == other.as_signed_integer().unwrap(), AtomClass::String => self.as_string().unwrap() == other.as_string().unwrap(), AtomClass::ByteString => self.as_bytestring().unwrap() == other.as_bytestring().unwrap(), AtomClass::Symbol => self.as_symbol().unwrap() == other.as_symbol().unwrap(), } ValueClass::Compound(c) => match c { CompoundClass::Record => { if self.label() != other.label() { return false; } iters_eq(self.iter(), other.iter()) } CompoundClass::Sequence => { iters_eq(self.iter(), other.iter()) } CompoundClass::Set => { let s1 = self.iter().collect::>(); let s2 = other.iter().collect::>(); s1 == s2 } CompoundClass::Dictionary => { let d1 = self.entries().collect::>(); let d2 = other.entries().collect::>(); d1 == d2 } } ValueClass::Embedded => self.embedded() == other.embedded(), } } } fn iters_cmp<'a, D: Domain>( mut i1: Box> + 'a>, mut i2: Box> + 'a>, ) -> Ordering { loop { match i1.next() { None => match i2.next() { None => return Ordering::Equal, Some(_) => return Ordering::Less, } Some(v1) => match i2.next() { None => return Ordering::Greater, Some(v2) => match v1.cmp(v2) { Ordering::Equal => (), other => return other, } } } } } impl<'a, D: Domain> Ord for dyn Value + 'a { fn cmp(&self, other: &Self) -> Ordering { let cls = self.value_class(); cls.cmp(&other.value_class()).then_with(|| match cls { ValueClass::Atomic(a) => match a { AtomClass::Boolean => self.as_boolean().cmp(&other.as_boolean()), AtomClass::Float => Float(self.as_float().unwrap()).cmp(&Float(other.as_float().unwrap())), AtomClass::Double => Double(self.as_double().unwrap()).cmp(&Double(other.as_double().unwrap())), AtomClass::SignedInteger => self.as_signed_integer().cmp(&other.as_signed_integer()), AtomClass::String => self.as_string().cmp(&other.as_string()), AtomClass::ByteString => self.as_bytestring().cmp(&other.as_bytestring()), AtomClass::Symbol => self.as_symbol().cmp(&other.as_symbol()), }, ValueClass::Compound(c) => match c { CompoundClass::Record => self.label().cmp(other.label()).then_with( || iters_cmp(self.iter(), other.iter())), CompoundClass::Sequence => iters_cmp(self.iter(), other.iter()), CompoundClass::Set => { let s1 = self.iter().collect::>(); let s2 = other.iter().collect::>(); s1.cmp(&s2) } CompoundClass::Dictionary => { let d1 = self.entries().collect::>(); let d2 = other.entries().collect::>(); d1.cmp(&d2) } }, ValueClass::Embedded => self.embedded().cmp(&other.embedded()), }) } } impl<'a, D: Domain> Eq for dyn Value + 'a {} impl<'a, D: Domain> PartialOrd for dyn Value + 'a { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum NoValue {} impl Domain for NoValue {} impl Value for NoValue { fn value_class(&self) -> ValueClass { unreachable!() } } impl Value for bool { fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Boolean) } fn as_boolean(&self) -> Option { Some(*self) } } impl Value for u64 { fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::SignedInteger) } fn as_signed_integer(&self) -> Option { Some((*self).into()) } } impl Value for Float { fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Float) } fn as_float(&self) -> Option { Some(self.0) } fn as_double(&self) -> Option { Some(self.0 as f64) } } impl Value for str { fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::String) } fn as_string(&self) -> Option> { Some(Cow::Borrowed(self)) } } impl Value for String { fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::String) } fn as_string(&self) -> Option> { Some(Cow::Borrowed(self)) } } impl> Value for Vec { fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Sequence) } fn is_sequence(&self) -> bool { true } fn len(&self) -> usize { self.len() } fn index(&self, i: usize) -> &dyn Value { &self[i] } fn iter(&self) -> Box> + '_> { Box::new(self[..].iter().map(value)) } } impl> Value for [V] { fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Sequence) } fn is_sequence(&self) -> bool { true } fn len(&self) -> usize { self.len() } fn index(&self, i: usize) -> &dyn Value { &self[i] } fn iter(&self) -> Box> + '_> { Box::new(self[..].iter().map(value)) } } impl Value for Set>> { fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Set) } fn is_set(&self) -> bool { true } fn len(&self) -> usize { self.len() } fn has(&self, v: &dyn Value) -> bool { self.contains(v) } fn iter(&self) -> Box> + '_> { Box::new(self.iter().map(value)) } } #[derive(PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] struct Key<'a, D: Domain>(dyn Value + 'a); // Many thanks to SkiFire13 and the other participants in // https://users.rust-lang.org/t/is-the-lifetime-of-a-btreemap-get-result-attached-to-the-key-as-well-as-the-map/83568/7 // for the idea of using TransparentWrapper here. // unsafe impl<'a, D: Domain> TransparentWrapper + 'a> for Key<'a, D> {} impl<'a, 'b: 'a, D: Domain> Borrow> for Box + 'b> { fn borrow(&self) -> &Key<'a, D> { Key::wrap_ref(&**self) } } impl> Value for Map>, V> { fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Dictionary) } fn is_dictionary(&self) -> bool { true } fn len(&self) -> usize { self.len() } fn has(&self, v: &dyn Value) -> bool { self.contains_key(v) } fn get(&self, k: &dyn Value) -> Option<&dyn Value> { match Map::get(self, Key::wrap_ref(&k)) { Some(v) => Some(v), None => None, } } fn entries(&self) -> Box, &dyn Value)> + '_> { Box::new(self.iter().map(|(k,v)| (value(k), value(v)))) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Record(Vec /* at least one element, for the label */); impl Record { pub fn new(label: V, mut fields: Vec) -> Self { fields.insert(0, label); Record(fields) } } impl> Value for Record { fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Record) } fn is_record(&self) -> bool { true } fn label(&self) -> &dyn Value { &self.0[0] } fn len(&self) -> usize { self.0.len() - 1 } fn index(&self, i: usize) -> &dyn Value { &self.0[i + 1] } fn iter(&self) -> Box> + '_> { Box::new(self.0[1..].iter().map(value)) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Symbol + Debug>(T); impl + Debug, D: Domain> Value for Symbol { fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Symbol) } fn as_symbol(&self) -> Option> { Some(Cow::Borrowed(self.0.as_ref())) } } #[derive(Debug)] pub struct Annotations>(V, Vec>>); impl> Annotations { pub fn value(&self) -> &dyn Value { &self.0 } } impl> Value for Annotations { fn value_class(&self) -> ValueClass { self.value().value_class() } fn as_boolean(&self) -> Option { self.value().as_boolean() } fn as_float(&self) -> Option { self.value().as_float() } fn as_double(&self) -> Option { self.value().as_double() } fn is_signed_integer(&self) -> bool { self.value().is_signed_integer() } fn as_signed_integer(&self) -> Option { self.value().as_signed_integer() } fn as_string(&self) -> Option> { self.value().as_string() } fn as_bytestring(&self) -> Option> { self.value().as_bytestring() } fn as_symbol(&self) -> Option> { self.value().as_symbol() } fn is_record(&self) -> bool { self.value().is_record() } fn label(&self) -> &dyn Value { self.value().label() } fn is_sequence(&self) -> bool { self.value().is_sequence() } fn len(&self) -> usize { self.value().len() } fn index(&self, i: usize) -> &dyn Value { self.value().index(i) } fn iter(&self) -> Box> + '_> { self.value().iter() } fn is_set(&self) -> bool { self.value().is_set() } fn has(&self, v: &dyn Value) -> bool { self.value().has(v) } fn is_dictionary(&self) -> bool { self.value().is_dictionary() } fn get(&self, k: &dyn Value) -> Option<&dyn Value> { self.value().get(k) } fn entries(&self) -> Box, &dyn Value)> + '_> { self.value().entries() } fn is_embedded(&self) -> bool { self.value().is_embedded() } fn embedded(&self) -> Cow<'_, D> { self.value().embedded() } fn annotations(&self) -> Option<&[Box>]> { Some(&self.1) } } impl> PartialEq for Annotations { fn eq(&self, other: &Self) -> bool { self.value().eq(&other.value()) } } impl> Eq for Annotations {} impl> Hash for Annotations { fn hash(&self, state: &mut H) { self.value().hash(state); } } impl> PartialOrd for Annotations { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl> Ord for Annotations { fn cmp(&self, other: &Self) -> Ordering { self.value().cmp(&other.value()) } } #[cfg(test)] mod demo { use crate::*; fn getit<'a>(d: &'a dyn Value, k: &str) -> Option<&'a dyn Value> { d.get(&k) } #[test] fn a() { let l = Symbol("label"); let r = Record::new(owned::(l.clone()), vec![owned(1), owned(2), owned(3)]); let r2 = Record::new(owned::(l), vec![owned(1), owned(2), owned(4)]); let mut v: Map>, String> = Map::new(); v.insert(Box::new("abc"), "def".to_owned()); v.insert(Box::new(123), "xyz".to_owned()); v.insert(Box::new(vec![1, 2, 3]), "www".to_owned()); v.insert(Box::new(r2), "bbb".to_owned()); v.insert(Box::new(r), "aaa".to_owned()); let w: &dyn Value = &v; println!("GETw abc {:?}", w.get(&"abc")); println!("GETw 123 {:?}", w.get(&123)); println!("GETw qqq {:?}", w.get(&"qqq")); println!("GETv abc {:?}", v.get(value(&"abc"))); println!("GETv 123 {:?}", v.get(value(&123))); println!("GETv qqq {:?}", v.get(value(&"qqq"))); for (kk, vv) in w.entries() { println!("{:?} {:?} ==> {:?} {:?}", kk.value_class(), kk, vv.value_class(), vv); } // { // use std::io::BufRead; // for line in std::io::stdin().lock().lines() { // let line = line.unwrap(); // let val = w.get(&line); // println!("{:?} ==> {:?} == {:?}", line, val, getit(&v, &line)); // } // } } }