copy_via, more library

This commit is contained in:
Tony Garnock-Jones 2022-11-04 15:24:01 +01:00
parent 228f34c699
commit 274c8b617d
2 changed files with 133 additions and 6 deletions

View File

@ -32,6 +32,8 @@ pub use repr::Record;
pub use repr::Set;
pub use repr::Symbol;
pub use repr::Value;
pub use repr::copy_via;
pub use repr::iovalue;
pub use repr::owned;
pub use repr::value;
pub use signed_integer::SignedInteger;
@ -92,3 +94,84 @@ mod demo {
// }
}
}
#[cfg(test)]
mod test_domain {
use std::io;
use crate::*;
#[derive(Debug, Hash, Clone, Ord, PartialEq, Eq, PartialOrd)]
pub enum Dom {
One,
Two,
}
impl Domain for Dom {
type Decode = DebugDomainCodec;
type Encode = DebugDomainCodec;
}
impl std::str::FromStr for Dom {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"One" => Ok(Dom::One),
"Two" => Ok(Dom::Two),
_ => Err(io::Error::new(io::ErrorKind::Other, "cannot parse preserves test domain")),
}
}
}
struct DomCodec;
impl DomainDecode<Dom> for DomCodec {
fn decode_embedded<'de, R: Reader<'de> + ?Sized>(
&mut self,
r: &mut R,
_read_annotations: bool,
) -> io::Result<Dom> {
let v = r.next_iovalue(false)?;
if v.as_bytestring().is_some() {
Ok(Dom::One)
} else {
Ok(Dom::Two)
}
}
}
impl DomainEncode<Dom> for DomCodec {
fn encode_embedded(
&mut self,
w: &mut dyn Writer,
d: &Dom,
) -> io::Result<()> {
match d {
Dom::One => Bytes::new(vec![255, 255, 255, 255]).write(w, self),
Dom::Two => Symbol::new(&format!("Dom::{:?}", d)).write(w, self),
}
}
}
fn dom_as_preserves(v: &Dom) -> io::Result<PlainValue<'static, IOValue>> {
Ok(match v {
Dom::One => owned(Bytes::new(vec![255, 255, 255, 255])),
Dom::Two => owned(Symbol::new(format!("Dom::{:?}", v))),
})
}
#[test] fn test_one() {
let v = owned(vec![owned(1),
owned(Embedded::new(Dom::One)),
owned(2)]);
assert_eq!(PackedWriter::encode_iovalue(&iovalue(copy_via(&v, &mut dom_as_preserves).unwrap())).unwrap(),
[0xb5, 0x91, 0xb2, 0x04, 255, 255, 255, 255, 0x92, 0x84]);
}
#[test] fn test_two() {
let v = owned(vec![owned(1),
owned(Embedded::new(Dom::Two)),
owned(2)]);
assert_eq!(PackedWriter::encode_iovalue(&iovalue(copy_via(&v, &mut dom_as_preserves).unwrap())).unwrap(),
[0xb5, 0x91, 0xb3, 0x08, 68, 111, 109, 58, 58, 84, 119, 111, 0x92, 0x84]);
}
}

View File

@ -1,5 +1,6 @@
use bytemuck::TransparentWrapper;
use std::any::Any;
use std::borrow::{Cow, Borrow};
use std::cmp::Ordering;
use std::fmt::Debug;
@ -25,6 +26,7 @@ use crate::domain::{NoEmbeddedDomainCodec, DomainEncode, IOValueDomainCodec};
use super::float::{eq_f32, eq_f64, cmp_f32, cmp_f64};
pub type PlainValue<'a, D = IOValue> = Box<dyn Value<D> + 'a>;
pub type ArcValue<D = IOValue> = Arc<dyn Value<D>>;
/// Atomic values from the specification.
pub trait Value<D: Domain> {
@ -65,6 +67,8 @@ pub trait Value<D: Domain> {
fn embedded(&self) -> Cow<'_, D> { panic!("Not an embedded value") }
fn annotations(&self) -> Option<&[IOValue]> { None }
fn specialized(&self) -> Option<&dyn Any> { None }
}
pub fn value<D: Domain, V: Value<D>>(v: &V) -> &dyn Value<D> {
@ -79,6 +83,40 @@ pub fn iovalue<V: Value<IOValue> + 'static>(v: V) -> IOValue {
IOValue(Arc::new(v))
}
pub fn copy_via<D: Domain, E: Domain + 'static, F, Err>(
v: &dyn Value<D>,
f: &mut F,
) -> Result<PlainValue<'static, E>, Err>
where
F: FnMut(&D) -> Result<PlainValue<'static, E>, Err>
{
match v.value_class() {
ValueClass::Atomic(a) => Ok(match a {
AtomClass::Boolean => owned(v.as_boolean().unwrap()),
AtomClass::Float => owned(v.as_float().unwrap()),
AtomClass::Double => owned(v.as_double().unwrap()),
AtomClass::SignedInteger => owned(v.as_signed_integer().unwrap()),
AtomClass::String => owned(v.as_string().unwrap().into_owned()),
AtomClass::ByteString => owned(Bytes(v.as_bytestring().unwrap().into_owned())),
AtomClass::Symbol => owned(Symbol(v.as_symbol().unwrap().into_owned())),
}),
ValueClass::Compound(c) => Ok(match c {
CompoundClass::Sequence =>
owned(v.iter().map(|w| copy_via(w, f)).collect::<Result<Vec<_>, _>>()?),
CompoundClass::Set =>
owned(v.iter().map(|w| copy_via(w, f)).collect::<Result<Set<_>, _>>()?),
CompoundClass::Record =>
owned(Record::new(
copy_via(v.label(), f)?,
v.iter().map(|w| copy_via(w, f)).collect::<Result<Vec<_>, _>>()?)),
CompoundClass::Dictionary =>
owned(v.entries().map(|(k, w)| Ok((copy_via(k, f)?, copy_via(w, f)?)))
.collect::<Result<Map<_, _>, _>>()?),
}),
ValueClass::Embedded => f(&v.embedded()),
}
}
impl<'a, D: Domain + 'static> From<&'a dyn Value<D>> for PlainValue<'static, D> {
fn from(v: &'a dyn Value<D>) -> Self {
v.value_clone()
@ -490,7 +528,13 @@ impl<D: Domain> Value<D> for String {
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Bytes<T: AsRef<[u8]>>(T);
pub struct Bytes<T: AsRef<[u8]> + Debug = Vec<u8>>(T);
impl<T: AsRef<[u8]> + Debug> Bytes<T> {
pub fn new(t: T) -> Self {
Bytes(t)
}
}
impl<T: AsRef<[u8]> + Debug, D: Domain> Value<D> for Bytes<T> {
fn write(&self, w: &mut dyn Writer, _enc: &mut dyn DomainEncode<D>) -> io::Result<()> { w.write_bytes(self.0.as_ref()) }
@ -504,8 +548,8 @@ impl<T: AsRef<[u8]> + Debug, D: Domain> Value<D> for Bytes<T> {
pub struct Symbol<T: AsRef<str> + Debug = String>(T);
impl<T: AsRef<str> + Debug> Symbol<T> {
pub fn new<R: Into<T>>(t: R) -> Self {
Symbol(t.into())
pub fn new(t: T) -> Self {
Symbol(t)
}
}
@ -702,8 +746,8 @@ impl<'k, D: Domain, V: Value<D>, K: for<'a> Borrow<Key<'a, D>> + Ord + 'k> Value
pub struct Embedded<D: Domain>(D);
impl<D: Domain> Embedded<D> {
pub fn new<E: Into<D>>(d: E) -> Self {
Embedded(d.into())
pub fn new(d: D) -> Self {
Embedded(d)
}
pub fn embedded_value(&self) -> &D {
@ -820,7 +864,7 @@ impl<D: Domain, V: Value<D>> Ord for Annotations<D, V> {
}
#[derive(Clone, Eq, Hash, PartialOrd, Ord)]
pub struct IOValue(Arc<dyn Value<IOValue>>);
pub struct IOValue(ArcValue);
impl Debug for IOValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {