diff --git a/implementations/rust/Cargo.toml b/implementations/rust/Cargo.toml index fdc97da..f1c13ae 100644 --- a/implementations/rust/Cargo.toml +++ b/implementations/rust/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "oo", "preserves", "preserves-path", "preserves-schema", diff --git a/implementations/rust/oo/Cargo.toml b/implementations/rust/oo/Cargo.toml new file mode 100644 index 0000000..0b4dad1 --- /dev/null +++ b/implementations/rust/oo/Cargo.toml @@ -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 diff --git a/implementations/rust/oo/src/float.rs b/implementations/rust/oo/src/float.rs new file mode 100644 index 0000000..ff1f9cf --- /dev/null +++ b/implementations/rust/oo/src/float.rs @@ -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 for Float { + fn from(v: f32) -> Self { + Float(v) + } +} + +impl From for f32 { + fn from(v: Float) -> Self { + v.0 + } +} + +impl Hash for Float { + fn hash(&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 { + Some(self.cmp(other)) + } +} + +impl Eq for Float {} + +impl From for Double { + fn from(v: f64) -> Self { + Double(v) + } +} + +impl From for f64 { + fn from(v: Double) -> Self { + v.0 + } +} + +impl Hash for Double { + fn hash(&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 { + Some(self.cmp(other)) + } +} + +impl Eq for Double {} diff --git a/implementations/rust/oo/src/lib.rs b/implementations/rust/oo/src/lib.rs new file mode 100644 index 0000000..b724062 --- /dev/null +++ b/implementations/rust/oo/src/lib.rs @@ -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: 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) -> Option<&dyn Value> { None } + + fn is_sequence(&self) -> bool { false } + fn len(&self) -> Option { None } + fn index(&self, _i: usize) -> &dyn Value { panic!("Not a sequence") } + fn iter(&self) -> Option> + '_>> { None } + + fn is_set(&self) -> bool { false } + fn has(&self, _v: &dyn Value) -> bool { false } + + fn is_dictionary(&self) -> bool { false } + fn get<'v>(&'v self, _k: &'v dyn Value) -> Option<&'v dyn Value> { None } + fn entries(&self) -> Option, &dyn Value)> + '_>> { None } + + fn is_embedded(&self) -> bool { false } + fn embedded(&self) -> Option> { None } + + fn annotations(&self) -> Option<&[Box>]> { None } +} + +pub fn value>(v: &V) -> &dyn Value { + v +} + +impl<'a, D: Domain> Value for &'a dyn Value { + 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) -> Option<&dyn Value> { (*self).label() } + fn is_sequence(&self) -> bool { (*self).is_sequence() } + fn len(&self) -> Option { (*self).len() } + fn index(&self, i: usize) -> &dyn Value { (*self).index(i) } + 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<'v>(&'v self, k: &'v dyn Value) -> Option<&'v dyn Value> { (*self).get(k) } + fn entries(&self) -> Option, &dyn Value)> + '_>> { (*self).entries() } + fn is_embedded(&self) -> bool { (*self).is_embedded() } + fn embedded(&self) -> Option> { (*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) -> Option<&dyn Value> { self.as_ref().label() } + fn is_sequence(&self) -> bool { self.as_ref().is_sequence() } + fn len(&self) -> Option { self.as_ref().len() } + fn index(&self, i: usize) -> &dyn Value { self.as_ref().index(i) } + 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<'v>(&'v self, k: &'v dyn Value) -> Option<&'v dyn Value> { self.as_ref().get(k) } + fn entries(&self) -> Option, &dyn Value)> + '_>> { self.as_ref().entries() } + fn is_embedded(&self) -> bool { self.as_ref().is_embedded() } + fn embedded(&self) -> Option> { 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().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 + '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 + '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 + '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(Cow::Owned((*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<'a, D: Domain> Value for &'a 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) -> Option { Some(self.len()) } + fn index(&self, i: usize) -> &dyn Value { &self[i] } + fn iter(&self) -> Option> + '_>> { + Some(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) -> Option { Some(self.len()) } + fn index(&self, i: usize) -> &dyn Value { &self[i] } + fn iter(&self) -> Option> + '_>> { + Some(Box::new(self[..].iter().map(value))) + } +} + +impl<'v, D: Domain, V: Value> Value for &'v [V] { + fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Sequence) } + fn is_sequence(&self) -> bool { true } + fn len(&self) -> Option { Some((self as &[V]).len()) } + fn index(&self, i: usize) -> &dyn Value { &self[i] } + fn iter(&self) -> Option> + '_>> { + Some(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) -> Option { Some(self.len()) } + fn has(&self, v: &dyn Value) -> bool { self.contains(v) } + fn iter(&self) -> Option> + '_>> { + Some(Box::new(self.iter().map(value))) + } +} + +impl> Value for Map>, V> { + fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Dictionary) } + fn is_dictionary(&self) -> bool { true } + fn len(&self) -> Option { Some(self.len()) } + fn has(&self, v: &dyn Value) -> bool { self.contains_key(v) } + fn get<'v>(&'v self, k: &'v dyn Value) -> Option<&'v dyn Value> { + match Map::get(self, k) { + Some(v) => Some(v), + None => None, + } + } + fn entries(&self) -> Option, &dyn Value)> + '_>> { + Some(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> Value for Record { + fn value_class(&self) -> ValueClass { ValueClass::Compound(CompoundClass::Record) } + fn is_record(&self) -> bool { true } + fn label(&self) -> Option<&dyn Value> { Some(&self.0[0]) } + fn len(&self) -> Option { Some(self.0.len() - 1) } + fn index(&self, i: usize) -> &dyn Value { &self.0[i + 1] } +} + +#[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) -> Option<&dyn Value> { self.value().label() } + fn is_sequence(&self) -> bool { self.value().is_sequence() } + fn len(&self) -> Option { self.value().len() } + fn index(&self, i: usize) -> &dyn Value { self.value().index(i) } + 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<'v>(&'v self, k: &'v dyn Value) -> Option<&'v dyn Value> { self.value().get(k) } + fn entries(&self) -> Option, &dyn Value)> + '_>> { self.value().entries() } + fn is_embedded(&self) -> bool { self.value().is_embedded() } + fn embedded(&self) -> Option> { 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::*; + + #[test] fn a() { + 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()); + 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().unwrap() { + println!("{:?} {:?} ==> {:?} {:?}", kk.value_class(), kk, vv.value_class(), vv); + } + } +} diff --git a/implementations/rust/oo/src/signed_integer.rs b/implementations/rust/oo/src/signed_integer.rs new file mode 100644 index 0000000..9c753e5 --- /dev/null +++ b/implementations/rust/oo/src/signed_integer.rs @@ -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), +} + +#[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 { + 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 { + i128::try_from(v)?.try_into().map_err(|_| ()) + } + } + + impl TryFrom<&SignedInteger> for $uN { + type Error = (); + fn try_from(v: &SignedInteger) -> Result { + 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 for SignedInteger { + fn from(v: i128) -> Self { + SignedInteger(SignedIntegerRepr::I128(v)) + } +} + +impl From 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 { + 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 { + match v.repr() { + SignedIntegerRepr::I128(i) => i.to_u128().ok_or(()), + SignedIntegerRepr::U128(u) => Ok(*u), + SignedIntegerRepr::Big(_) => Err(()), + } + } +} + +//-- + +impl From 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> 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 for SignedInteger { + fn from(v: isize) -> Self { + SignedInteger(SignedIntegerRepr::I128(v as i128)) + } +} + +impl From 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 { + i128::try_from(v)?.try_into().map_err(|_| ()) + } +} + +impl TryFrom<&SignedInteger> for usize { + type Error = (); + fn try_from(v: &SignedInteger) -> Result { + u128::try_from(v)?.try_into().map_err(|_| ()) + } +}