901 lines
31 KiB
Rust
901 lines
31 KiB
Rust
use std::borrow::Borrow;
|
|
use std::borrow::Cow;
|
|
use std::cmp::Ordering;
|
|
use std::fmt::Debug;
|
|
use std::hash::Hash;
|
|
use std::hash::Hasher;
|
|
use std::io;
|
|
use std::str::FromStr;
|
|
use std::sync::Arc;
|
|
|
|
use bytemuck::TransparentWrapper;
|
|
|
|
use crate::AtomClass;
|
|
use crate::BinarySource;
|
|
use crate::BytesBinarySource;
|
|
use crate::CompoundClass;
|
|
use crate::DefaultDomainCodec;
|
|
use crate::Domain;
|
|
use crate::DomainDecode;
|
|
use crate::DomainEncode;
|
|
use crate::Error;
|
|
use crate::ExpectedKind;
|
|
use crate::IOValueDomainDecode;
|
|
use crate::IOValueDomainEncode;
|
|
use crate::Reader;
|
|
use crate::SignedInteger;
|
|
use crate::ValueClass;
|
|
use crate::ValueImpl;
|
|
use crate::ValueReader;
|
|
use crate::Writer;
|
|
use crate::boundary as B;
|
|
use crate::error::ReadError;
|
|
use crate::error::io_eof;
|
|
use crate::impl_value_methods;
|
|
|
|
pub use std::collections::BTreeSet as Set;
|
|
pub use std::collections::BTreeMap as Map;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Atom<'a> {
|
|
Boolean(bool),
|
|
Float(f32),
|
|
Double(f64),
|
|
SignedInteger(Cow<'a, SignedInteger>),
|
|
String(Cow<'a, str>),
|
|
ByteString(Cow<'a, [u8]>),
|
|
Symbol(Cow<'a, str>),
|
|
}
|
|
|
|
impl<'a> Atom<'a> {
|
|
pub fn into_owned(self) -> Atom<'static> {
|
|
match self {
|
|
Atom::Boolean(b) => Atom::Boolean(b),
|
|
Atom::Float(f) => Atom::Float(f),
|
|
Atom::Double(d) => Atom::Double(d),
|
|
Atom::SignedInteger(i) => Atom::SignedInteger(i.to_owned()),
|
|
Atom::String(s) => Atom::String(s.to_owned()),
|
|
Atom::ByteString(bs) => Atom::ByteString(bs.to_owned()),
|
|
Atom::Symbol(s) => Atom::Symbol(s.to_owned()),
|
|
}
|
|
}
|
|
|
|
pub fn write(&self, w: &mut dyn Writer) -> io::Result<()> {
|
|
match self {
|
|
Atom::Boolean(b) => w.write_bool(*b),
|
|
Atom::Float(f) => w.write_f32(*f),
|
|
Atom::Double(d) => w.write_f64(*d),
|
|
Atom::SignedInteger(i) => w.write_signed_integer(i),
|
|
Atom::String(s) => w.write_string(s),
|
|
Atom::ByteString(bs) => w.write_bytes(bs),
|
|
Atom::Symbol(s) => w.write_symbol(s),
|
|
}
|
|
}
|
|
|
|
pub fn symbol<W: Into<Cow<'a, str>>>(v: W) -> Self {
|
|
Atom::Symbol(v.into())
|
|
}
|
|
|
|
pub fn try_into_symbol(self) -> Result<Cow<'a, str>, ExpectedKind> {
|
|
match self {
|
|
Atom::Symbol(s) => Ok(s),
|
|
_ => Err(ExpectedKind::Symbol),
|
|
}
|
|
}
|
|
|
|
pub fn as_symbol(self) -> Result<&'a str, ExpectedKind> {
|
|
match self {
|
|
Atom::Symbol(s) => Ok(s.as_ref()),
|
|
_ => Err(ExpectedKind::Symbol),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'r, 'a> From<&'r Atom<'a>> for AtomClass {
|
|
fn from(a: &'r Atom<'a>) -> Self {
|
|
match a {
|
|
Atom::Boolean(_) => AtomClass::Boolean,
|
|
Atom::Float(_) => AtomClass::Float,
|
|
Atom::Double(_) => AtomClass::Double,
|
|
Atom::SignedInteger(_) => AtomClass::SignedInteger,
|
|
Atom::String(_) => AtomClass::String,
|
|
Atom::ByteString(_) => AtomClass::ByteString,
|
|
Atom::Symbol(_) => AtomClass::Symbol,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<bool> for Atom<'a> { fn from(v: bool) -> Self { Atom::Boolean(v) } }
|
|
impl<'a> From<f32> for Atom<'a> { fn from(v: f32) -> Self { Atom::Float(v) } }
|
|
impl<'a> From<f64> for Atom<'a> { fn from(v: f64) -> Self { Atom::Double(v) } }
|
|
impl<'a> From<&'a SignedInteger> for Atom<'a> { fn from(v: &'a SignedInteger) -> Self { Atom::SignedInteger(Cow::Borrowed(v)) } }
|
|
impl<'a> From<SignedInteger> for Atom<'a> { fn from(v: SignedInteger) -> Self { Atom::SignedInteger(Cow::Owned(v)) } }
|
|
impl<'a> From<&'a str> for Atom<'a> { fn from(v: &'a str) -> Self { Atom::String(Cow::Borrowed(v)) } }
|
|
impl<'a> From<String> for Atom<'a> { fn from(v: String) -> Self { Atom::String(Cow::Owned(v)) } }
|
|
impl<'a> From<&'a [u8]> for Atom<'a> { fn from(v: &'a [u8]) -> Self { Atom::ByteString(Cow::Borrowed(v)) } }
|
|
impl<'a> From<Vec<u8>> for Atom<'a> { fn from(v: Vec<u8>) -> Self { Atom::ByteString(Cow::Owned(v)) } }
|
|
|
|
impl<'a> From<i8> for Atom<'a> { fn from(i: i8) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<u8> for Atom<'a> { fn from(i: u8) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<i16> for Atom<'a> { fn from(i: i16) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<u16> for Atom<'a> { fn from(i: u16) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<i32> for Atom<'a> { fn from(i: i32) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<u32> for Atom<'a> { fn from(i: u32) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<i64> for Atom<'a> { fn from(i: i64) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<u64> for Atom<'a> { fn from(i: u64) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<i128> for Atom<'a> { fn from(i: i128) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<u128> for Atom<'a> { fn from(i: u128) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<isize> for Atom<'a> { fn from(i: isize) -> Self { SignedInteger::from(i).into() } }
|
|
impl<'a> From<usize> for Atom<'a> { fn from(i: usize) -> Self { SignedInteger::from(i).into() } }
|
|
|
|
macro_rules! from_atom_ref_impl {
|
|
($t:ty, $p:pat, $e:expr, $errty:ty, $err:expr) => {
|
|
impl<'r, 'a> TryFrom<&'r Atom<'a>> for $t {
|
|
type Error = $errty;
|
|
fn try_from(value: &'r Atom<'a>) -> Result<Self, Self::Error> {
|
|
match value {
|
|
$p => Ok($e),
|
|
_ => Err($err),
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
from_atom_ref_impl!(bool, Atom::Boolean(b), *b, ExpectedKind, ExpectedKind::Boolean);
|
|
from_atom_ref_impl!(f32, Atom::Float(f), *f, ExpectedKind, ExpectedKind::Float);
|
|
from_atom_ref_impl!(f64, Atom::Double(d), *d, ExpectedKind, ExpectedKind::Double);
|
|
from_atom_ref_impl!(&'a SignedInteger, Atom::SignedInteger(i), i.as_ref(), ExpectedKind, ExpectedKind::SignedInteger);
|
|
from_atom_ref_impl!(&'a str, Atom::String(s), s.as_ref(), ExpectedKind, ExpectedKind::String);
|
|
from_atom_ref_impl!(&'a [u8], Atom::ByteString(bs), bs.as_ref(), ExpectedKind, ExpectedKind::ByteString);
|
|
|
|
from_atom_ref_impl!(i8, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(u8, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(i16, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(u16, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(i32, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(u32, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(i64, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(u64, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(i128, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(u128, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(isize, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
from_atom_ref_impl!(usize, Atom::SignedInteger(i), i.as_ref().try_into()?, Error, Error::Expected(ExpectedKind::SignedInteger));
|
|
|
|
macro_rules! from_atom_val_impl {
|
|
($t:ty, $p:pat, $e:expr, $err:expr) => {
|
|
impl<'a> TryFrom<Atom<'a>> for $t {
|
|
type Error = ExpectedKind;
|
|
fn try_from(value: Atom<'a>) -> Result<Self, Self::Error> {
|
|
match value {
|
|
$p => Ok($e),
|
|
_ => Err($err),
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
from_atom_val_impl!(bool, Atom::Boolean(b), b, ExpectedKind::Boolean);
|
|
from_atom_val_impl!(f32, Atom::Float(f), f, ExpectedKind::Float);
|
|
from_atom_val_impl!(f64, Atom::Double(d), d, ExpectedKind::Double);
|
|
from_atom_val_impl!(Cow<'a, SignedInteger>, Atom::SignedInteger(i), i, ExpectedKind::SignedInteger);
|
|
from_atom_val_impl!(Cow<'a, str>, Atom::String(s), s, ExpectedKind::String);
|
|
from_atom_val_impl!(Cow<'a, [u8]>, Atom::ByteString(bs), bs, ExpectedKind::ByteString);
|
|
|
|
pub type ShellHandle<'a, D> = Arc<Shell<'a, D>>;
|
|
pub enum Shell<'de, D: Domain<'de>> {
|
|
Atom(Atom<'de>),
|
|
Record(Record<ShellHandle<'de, D>>),
|
|
Sequence(Vec<ShellHandle<'de, D>>),
|
|
Set(Set<ShellHandle<'de, D>>),
|
|
Dictionary(Map<ShellHandle<'de, D>, ShellHandle<'de, D>>),
|
|
Embedded(D),
|
|
Annotated(Annotations<'de, Self>),
|
|
}
|
|
|
|
impl<'de, D: Domain<'de>> Shell<'de, D> {
|
|
pub fn record(label: ShellHandle<'de, D>, fields: Vec<ShellHandle<'de, D>>) -> Self {
|
|
Shell::Record(Record::new(label, fields))
|
|
}
|
|
|
|
pub fn symbol<S: Into<Cow<'de, str>>>(s: S) -> Self {
|
|
Shell::Atom(Atom::symbol(s))
|
|
}
|
|
|
|
pub fn embedded(d: D) -> Self {
|
|
Shell::Embedded(d)
|
|
}
|
|
}
|
|
|
|
impl<'de, D: Domain<'de>> ValueReader<'de> for Shell<'de, D> {
|
|
type Impl = Shell<'de, D>;
|
|
|
|
fn read_impl<R: Reader<'de> + ?Sized, Dec: DomainDecode<'de, <Self::Impl as ValueImpl<'de>>::Embedded>>(
|
|
r: &mut R,
|
|
read_annotations: bool,
|
|
dec: &mut Dec,
|
|
) -> Result<Self::Impl, ReadError> {
|
|
Ok(read(r, read_annotations, dec)?)
|
|
}
|
|
|
|
fn read_iovalue<R: Reader<'de> + ?Sized>(
|
|
r: &mut R,
|
|
read_annotations: bool,
|
|
) -> Result<<Self::Impl as ValueImpl<'de>>::IOEmbedded, ReadError> {
|
|
Ok(Shell::<'de, IOValue>::read_impl(
|
|
r,
|
|
read_annotations,
|
|
&mut IOValueDomainDecode::<Shell<'de, IOValue>>::default())?.into())
|
|
}
|
|
}
|
|
|
|
impl<'de, Err: Into<io::Error>, D: Domain<'de> + FromStr<Err = Err>> FromStr for Shell<'de, D> {
|
|
type Err = io::Error;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
Ok(Shell::read_impl(&mut BytesBinarySource::new(s.as_bytes()).text(), true, &mut DefaultDomainCodec)?)
|
|
}
|
|
}
|
|
|
|
impl<'de, D: Domain<'de>> ValueImpl<'de> for Shell<'de, D> {
|
|
type Handle = ShellHandle<'de, D>;
|
|
type Embedded = D;
|
|
type Mapped<E: Domain<'de>> = Shell<'de, E>;
|
|
type Items<'i> = std::slice::Iter<'i, Self::Handle> where Self: 'i;
|
|
type Entries<'i> = std::collections::btree_map::Iter<'i, Self::Handle, Self::Handle> where Self: 'i;
|
|
type IOEmbedded = IOValue<'de>;
|
|
|
|
fn wrap(self) -> Self::Handle {
|
|
Self::Handle::new(self)
|
|
}
|
|
|
|
fn write(&self, w: &mut dyn Writer, enc: &mut dyn DomainEncode<D>) -> io::Result<()> {
|
|
match self {
|
|
Shell::Atom(a) => a.write(w),
|
|
Shell::Record(_) => todo!(),
|
|
Shell::Sequence(items) => {
|
|
w.start_sequence()?;
|
|
let mut b = B::Type::default();
|
|
for e in items {
|
|
b.shift(Some(B::Item::SequenceValue));
|
|
w.boundary(&b)?;
|
|
e.write(w, enc)?;
|
|
}
|
|
b.shift(None);
|
|
w.boundary(&b)?;
|
|
w.end_sequence()
|
|
}
|
|
Shell::Set(items) => {
|
|
w.start_set()?;
|
|
let mut b = B::Type::default();
|
|
for e in items.iter() {
|
|
b.shift(Some(B::Item::SetValue));
|
|
w.boundary(&b)?;
|
|
e.write(w, enc)?;
|
|
}
|
|
b.shift(None);
|
|
w.boundary(&b)?;
|
|
w.end_set()
|
|
}
|
|
Shell::Dictionary(entries) => {
|
|
w.start_dictionary()?;
|
|
let mut b = B::Type::default();
|
|
for (k, v) in entries.iter() {
|
|
b.shift(Some(B::Item::DictionaryKey));
|
|
w.boundary(&b)?;
|
|
k.write(w, enc)?;
|
|
b.shift(Some(B::Item::DictionaryValue));
|
|
w.boundary(&b)?;
|
|
v.write(w, enc)?;
|
|
}
|
|
b.shift(None);
|
|
w.boundary(&b)?;
|
|
w.end_dictionary()
|
|
}
|
|
Shell::Embedded(d) => {
|
|
w.start_embedded()?;
|
|
enc.encode_embedded(w, d)?;
|
|
w.end_embedded()
|
|
}
|
|
Shell::Annotated(b) => {
|
|
let (value, anns) = b.0.as_ref();
|
|
w.start_annotations()?;
|
|
let mut b = B::Type::default();
|
|
for ann in anns {
|
|
b.shift(Some(B::Item::Annotation));
|
|
w.boundary(&b)?;
|
|
ann.write(w, &mut IOValueDomainEncode::<Self>::default())?;
|
|
}
|
|
b.shift(Some(B::Item::AnnotatedValue));
|
|
w.boundary(&b)?;
|
|
value.write(w, enc)?;
|
|
b.shift(None);
|
|
w.boundary(&b)?;
|
|
w.end_annotations()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn value_class(&self) -> ValueClass {
|
|
match self {
|
|
Shell::Atom(a) => ValueClass::Atomic(a.into()),
|
|
Shell::Record(_) => ValueClass::Compound(CompoundClass::Record),
|
|
Shell::Sequence(_) => ValueClass::Compound(CompoundClass::Sequence),
|
|
Shell::Set(_) => ValueClass::Compound(CompoundClass::Set),
|
|
Shell::Dictionary(_) => ValueClass::Compound(CompoundClass::Dictionary),
|
|
Shell::Embedded(_) => ValueClass::Embedded,
|
|
Shell::Annotated(b) => b.0.as_ref().0.value_class(),
|
|
}
|
|
}
|
|
|
|
fn copy<E: ValueImpl<'de>, F, Err>(w: &E::Handle, f: &mut F) -> Result<Self::Handle, Err>
|
|
where
|
|
F: FnMut(&E::Embedded) -> Result<Self::Handle, Err>
|
|
{
|
|
let w = w.borrow();
|
|
let r: Self::Handle = match w.value_class() {
|
|
ValueClass::Atomic(a) => match a {
|
|
AtomClass::Boolean => Shell::Atom(Atom::Boolean(w.as_boolean().unwrap())),
|
|
AtomClass::Float => Shell::Atom(Atom::Float(w.as_float().unwrap())),
|
|
AtomClass::Double => Shell::Atom(Atom::Double(w.as_double().unwrap())),
|
|
AtomClass::SignedInteger => Shell::Atom(Atom::SignedInteger(w.as_signed_integer().unwrap())),
|
|
AtomClass::String => Shell::Atom(Atom::String(w.as_string().unwrap())),
|
|
AtomClass::ByteString => Shell::Atom(Atom::ByteString(w.as_bytestring().unwrap())),
|
|
AtomClass::Symbol => Shell::Atom(Atom::Symbol(w.as_symbol().unwrap())),
|
|
}.wrap(),
|
|
ValueClass::Compound(c) => match c {
|
|
CompoundClass::Sequence =>
|
|
Shell::Sequence(w.iter().map(|ww| Self::copy::<E, _, _>(&ww, f)).collect::<Result<Vec<_>, _>>()?),
|
|
CompoundClass::Set =>
|
|
Shell::Set(w.iter().map(|ww| Self::copy::<E, _, _>(&ww, f)).collect::<Result<Set<_>, _>>()?),
|
|
CompoundClass::Record =>
|
|
Shell::Record(Record::new(
|
|
Self::copy::<E, _, _>(&w.label(), f)?,
|
|
w.iter().map(|ww| Self::copy::<E, _, _>(&ww, f)).collect::<Result<Vec<_>, _>>()?)),
|
|
CompoundClass::Dictionary =>
|
|
Shell::Dictionary(
|
|
w.entries().map(|(k, ww)| Ok((Self::copy::<E, _, _>(&k, f)?,
|
|
Self::copy::<E, _, _>(&ww, f)?)))
|
|
.collect::<Result<Map<_, _>, _>>()?),
|
|
}.wrap(),
|
|
ValueClass::Embedded => f(&w.as_embedded().unwrap())?
|
|
};
|
|
if let Some(anns) = w.annotations() {
|
|
Ok(Shell::Annotated(Annotations(Box::new((
|
|
r,
|
|
anns.iter().map(copy_iovalue::<E>).map(|a| a.into()).collect()
|
|
)))).wrap())
|
|
} else {
|
|
Ok(r)
|
|
}
|
|
}
|
|
|
|
fn map_embedded<E: Domain<'de>, F, Err>(v: &Self::Handle, f: &mut F) -> Result<<Self::Mapped<E> as ValueImpl<'de>>::Handle, Err>
|
|
where
|
|
F: FnMut(&D) -> Result<E, Err>
|
|
{
|
|
Self::Mapped::<E>::copy::<Self, _, _>(v, &mut |d| Ok(
|
|
ShellHandle::<'de, E>::new(Self::Mapped::<E>::Embedded(f(d)?))))
|
|
}
|
|
|
|
fn as_boolean(&self) -> Option<bool> {
|
|
match self {
|
|
Shell::Atom(Atom::Boolean(b)) => Some(*b),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn as_float(&self) -> Option<f32> {
|
|
match self {
|
|
Shell::Atom(Atom::Float(f)) => Some(*f),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn as_double(&self) -> Option<f64> {
|
|
match self {
|
|
Shell::Atom(Atom::Double(d)) => Some(*d),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn as_signed_integer(&self) -> Option<Cow<'_, SignedInteger>> {
|
|
match self {
|
|
Shell::Atom(Atom::SignedInteger(i)) => Some(Cow::Borrowed(i)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn as_string(&self) -> Option<Cow<'_, str>> {
|
|
match self {
|
|
Shell::Atom(Atom::String(s)) => Some(Cow::Borrowed(s)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn as_bytestring(&self) -> Option<Cow<'_, [u8]>> {
|
|
match self {
|
|
Shell::Atom(Atom::ByteString(bs)) => Some(Cow::Borrowed(bs)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn as_symbol(&self) -> Option<Cow<'_, str>> {
|
|
match self {
|
|
Shell::Atom(Atom::Symbol(s)) => Some(Cow::Borrowed(s)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn is_record(&self) -> bool {
|
|
matches!(self, Shell::Record(_))
|
|
}
|
|
|
|
fn label(&self) -> Self::Handle {
|
|
match self {
|
|
Shell::Record(items) => items.0[0],
|
|
_ => panic!("Not a record"),
|
|
}
|
|
}
|
|
|
|
fn is_sequence(&self) -> bool {
|
|
matches!(self, Shell::Sequence(_))
|
|
}
|
|
|
|
fn len(&self) -> usize {
|
|
match self {
|
|
Shell::Record(items) => items.0.len() - 1,
|
|
Shell::Sequence(items) => items.len(),
|
|
Shell::Set(items) => items.len(),
|
|
Shell::Dictionary(entries) => entries.len(),
|
|
_ => panic!("Not a compound value"),
|
|
}
|
|
}
|
|
|
|
fn index(&self, i: usize) -> Self::Handle {
|
|
match self {
|
|
Shell::Record(items) => items.0[i - 1],
|
|
Shell::Sequence(items) => items[i],
|
|
_ => panic!("Not indexable"),
|
|
}
|
|
}
|
|
|
|
fn iter(&self) -> Self::Items<'_> {
|
|
match self {
|
|
Shell::Record(items) => items.0[1..].iter(),
|
|
Shell::Sequence(items) => items.iter(),
|
|
Shell::Set(items) => todo!(), // TODO: don't use slice iter directly
|
|
_ => panic!("Not iterable"),
|
|
}
|
|
}
|
|
|
|
fn is_set(&self) -> bool {
|
|
matches!(self, Shell::Set(_))
|
|
}
|
|
|
|
fn has<E: ValueImpl<'de, Embedded = D>>(&self, v: &E::Handle) -> bool {
|
|
match self {
|
|
Shell::Set(items) => todo!(), // items.contains(v),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
fn is_dictionary(&self) -> bool {
|
|
matches!(self, Shell::Dictionary(_))
|
|
}
|
|
|
|
fn get<K: ValueImpl<'de, Embedded = D>>(&self, k: &K::Handle) -> Option<Self::Handle> {
|
|
match self {
|
|
Shell::Dictionary(entries) => todo!(), // entries.get(k),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn entries(&self) -> Self::Entries<'_> {
|
|
match self {
|
|
Shell::Dictionary(entries) => entries.iter(),
|
|
_ => panic!("Not a dictionary"),
|
|
}
|
|
}
|
|
|
|
fn as_embedded(&self) -> Option<Cow<'_, D>> {
|
|
match self {
|
|
Shell::Embedded(d) => Some(Cow::Borrowed(d)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn annotations(&self) -> Option<Cow<'_, [<Self::Mapped<Self::IOEmbedded> as ValueImpl<'de>>::Handle]>> {
|
|
match self {
|
|
Shell::Annotated(b) => Some(Cow::Borrowed(&b.0.as_ref().1)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn peeled(v: &Self::Handle) -> Self::Handle {
|
|
match v.as_ref() {
|
|
Shell::Annotated(b) => b.0.0,
|
|
_ => v.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl_value_methods!({'de, D: Domain<'de>}, Shell<'de, D>);
|
|
|
|
impl<'de, W: Into<Atom<'de>>, D: Domain<'de>> From<W> for Shell<'de, D> {
|
|
fn from(w: W) -> Self {
|
|
Shell::Atom(w.into())
|
|
}
|
|
}
|
|
|
|
impl<'de, D: Domain<'de>> From<Vec<ShellHandle<'de, D>>> for Shell<'de, D> {
|
|
fn from(vs: Vec<ShellHandle<'de, D>>) -> Self {
|
|
Shell::Sequence(vs)
|
|
}
|
|
}
|
|
|
|
impl<'de, D: Domain<'de>> From<Vec<Shell<'de, D>>> for Shell<'de, D> {
|
|
fn from(vs: Vec<Shell<'de, D>>) -> Self {
|
|
vs.iter().map(|v| v.wrap()).collect::<Vec<_>>().into()
|
|
}
|
|
}
|
|
|
|
impl<'de, D: Domain<'de>> From<Set<ShellHandle<'de, D>>> for Shell<'de, D> {
|
|
fn from(vs: Set<ShellHandle<'de, D>>) -> Self {
|
|
Shell::Set(vs)
|
|
}
|
|
}
|
|
|
|
impl<'de, D: Domain<'de>> From<Map<ShellHandle<'de, D>, ShellHandle<'de, D>>> for Shell<'de, D> {
|
|
fn from(vs: Map<ShellHandle<'de, D>, ShellHandle<'de, D>>) -> Self {
|
|
Shell::Dictionary(vs)
|
|
}
|
|
}
|
|
|
|
#[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)
|
|
}
|
|
|
|
pub fn _from_vec(v: Vec<V>) -> Self {
|
|
if v.is_empty() { panic!("Internal error: empty vec supplied to Record::_from_vec") }
|
|
Record(v)
|
|
}
|
|
|
|
pub fn _vec(&self) -> &Vec<V> {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct Annotations<'de, V: ValueImpl<'de>>(Box<(V::Handle, Vec<<V::Mapped<V::IOEmbedded> as ValueImpl<'de>>::Handle>)>);
|
|
|
|
impl<'de, V: ValueImpl<'de>> Annotations<'de, V> {
|
|
pub fn new(v: V::Handle, anns: Vec<<V::Mapped<V::IOEmbedded> as ValueImpl<'de>>::Handle>) -> Self {
|
|
Self(Box::new((v, anns)))
|
|
}
|
|
}
|
|
|
|
impl<'de, V: ValueImpl<'de>> Hash for Annotations<'de, V> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.0.as_ref().0.hash(state)
|
|
}
|
|
}
|
|
|
|
impl<'de, V: ValueImpl<'de>> PartialEq for Annotations<'de, V> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.0.as_ref().0.eq(&other.0.as_ref().0)
|
|
}
|
|
}
|
|
|
|
impl<'de, V: ValueImpl<'de>> Ord for Annotations<'de, V> {
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
self.0.as_ref().0.cmp(&other.0.as_ref().0)
|
|
}
|
|
}
|
|
|
|
impl<'de, V: ValueImpl<'de>> Eq for Annotations<'de, V> {}
|
|
|
|
impl<'de, V: ValueImpl<'de>> PartialOrd for Annotations<'de, V> {
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
pub fn copy_iovalue<'de, V: ValueImpl<'de>>(v: &<V::Mapped<V::IOEmbedded> as ValueImpl<'de>>::Handle) -> IOValue<'de> {
|
|
Shell::copy::<V::Mapped<V::IOEmbedded>, _, _>(v, &mut |a| Result::<_, ()>::Ok(
|
|
copy_iovalue::<V>(a.as_ref()).into())).unwrap().into()
|
|
}
|
|
|
|
pub type IOValueImpl<'a> = Shell<'a, IOValue<'a>>;
|
|
pub type IOValueIso<'a> = ShellHandle<'a, IOValue<'a>>;
|
|
|
|
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
#[repr(transparent)]
|
|
pub struct IOValue<'a>(IOValueIso<'a>);
|
|
unsafe impl<'a> TransparentWrapper<IOValueIso<'a>> for IOValue<'a> {}
|
|
|
|
impl<'de> Domain<'de> for IOValue<'de> {
|
|
type Decode = IOValueDomainDecode<'de, IOValueImpl<'de>>;
|
|
type Encode = IOValueDomainEncode<'de, Self>;
|
|
}
|
|
|
|
impl<'de> Debug for IOValue<'de> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
IOValue::peel_ref(self).fmt(f)
|
|
}
|
|
}
|
|
|
|
impl<'de> IOValue<'de> {
|
|
pub fn record(label: IOValue<'de>, fields: Vec<IOValue<'de>>) -> Self {
|
|
IOValue(Shell::Record(Record::new(
|
|
label.into(),
|
|
fields.into_iter().map(|f| f.into()).collect())).wrap())
|
|
}
|
|
|
|
pub fn value(&self) -> &IOValueImpl<'de> {
|
|
self.0.as_ref()
|
|
}
|
|
|
|
pub fn iso(self) -> IOValueIso<'de> {
|
|
IOValue::peel(self)
|
|
}
|
|
}
|
|
|
|
pub fn iso_parse<'a>(s: &'a str) -> io::Result<IOValueIso<'a>> {
|
|
Ok(IOValue::from_str(s)?.iso())
|
|
}
|
|
|
|
impl<'de, T: Into<IOValueImpl<'de>>> From<T> for IOValue<'de> {
|
|
fn from(t: T) -> Self {
|
|
IOValue(t.into().wrap())
|
|
}
|
|
}
|
|
|
|
impl<'de> Borrow<IOValueImpl<'de>> for IOValue<'de> {
|
|
fn borrow(&self) -> &IOValueImpl<'de> {
|
|
self.0.as_ref()
|
|
}
|
|
}
|
|
|
|
impl<'de> AsRef<Arc<Shell<'de, IOValue<'de>>>> for IOValue<'de> {
|
|
fn as_ref(&self) -> &Arc<Shell<'de, IOValue<'de>>> {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl<'de> FromStr for IOValue<'de> {
|
|
type Err = io::Error;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
crate::annotated_iovalue_from_str(s)
|
|
}
|
|
}
|
|
|
|
impl<'de> From<<IOValueImpl<'de> as ValueImpl<'de>>::Handle> for IOValue<'de> {
|
|
fn from(h: <IOValueImpl<'de> as ValueImpl<'de>>::Handle) -> Self {
|
|
TransparentWrapper::wrap(h)
|
|
}
|
|
}
|
|
|
|
impl<'r, 'de> From<&'r <IOValueImpl<'de> as ValueImpl<'de>>::Handle> for &'r IOValue<'de> {
|
|
fn from(h: &'r <IOValueImpl<'de> as ValueImpl<'de>>::Handle) -> Self {
|
|
TransparentWrapper::wrap_ref(h)
|
|
}
|
|
}
|
|
|
|
impl<'de> From<IOValue<'de>> for <IOValueImpl<'de> as ValueImpl<'de>>::Handle {
|
|
fn from(i: IOValue<'de>) -> Self {
|
|
IOValue::peel(i)
|
|
}
|
|
}
|
|
|
|
impl<'r, 'de> From<&'r IOValue<'de>> for &'r <IOValueImpl<'de> as ValueImpl<'de>>::Handle {
|
|
fn from(i: &'r IOValue<'de>) -> Self {
|
|
IOValue::peel_ref(i)
|
|
}
|
|
}
|
|
|
|
impl<'de> ValueReader<'de> for IOValue<'de> {
|
|
type Impl = Self;
|
|
|
|
fn read_impl<R: Reader<'de> + ?Sized, Dec: DomainDecode<'de, <Self::Impl as ValueImpl<'de>>::Embedded>>(
|
|
r: &mut R,
|
|
read_annotations: bool,
|
|
dec: &mut Dec,
|
|
) -> Result<Self::Impl, ReadError> {
|
|
Ok(read(r, read_annotations, dec)?.into())
|
|
}
|
|
|
|
fn read_iovalue<R: Reader<'de> + ?Sized>(
|
|
r: &mut R,
|
|
read_annotations: bool,
|
|
) -> Result<<Self::Impl as ValueImpl<'de>>::IOEmbedded, ReadError> {
|
|
Self::read_domain(r, read_annotations, &mut IOValueDomainDecode::<Self>::default())
|
|
}
|
|
}
|
|
|
|
impl<'de> ValueImpl<'de> for IOValue<'de> {
|
|
type Handle = Self;
|
|
type Embedded = Self;
|
|
type Mapped<E: Domain<'de>> = Shell<'de, E>;
|
|
type Items<'i> = std::slice::Iter<'i, Self::Handle> where Self: 'i;
|
|
type Entries<'i> = std::collections::btree_map::Iter<'i, Self::Handle, Self::Handle> where Self: 'i;
|
|
type IOEmbedded = Self;
|
|
|
|
fn wrap(self) -> Self::Handle {
|
|
self
|
|
}
|
|
|
|
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 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) -> Self::Handle {
|
|
self.value().label().into()
|
|
}
|
|
|
|
fn is_sequence(&self) -> bool {
|
|
self.value().is_sequence()
|
|
}
|
|
|
|
fn len(&self) -> usize {
|
|
self.value().len()
|
|
}
|
|
|
|
fn index(&self, i: usize) -> Self::Handle {
|
|
self.value().index(i).into()
|
|
}
|
|
|
|
fn iter(&self) -> Self::Items<'_> {
|
|
todo!() // self.value().iter()
|
|
}
|
|
|
|
fn is_set(&self) -> bool {
|
|
self.value().is_set()
|
|
}
|
|
|
|
fn has<E: ValueImpl<'de, Embedded = Self::Embedded>>(&self, v: &E::Handle) -> bool {
|
|
self.value().has::<E>(v)
|
|
}
|
|
|
|
fn is_dictionary(&self) -> bool {
|
|
self.value().is_dictionary()
|
|
}
|
|
|
|
fn get<K: ValueImpl<'de, Embedded = Self::Embedded>>(&self, k: &K::Handle) -> Option<Self::Handle> {
|
|
self.value().get::<K>(k).map(|v| v.into())
|
|
}
|
|
|
|
fn entries(&self) -> Self::Entries<'_> {
|
|
todo!() // self.value().entries()
|
|
}
|
|
|
|
fn as_embedded(&self) -> Option<Cow<'_, Self::Embedded>> {
|
|
self.value().as_embedded()
|
|
}
|
|
|
|
fn annotations(&self) -> Option<Cow<'_, [<Self::Mapped<Self::IOEmbedded> as ValueImpl<'de>>::Handle]>> {
|
|
self.value().annotations()
|
|
}
|
|
|
|
fn peeled(v: &Self::Handle) -> Self::Handle {
|
|
TransparentWrapper::wrap(Shell::peeled(IOValue::peel_ref(v)))
|
|
}
|
|
|
|
fn copy<E: ValueImpl<'de>, F, Err>(w: &E::Handle, f: &mut F) -> Result<Self::Handle, Err>
|
|
where
|
|
F: FnMut(&E::Embedded) -> Result<Self::Handle, Err> {
|
|
IOValueImpl::copy::<E, _, _>(w, &mut |e| f(e).map(|v| v.into())).map(|v| v.into())
|
|
}
|
|
|
|
fn map_embedded<E: Domain<'de>, F, Err>(v: &Self::Handle, f: &mut F) -> Result<<Self::Mapped<E> as ValueImpl<'de>>::Handle, Err>
|
|
where
|
|
F: FnMut(&Self::Embedded) -> Result<E, Err> {
|
|
IOValueImpl::map_embedded(v.into(), f)
|
|
}
|
|
}
|
|
|
|
pub fn read<'de, R: Reader<'de> + ?Sized, D: Domain<'de>, Dec: DomainDecode<'de, D>>(
|
|
r: &mut R,
|
|
read_annotations: bool,
|
|
dec: &mut Dec,
|
|
) -> io::Result<Shell<'de, D>> {
|
|
let (anns, v) = match read_annotations {
|
|
true => IOValue::gather_annotations(r)?.ok_or_else(io_eof)?,
|
|
false => (Vec::new(), r.skip_annotations()?.ok_or_else(io_eof)?),
|
|
};
|
|
let value = match v {
|
|
ValueClass::Atomic(_) =>
|
|
Shell::Atom(r.next_atom()?),
|
|
ValueClass::Embedded => {
|
|
r.open_embedded()?;
|
|
let v = dec.decode_embedded(r, read_annotations)?;
|
|
r.close_embedded()?;
|
|
Shell::Embedded(v)
|
|
}
|
|
ValueClass::Compound(CompoundClass::Record) => {
|
|
let mut vs = Vec::new();
|
|
r.open_record()?;
|
|
let mut b = B::start(B::Item::RecordLabel);
|
|
r.boundary(&b)?;
|
|
vs.push(read(r, read_annotations, dec)?.wrap());
|
|
while !r.close_compound(&mut b, &B::Item::RecordField)? {
|
|
vs.push(read(r, read_annotations, dec)?.wrap());
|
|
}
|
|
Shell::Record(Record::_from_vec(vs))
|
|
}
|
|
ValueClass::Compound(CompoundClass::Sequence) => {
|
|
let mut vs = Vec::new();
|
|
r.open_sequence()?;
|
|
let mut b = B::Type::default();
|
|
while !r.close_compound(&mut b, &B::Item::SequenceValue)? {
|
|
vs.push(read(r, read_annotations, dec)?.wrap());
|
|
}
|
|
Shell::Sequence(vs)
|
|
}
|
|
ValueClass::Compound(CompoundClass::Set) => {
|
|
let mut s = Set::new();
|
|
r.open_set()?;
|
|
let mut b = B::Type::default();
|
|
while !r.close_compound(&mut b, &B::Item::SetValue)? {
|
|
s.insert(read(r, read_annotations, dec)?.wrap());
|
|
}
|
|
Shell::Set(s)
|
|
}
|
|
ValueClass::Compound(CompoundClass::Dictionary) => {
|
|
let mut d = Map::new();
|
|
r.open_dictionary()?;
|
|
let mut b = B::Type::default();
|
|
while !r.close_compound(&mut b, &B::Item::DictionaryKey)? {
|
|
let k = read(r, read_annotations, dec)?.wrap();
|
|
b.shift(Some(B::Item::DictionaryValue));
|
|
r.boundary(&b)?;
|
|
d.insert(k, read(r, read_annotations, dec)?.wrap());
|
|
}
|
|
Shell::Dictionary(d)
|
|
}
|
|
};
|
|
if anns.is_empty() {
|
|
Ok(value)
|
|
} else {
|
|
Ok(Shell::Annotated(Annotations::new(value.wrap(), anns)))
|
|
}
|
|
}
|