More basics

This commit is contained in:
Tony Garnock-Jones 2022-11-02 17:17:46 +01:00
parent c93fea0545
commit e7f559c944
2 changed files with 76 additions and 119 deletions

View File

@ -1,94 +1,25 @@
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)
}
pub fn cmp_f32(a: f32, b: f32) -> Ordering {
let mut a: u32 = a.to_bits();
let mut b: u32 = b.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 From<Float> for f32 {
fn from(v: Float) -> Self {
v.0
}
pub fn eq_f32(a: f32, b: f32) -> bool {
a.to_bits() == b.to_bits()
}
impl Hash for Float {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.to_bits().hash(state);
}
pub fn cmp_f64(a: f64, b: f64) -> Ordering {
let mut a: u64 = a.to_bits();
let mut b: u64 = b.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 PartialEq for Float {
fn eq(&self, other: &Self) -> bool {
self.0.to_bits() == other.0.to_bits()
}
pub fn eq_f64(a: f64, b: f64) -> bool {
a.to_bits() == b.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 {}

View File

@ -1,4 +1,5 @@
use bytemuck::TransparentWrapper;
use float::{eq_f32, eq_f64, cmp_f32, cmp_f64};
use std::borrow::{Cow, Borrow};
use std::cmp::Ordering;
@ -12,8 +13,6 @@ 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.
@ -205,9 +204,9 @@ impl<'a, D: Domain> PartialEq for dyn Value<D> + 'a {
AtomClass::Boolean =>
self.as_boolean().unwrap() == other.as_boolean().unwrap(),
AtomClass::Float =>
Float(self.as_float().unwrap()) == Float(other.as_float().unwrap()),
eq_f32(self.as_float().unwrap(), other.as_float().unwrap()),
AtomClass::Double =>
Double(self.as_double().unwrap()) == Double(other.as_double().unwrap()),
eq_f64(self.as_double().unwrap(), other.as_double().unwrap()),
AtomClass::SignedInteger =>
self.as_signed_integer().unwrap() == other.as_signed_integer().unwrap(),
AtomClass::String =>
@ -270,9 +269,9 @@ impl<'a, D: Domain> Ord for dyn Value<D> + 'a {
AtomClass::Boolean =>
self.as_boolean().cmp(&other.as_boolean()),
AtomClass::Float =>
Float(self.as_float().unwrap()).cmp(&Float(other.as_float().unwrap())),
cmp_f32(self.as_float().unwrap(), other.as_float().unwrap()),
AtomClass::Double =>
Double(self.as_double().unwrap()).cmp(&Double(other.as_double().unwrap())),
cmp_f64(self.as_double().unwrap(), other.as_double().unwrap()),
AtomClass::SignedInteger =>
self.as_signed_integer().cmp(&other.as_signed_integer()),
AtomClass::String =>
@ -332,10 +331,16 @@ impl<D: Domain> Value<D> for u64 {
}
}
impl<D: Domain> Value<D> for Float {
impl<D: Domain> Value<D> for f32 {
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) }
fn as_float(&self) -> Option<f32> { Some(*self) }
fn as_double(&self) -> Option<f64> { Some(*self as f64) }
}
impl<D: Domain> Value<D> for f64 {
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Float) }
fn as_float(&self) -> Option<f32> { Some(*self as f32) }
fn as_double(&self) -> Option<f64> { Some(*self) }
}
impl<D: Domain> Value<D> for str {
@ -348,6 +353,46 @@ impl<D: Domain> Value<D> for String {
fn as_string(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self)) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Bytes<T: AsRef<[u8]>>(T);
impl<T: AsRef<[u8]> + Debug, D: Domain> Value<D> for Bytes<T> {
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::ByteString) }
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> { Some(Cow::Borrowed(self.0.as_ref())) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Symbol<T: AsRef<str> + Debug>(T);
impl<T: AsRef<str> + Debug, D: Domain> Value<D> for Symbol<T> {
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Symbol) }
fn as_symbol(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self.0.as_ref())) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Record<V>(Vec<V> /* at least one element, for the label */);
impl<V> Record<V> {
pub fn new(label: V, mut fields: Vec<V>) -> Self {
fields.insert(0, label);
Record(fields)
}
}
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) -> &dyn Value<D> { &self.0[0] }
fn len(&self) -> usize { self.0.len() - 1 }
fn index(&self, i: usize) -> &dyn Value<D> { &self.0[i + 1] }
fn iter(&self) -> Box<dyn Iterator<Item = &dyn Value<D>> + '_> {
Box::new(self.0[1..].iter().map(value))
}
}
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 }
@ -410,32 +455,13 @@ impl<D: Domain, V: Value<D>> Value<D> for Map<Box<dyn Value<D>>, V> {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Record<V>(Vec<V> /* at least one element, for the label */);
#[repr(transparent)]
pub struct Embedded<D: Domain>(D);
impl<V> Record<V> {
pub fn new(label: V, mut fields: Vec<V>) -> Self {
fields.insert(0, label);
Record(fields)
}
}
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) -> &dyn Value<D> { &self.0[0] }
fn len(&self) -> usize { self.0.len() - 1 }
fn index(&self, i: usize) -> &dyn Value<D> { &self.0[i + 1] }
fn iter(&self) -> Box<dyn Iterator<Item = &dyn Value<D>> + '_> {
Box::new(self.0[1..].iter().map(value))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Symbol<T: AsRef<str> + Debug>(T);
impl<T: AsRef<str> + Debug, D: Domain> Value<D> for Symbol<T> {
fn value_class(&self) -> ValueClass { ValueClass::Atomic(AtomClass::Symbol) }
fn as_symbol(&self) -> Option<Cow<'_, str>> { Some(Cow::Borrowed(self.0.as_ref())) }
impl<D: Domain> Value<D> for Embedded<D> {
fn value_class(&self) -> ValueClass { ValueClass::Embedded }
fn is_embedded(&self) -> bool { true }
fn embedded(&self) -> Cow<'_, D> { Cow::Borrowed(&self.0) }
}
#[derive(Debug)]