Initial experimentation
This commit is contained in:
parent
0f3bca673a
commit
bb100cc0dd
|
@ -1,5 +1,6 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"oo",
|
||||
"preserves",
|
||||
"preserves-path",
|
||||
"preserves-schema",
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "oo"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.13"
|
||||
dtoa = "0.4"
|
||||
num = "0.4"
|
||||
regex = "1.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_bytes = "0.11"
|
||||
|
||||
[package.metadata.workspaces]
|
||||
independent = true
|
|
@ -0,0 +1,94 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
/// Single-precision IEEE 754 Value
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Float(pub f32);
|
||||
|
||||
/// Double-precision IEEE 754 Value
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Double(pub f64);
|
||||
|
||||
impl From<f32> for Float {
|
||||
fn from(v: f32) -> Self {
|
||||
Float(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Float> for f32 {
|
||||
fn from(v: Float) -> Self {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Float {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Float {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.to_bits() == other.0.to_bits()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Float {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let mut a: u32 = self.0.to_bits();
|
||||
let mut b: u32 = other.0.to_bits();
|
||||
if a & 0x8000_0000 != 0 { a ^= 0x7fff_ffff; }
|
||||
if b & 0x8000_0000 != 0 { b ^= 0x7fff_ffff; }
|
||||
(a as i32).cmp(&(b as i32))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Float {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Float {}
|
||||
|
||||
impl From<f64> for Double {
|
||||
fn from(v: f64) -> Self {
|
||||
Double(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Double> for f64 {
|
||||
fn from(v: Double) -> Self {
|
||||
v.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Double {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Double {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.to_bits() == other.0.to_bits()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Double {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let mut a: u64 = self.0.to_bits();
|
||||
let mut b: u64 = other.0.to_bits();
|
||||
if a & 0x8000_0000_0000_0000 != 0 { a ^= 0x7fff_ffff_ffff_ffff; }
|
||||
if b & 0x8000_0000_0000_0000 != 0 { b ^= 0x7fff_ffff_ffff_ffff; }
|
||||
(a as i64).cmp(&(b as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Double {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Double {}
|
|
@ -0,0 +1,430 @@
|
|||
use std::borrow::Cow;
|
||||
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<D: Domain>: Debug {
|
||||
fn value_class(&self) -> ValueClass;
|
||||
|
||||
fn as_boolean(&self) -> Option<bool> { None }
|
||||
fn as_float(&self) -> Option<f32> { None }
|
||||
fn as_double(&self) -> Option<f64> { None }
|
||||
|
||||
fn is_signed_integer(&self) -> bool { false }
|
||||
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> { None }
|
||||
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { None }
|
||||
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { None }
|
||||
fn as_symbol(&self) -> Option<Cow<'_, str>> { None }
|
||||
|
||||
fn is_record(&self) -> bool { false }
|
||||
fn label(&self) -> Option<&dyn Value<D>> { None }
|
||||
|
||||
fn is_sequence(&self) -> bool { false }
|
||||
fn len(&self) -> Option<usize> { None }
|
||||
fn index(&self, _i: usize) -> &dyn Value<D> { panic!("Not a sequence") }
|
||||
fn iter(&self) -> Option<Box<dyn Iterator<Item = &dyn Value<D>> + '_>> { None }
|
||||
|
||||
fn is_set(&self) -> bool { false }
|
||||
fn has(&self, _v: &dyn Value<D>) -> bool { false }
|
||||
|
||||
fn is_dictionary(&self) -> bool { false }
|
||||
fn get<'v>(&'v self, _k: &'v dyn Value<D>) -> Option<&'v dyn Value<D>> { None }
|
||||
fn entries(&self) -> Option<Box<dyn Iterator<Item = (&dyn Value<D>, &dyn Value<D>)> + '_>> { None }
|
||||
|
||||
fn is_embedded(&self) -> bool { false }
|
||||
fn embedded(&self) -> Option<Cow<'_, D>> { None }
|
||||
|
||||
fn annotations(&self) -> Option<&[Box<dyn Value<D>>]> { None }
|
||||
}
|
||||
|
||||
pub fn value<D: Domain, V: Value<D>>(v: &V) -> &dyn Value<D> {
|
||||
v
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> Value<D> for &'a dyn Value<D> {
|
||||
fn value_class(&self) -> ValueClass { (*self).value_class() }
|
||||
fn as_boolean(&self) -> Option<bool> { (*self).as_boolean() }
|
||||
fn as_float(&self) -> Option<f32> { (*self).as_float() }
|
||||
fn as_double(&self) -> Option<f64> { (*self).as_double() }
|
||||
fn is_signed_integer(&self) -> bool { (*self).is_signed_integer() }
|
||||
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> { (*self).as_signed_integer() }
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { (*self).as_string() }
|
||||
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { (*self).as_bytestring() }
|
||||
fn as_symbol(&self) -> Option<Cow<'_, str>> { (*self).as_symbol() }
|
||||
fn is_record(&self) -> bool { (*self).is_record() }
|
||||
fn label(&self) -> Option<&dyn Value<D>> { (*self).label() }
|
||||
fn is_sequence(&self) -> bool { (*self).is_sequence() }
|
||||
fn len(&self) -> Option<usize> { (*self).len() }
|
||||
fn index(&self, i: usize) -> &dyn Value<D> { (*self).index(i) }
|
||||
fn is_set(&self) -> bool { (*self).is_set() }
|
||||
fn has(&self, v: &dyn Value<D>) -> bool { (*self).has(v) }
|
||||
fn is_dictionary(&self) -> bool { (*self).is_dictionary() }
|
||||
fn get<'v>(&'v self, k: &'v dyn Value<D>) -> Option<&'v dyn Value<D>> { (*self).get(k) }
|
||||
fn entries(&self) -> Option<Box<dyn Iterator<Item = (&dyn Value<D>, &dyn Value<D>)> + '_>> { (*self).entries() }
|
||||
fn is_embedded(&self) -> bool { (*self).is_embedded() }
|
||||
fn embedded(&self) -> Option<Cow<'_, D>> { (*self).embedded() }
|
||||
fn annotations(&self) -> Option<&[Box<dyn Value<D>>]> { (*self).annotations() }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for Box<dyn Value<D>> {
|
||||
fn value_class(&self) -> ValueClass { self.as_ref().value_class() }
|
||||
fn as_boolean(&self) -> Option<bool> { self.as_ref().as_boolean() }
|
||||
fn as_float(&self) -> Option<f32> { self.as_ref().as_float() }
|
||||
fn as_double(&self) -> Option<f64> { self.as_ref().as_double() }
|
||||
fn is_signed_integer(&self) -> bool { self.as_ref().is_signed_integer() }
|
||||
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> { self.as_ref().as_signed_integer() }
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { self.as_ref().as_string() }
|
||||
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { self.as_ref().as_bytestring() }
|
||||
fn as_symbol(&self) -> Option<Cow<'_, str>> { self.as_ref().as_symbol() }
|
||||
fn is_record(&self) -> bool { self.as_ref().is_record() }
|
||||
fn label(&self) -> Option<&dyn Value<D>> { self.as_ref().label() }
|
||||
fn is_sequence(&self) -> bool { self.as_ref().is_sequence() }
|
||||
fn len(&self) -> Option<usize> { self.as_ref().len() }
|
||||
fn index(&self, i: usize) -> &dyn Value<D> { self.as_ref().index(i) }
|
||||
fn is_set(&self) -> bool { self.as_ref().is_set() }
|
||||
fn has(&self, v: &dyn Value<D>) -> bool { self.as_ref().has(v) }
|
||||
fn is_dictionary(&self) -> bool { self.as_ref().is_dictionary() }
|
||||
fn get<'v>(&'v self, k: &'v dyn Value<D>) -> Option<&'v dyn Value<D>> { self.as_ref().get(k) }
|
||||
fn entries(&self) -> Option<Box<dyn Iterator<Item = (&dyn Value<D>, &dyn Value<D>)> + '_>> { self.as_ref().entries() }
|
||||
fn is_embedded(&self) -> bool { self.as_ref().is_embedded() }
|
||||
fn embedded(&self) -> Option<Cow<'_, D>> { self.as_ref().embedded() }
|
||||
fn annotations(&self) -> Option<&[Box<dyn Value<D>>]> { self.as_ref().annotations() }
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> Hash for dyn Value<D> + 'a {
|
||||
fn hash<H: Hasher>(&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().unwrap());
|
||||
for v in self.iter().unwrap() { v.hash(state) }
|
||||
}
|
||||
CompoundClass::Record => {
|
||||
self.label().unwrap().hash(state);
|
||||
state.write_usize(self.len().unwrap());
|
||||
for v in self.iter().unwrap() { v.hash(state) }
|
||||
}
|
||||
CompoundClass::Dictionary => {
|
||||
state.write_usize(self.len().unwrap());
|
||||
for (k, v) in self.entries().unwrap() {
|
||||
k.hash(state);
|
||||
v.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
ValueClass::Embedded => self.embedded().unwrap().hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> PartialEq for dyn Value<D> + '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 {
|
||||
_ => todo!(),
|
||||
}
|
||||
ValueClass::Embedded => self.embedded().unwrap() == other.embedded().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> Ord for dyn Value<D> + 'a {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let cls = self.value_class();
|
||||
match cls.cmp(&other.value_class()) {
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
Ordering::Equal => 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 {
|
||||
_ => todo!(),
|
||||
},
|
||||
ValueClass::Embedded =>
|
||||
self.embedded().cmp(&other.embedded()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> Eq for dyn Value<D> + 'a {}
|
||||
|
||||
impl<'a, D: Domain> PartialOrd for dyn Value<D> + 'a {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub enum NoValue {}
|
||||
|
||||
impl Domain for NoValue {}
|
||||
|
||||
impl<D: Domain> Value<D> for NoValue {
|
||||
fn value_class(&self) -> ValueClass { unreachable!() }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for bool {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Boolean) }
|
||||
fn as_boolean(&self) -> Option<bool> { Some(*self) }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for u64 {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::SignedInteger) }
|
||||
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> {
|
||||
Some(Cow::Owned((*self).into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for Float {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Float) }
|
||||
fn as_float(&self) -> Option<f32> { Some(self.0) }
|
||||
fn as_double(&self) -> Option<f64> { Some(self.0 as f64) }
|
||||
}
|
||||
|
||||
impl<'a, D: Domain> Value<D> for &'a str {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::String) }
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self)) }
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for String {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::String) }
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self)) }
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> Value<D> for Vec<V> {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Sequence) }
|
||||
fn is_sequence(&self) -> bool { true }
|
||||
fn len(&self) -> Option<usize> { Some(self.len()) }
|
||||
fn index(&self, i: usize) -> &dyn Value<D> { &self[i] }
|
||||
fn iter(&self) -> Option<Box<dyn Iterator<Item = &dyn Value<D>> + '_>> {
|
||||
Some(Box::new(self[..].iter().map(value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> Value<D> for [V] {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Sequence) }
|
||||
fn is_sequence(&self) -> bool { true }
|
||||
fn len(&self) -> Option<usize> { Some(self.len()) }
|
||||
fn index(&self, i: usize) -> &dyn Value<D> { &self[i] }
|
||||
fn iter(&self) -> Option<Box<dyn Iterator<Item = &dyn Value<D>> + '_>> {
|
||||
Some(Box::new(self[..].iter().map(value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v, D: Domain, V: Value<D>> Value<D> for &'v [V] {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Sequence) }
|
||||
fn is_sequence(&self) -> bool { true }
|
||||
fn len(&self) -> Option<usize> { Some((self as &[V]).len()) }
|
||||
fn index(&self, i: usize) -> &dyn Value<D> { &self[i] }
|
||||
fn iter(&self) -> Option<Box<dyn Iterator<Item = &dyn Value<D>> + '_>> {
|
||||
Some(Box::new(self[..].iter().map(value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain> Value<D> for Set<Box<dyn Value<D>>> {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Set) }
|
||||
fn is_set(&self) -> bool { true }
|
||||
fn len(&self) -> Option<usize> { Some(self.len()) }
|
||||
fn has(&self, v: &dyn Value<D>) -> bool { self.contains(v) }
|
||||
fn iter(&self) -> Option<Box<dyn Iterator<Item = &dyn Value<D>> + '_>> {
|
||||
Some(Box::new(self.iter().map(value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> Value<D> for Map<Box<dyn Value<D>>, V> {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Dictionary) }
|
||||
fn is_dictionary(&self) -> bool { true }
|
||||
fn len(&self) -> Option<usize> { Some(self.len()) }
|
||||
fn has(&self, v: &dyn Value<D>) -> bool { self.contains_key(v) }
|
||||
fn get<'v>(&'v self, k: &'v dyn Value<D>) -> Option<&'v dyn Value<D>> {
|
||||
match Map::get(self, k) {
|
||||
Some(v) => Some(v),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
fn entries(&self) -> Option<Box<dyn Iterator<Item = (&dyn Value<D>, &dyn Value<D>)> + '_>> {
|
||||
Some(Box::new(self.iter().map(|(k,v)| (value(k), value(v)))))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct Record<V>(Vec<V> /* at least one element, for the label */);
|
||||
|
||||
impl<D: Domain, V: Value<D>> Value<D> for Record<V> {
|
||||
fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Record) }
|
||||
fn is_record(&self) -> bool { true }
|
||||
fn label(&self) -> Option<&dyn Value<D>> { Some(&self.0[0]) }
|
||||
fn len(&self) -> Option<usize> { Some(self.0.len() - 1) }
|
||||
fn index(&self, i: usize) -> &dyn Value<D> { &self.0[i + 1] }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Annotations<D: Domain, V: Value<D>>(V, Vec<Box<dyn Value<D>>>);
|
||||
|
||||
impl<D: Domain, V: Value<D>> Annotations<D, V> {
|
||||
pub fn value(&self) -> &dyn Value<D> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> Value<D> for Annotations<D, V> {
|
||||
fn value_class(&self) -> ValueClass { self.value().value_class() }
|
||||
fn as_boolean(&self) -> Option<bool> { self.value().as_boolean() }
|
||||
fn as_float(&self) -> Option<f32> { self.value().as_float() }
|
||||
fn as_double(&self) -> Option<f64> { self.value().as_double() }
|
||||
fn is_signed_integer(&self) -> bool { self.value().is_signed_integer() }
|
||||
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> { self.value().as_signed_integer() }
|
||||
fn as_string(&self) -> Option<Cow<'_, str>> { self.value().as_string() }
|
||||
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { self.value().as_bytestring() }
|
||||
fn as_symbol(&self) -> Option<Cow<'_, str>> { self.value().as_symbol() }
|
||||
fn is_record(&self) -> bool { self.value().is_record() }
|
||||
fn label(&self) -> Option<&dyn Value<D>> { self.value().label() }
|
||||
fn is_sequence(&self) -> bool { self.value().is_sequence() }
|
||||
fn len(&self) -> Option<usize> { self.value().len() }
|
||||
fn index(&self, i: usize) -> &dyn Value<D> { self.value().index(i) }
|
||||
fn is_set(&self) -> bool { self.value().is_set() }
|
||||
fn has(&self, v: &dyn Value<D>) -> bool { self.value().has(v) }
|
||||
fn is_dictionary(&self) -> bool { self.value().is_dictionary() }
|
||||
fn get<'v>(&'v self, k: &'v dyn Value<D>) -> Option<&'v dyn Value<D>> { self.value().get(k) }
|
||||
fn entries(&self) -> Option<Box<dyn Iterator<Item = (&dyn Value<D>, &dyn Value<D>)> + '_>> { self.value().entries() }
|
||||
fn is_embedded(&self) -> bool { self.value().is_embedded() }
|
||||
fn embedded(&self) -> Option<Cow<'_, D>> { self.value().embedded() }
|
||||
fn annotations(&self) -> Option<&[Box<dyn Value<D>>]> { Some(&self.1) }
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> PartialEq for Annotations<D, V> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.value().eq(&other.value())
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> Eq for Annotations<D, V> {}
|
||||
|
||||
impl<D: Domain, V: Value<D>> Hash for Annotations<D, V> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.value().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> PartialOrd for Annotations<D, V> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Domain, V: Value<D>> Ord for Annotations<D, V> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.value().cmp(&other.value())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod demo {
|
||||
use crate::*;
|
||||
|
||||
#[test] fn a() {
|
||||
let mut v: Map<Box<dyn Value<NoValue>>, 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());
|
||||
let w: &dyn Value<NoValue> = &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().unwrap() {
|
||||
println!("{:?} {:?} ==> {:?} {:?}", kk.value_class(), kk, vv.value_class(), vv);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
use num::bigint::BigInt;
|
||||
use num::traits::cast::ToPrimitive;
|
||||
use num::traits::sign::Signed;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::{Ord, Ordering, PartialOrd};
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
|
||||
// Invariant: if I128 can be used, it will be; otherwise, if U128 can
|
||||
// be used, it will be; otherwise, Big will be used.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum SignedIntegerRepr {
|
||||
I128(i128),
|
||||
U128(u128),
|
||||
Big(Box<BigInt>),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SignedInteger(SignedIntegerRepr);
|
||||
|
||||
impl fmt::Debug for SignedInteger {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "{}n", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SignedInteger {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self.repr() {
|
||||
SignedIntegerRepr::I128(i) => i.fmt(f),
|
||||
SignedIntegerRepr::U128(u) => u.fmt(f),
|
||||
SignedIntegerRepr::Big(n) => n.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for SignedInteger {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match self.repr() {
|
||||
SignedIntegerRepr::I128(i1) => match other.repr() {
|
||||
SignedIntegerRepr::I128(i2) => i1.cmp(i2),
|
||||
SignedIntegerRepr::U128(_) => if *i1 < 0 { Ordering::Less } else { Ordering::Greater },
|
||||
SignedIntegerRepr::Big(n) => if n.is_negative() { Ordering::Less } else { Ordering::Greater },
|
||||
},
|
||||
SignedIntegerRepr::U128(u1) => match other.repr() {
|
||||
SignedIntegerRepr::I128(_) => Ordering::Greater,
|
||||
SignedIntegerRepr::U128(u2) => u1.cmp(u2),
|
||||
SignedIntegerRepr::Big(n) => if n.is_positive() { Ordering::Less } else { Ordering::Greater },
|
||||
},
|
||||
SignedIntegerRepr::Big(n1) => match other.repr() {
|
||||
SignedIntegerRepr::I128(_) |
|
||||
SignedIntegerRepr::U128(_) => if n1.is_negative() { Ordering::Less } else { Ordering::Greater },
|
||||
SignedIntegerRepr::Big(n2) => n1.cmp(n2),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for SignedInteger {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl SignedInteger {
|
||||
pub fn repr(&self) -> &SignedIntegerRepr {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn is_i(&self) -> bool {
|
||||
matches!(self.0, SignedIntegerRepr::I128(_))
|
||||
}
|
||||
|
||||
pub fn is_u(&self) -> bool {
|
||||
matches!(self.0, SignedIntegerRepr::U128(_))
|
||||
}
|
||||
|
||||
pub fn is_big(&self) -> bool {
|
||||
matches!(self.0, SignedIntegerRepr::Big(_))
|
||||
}
|
||||
}
|
||||
|
||||
//--
|
||||
|
||||
macro_rules! map_integral_type_to_signed_integer {
|
||||
($iN:ident, $uN:ident) => {
|
||||
impl From<$iN> for SignedInteger {
|
||||
fn from(v: $iN) -> Self {
|
||||
SignedInteger(SignedIntegerRepr::I128(v.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$uN> for SignedInteger {
|
||||
fn from(v: $uN) -> Self {
|
||||
SignedInteger(SignedIntegerRepr::I128(v.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SignedInteger> for $iN {
|
||||
type Error = ();
|
||||
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
||||
i128::try_from(v)?.try_into().map_err(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SignedInteger> for $uN {
|
||||
type Error = ();
|
||||
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
||||
u128::try_from(v)?.try_into().map_err(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map_integral_type_to_signed_integer!(i8, u8);
|
||||
map_integral_type_to_signed_integer!(i16, u16);
|
||||
map_integral_type_to_signed_integer!(i32, u32);
|
||||
map_integral_type_to_signed_integer!(i64, u64);
|
||||
|
||||
//--
|
||||
|
||||
impl From<i128> for SignedInteger {
|
||||
fn from(v: i128) -> Self {
|
||||
SignedInteger(SignedIntegerRepr::I128(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for SignedInteger {
|
||||
fn from(v: u128) -> Self {
|
||||
if let Ok(w) = v.try_into() {
|
||||
SignedInteger(SignedIntegerRepr::I128(w))
|
||||
} else {
|
||||
SignedInteger(SignedIntegerRepr::U128(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SignedInteger> for i128 {
|
||||
type Error = ();
|
||||
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
||||
match v.repr() {
|
||||
SignedIntegerRepr::I128(i) => Ok(*i),
|
||||
SignedIntegerRepr::U128(_) => Err(()),
|
||||
SignedIntegerRepr::Big(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SignedInteger> for u128 {
|
||||
type Error = ();
|
||||
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
||||
match v.repr() {
|
||||
SignedIntegerRepr::I128(i) => i.to_u128().ok_or(()),
|
||||
SignedIntegerRepr::U128(u) => Ok(*u),
|
||||
SignedIntegerRepr::Big(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--
|
||||
|
||||
impl From<BigInt> for SignedInteger {
|
||||
fn from(v: BigInt) -> Self {
|
||||
Self::from(Cow::Owned(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a SignedInteger> for BigInt {
|
||||
fn from(v: &'a SignedInteger) -> Self {
|
||||
match v.repr() {
|
||||
SignedIntegerRepr::I128(i) => BigInt::from(*i),
|
||||
SignedIntegerRepr::U128(u) => BigInt::from(*u),
|
||||
SignedIntegerRepr::Big(n) => *n.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--
|
||||
|
||||
impl<'a> From<Cow<'a, BigInt>> for SignedInteger {
|
||||
fn from(v: Cow<'a, BigInt>) -> Self {
|
||||
if let Some(w) = v.to_i128() {
|
||||
SignedInteger(SignedIntegerRepr::I128(w))
|
||||
} else if let Some(w) = v.to_u128() {
|
||||
SignedInteger(SignedIntegerRepr::U128(w))
|
||||
} else {
|
||||
SignedInteger(SignedIntegerRepr::Big(Box::new(v.into_owned())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a SignedInteger> for Cow<'a, BigInt> {
|
||||
fn from(v: &'a SignedInteger) -> Self {
|
||||
match v.repr() {
|
||||
SignedIntegerRepr::I128(i) => Cow::Owned(BigInt::from(*i)),
|
||||
SignedIntegerRepr::U128(u) => Cow::Owned(BigInt::from(*u)),
|
||||
SignedIntegerRepr::Big(n) => Cow::Borrowed(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--
|
||||
|
||||
impl From<isize> for SignedInteger {
|
||||
fn from(v: isize) -> Self {
|
||||
SignedInteger(SignedIntegerRepr::I128(v as i128))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for SignedInteger {
|
||||
fn from(v: usize) -> Self {
|
||||
SignedInteger(SignedIntegerRepr::U128(v as u128))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SignedInteger> for isize {
|
||||
type Error = ();
|
||||
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
||||
i128::try_from(v)?.try_into().map_err(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SignedInteger> for usize {
|
||||
type Error = ();
|
||||
fn try_from(v: &SignedInteger) -> Result<Self, Self::Error> {
|
||||
u128::try_from(v)?.try_into().map_err(|_| ())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue