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