use alloc::borrow::Cow;
use deser_core::State;
use deser_core::de::{Deserialize, Sink, SinkHandle};
use deser_core::ext::{ExtValue, Extension};
use deser_core::ser::{Chunk, Serialize};
use deser_core::{Atom, Error, ErrorKind};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Simple(u8);
impl Simple {
pub fn new(value: u8) -> Option<Simple> {
if (24..32).contains(&value) {
None
} else {
Some(Simple(value))
}
}
pub fn value(self) -> u8 {
self.0
}
}
impl Extension for Simple {
fn name(&self) -> &str {
"simple value"
}
fn fallback(&self) -> Atom<'_> {
Atom::U64(u64::from(self.0))
}
}
impl Serialize for Simple {
fn serialize(&self, _state: &mut State) -> Result<Chunk<'_>, Error> {
Ok(Chunk::Atom(Atom::Ext(ExtValue::borrowed(self))))
}
}
impl<'de> Deserialize<'de> for Simple {
fn deserialize_into<'out>(
out: &'out mut Option<Self>,
state: &mut State,
) -> SinkHandle<'out, 'de> {
SinkHandle::arena(SimpleSink(out), state)
}
}
struct SimpleSink<'a>(&'a mut Option<Simple>);
impl<'a, 'de> Sink<'de> for SimpleSink<'a> {
fn expecting(&self) -> Cow<'_, str> {
Cow::Borrowed("simple")
}
fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
let simple = match atom {
Atom::Ext(ref ext) if ext.is::<Simple>() => *ext.downcast_ref::<Simple>().unwrap(),
Atom::Bool(false) => Simple(20),
Atom::Bool(true) => Simple(21),
Atom::Null => Simple(22),
Atom::U64(value) => match u8::try_from(value).ok().and_then(Simple::new) {
Some(simple) => simple,
None => {
return Err(Error::new(
ErrorKind::OutOfRange,
"value out of range for simple value",
));
}
},
other => return self.unexpected_atom(other, state),
};
*self.0 = Some(simple);
Ok(())
}
}