preserves 5.0.0-rc.9

Implementation of the Preserves serialization format.
Documentation
use std::borrow::Cow;
use std::convert::TryFrom;
use std::io;

use crate::AtomClass;
use crate::ExpectedKind;
use crate::SignedInteger;
use crate::Writer;

#[derive(Debug, Clone)]
pub enum Atom<'a> {
    Boolean(bool),
    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::Double(d) => Atom::Double(d),
            Atom::SignedInteger(i) => Atom::SignedInteger(Cow::Owned(i.into_owned())),
            Atom::String(s) => Atom::String(Cow::Owned(s.into_owned())),
            Atom::ByteString(bs) => Atom::ByteString(Cow::Owned(bs.into_owned())),
            Atom::Symbol(s) => Atom::Symbol(Cow::Owned(s.into_owned())),
        }
    }

    pub fn write(&self, w: &mut dyn Writer) -> io::Result<()> {
        match self {
            Atom::Boolean(b) => w.write_bool(*b),
            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),
        }
    }
}

impl<'r, 'a> From<&'r Atom<'a>> for AtomClass {
    fn from(a: &'r Atom<'a>) -> Self {
        match a {
            Atom::Boolean(_) => AtomClass::Boolean,
            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<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)) } }

macro_rules! from_atom_ref_impl {
    ($t:ty, $p:pat, $e:expr, $err:expr) => {
        impl<'r, 'a> TryFrom<&'r Atom<'a>> for $t {
            type Error = ExpectedKind;
            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::Boolean);
from_atom_ref_impl!(f64, Atom::Double(d), *d, ExpectedKind::Double);
from_atom_ref_impl!(&'r SignedInteger, Atom::SignedInteger(i), i.as_ref(), ExpectedKind::SignedInteger);
from_atom_ref_impl!(&'r str, Atom::String(s), s.as_ref(), ExpectedKind::String);
from_atom_ref_impl!(&'r [u8], Atom::ByteString(bs), bs.as_ref(), ExpectedKind::ByteString);

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!(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);