//! The available formats to convert use super::*; use std::io; use std::convert::TryFrom; use object::Object; /// `Format` impl for JSON. pub mod json; /// `Format` impl for S expressions. pub mod sexpr; /// `Format` impl for CBOR. pub mod cbor; use error::*; pub mod config; use config::*; /// A directive for a format on how to encode and decode objects. #[derive(Clone, Copy)] pub struct FormatDirective { encode: fn (&Config, &mut dyn io::Write, &Object) -> Result, decode: fn (&Config, &mut dyn io::Read) -> Result<(Object, usize), Error>, } impl FormatDirective { /// Call the decode method of this directive #[inline(always)] pub fn call_decode(&self, cfg: &Config, mut stream: impl io::Read) -> Result<(Object, usize), Error> { let call = self.decode; call(cfg, &mut stream) } /// Call the encode method of this directive #[inline(always)] pub fn call_encode(&self, cfg: &Config, mut stream: impl io::Write, obj: &Object) -> Result { let call = self.encode; call(cfg, &mut stream, obj) } } /// Trait for statically implementing formatters to/from `Object`. pub trait Format { fn encode(cfg: &Config, to: W, obj: &Object) -> Result; fn decode(cfg: &Config, from: R) -> Result; } macro_rules! directive { ($($name:literal),+ => $encode:expr, $decode:expr) => { (&[$($name),+], FormatDirective { encode: $encode, decode: $decode, }) }; (for $fmt:path => $($name:literal),+) => { directive!($($name),+ => |c, w, o| { <$fmt as Format>::encode(c, w, o).map_err(Error::encode) }, |c, r| { let mut r = r.with_counter(); let obj = <$fmt as Format>::decode(c, &mut r).map_err(Error::decode)?; Ok((obj, r.count())) }) } } /// All format directives and their name(s) pub static FORMATS: &[(&'static [&'static str], FormatDirective)] = &[ directive!(for json::JsonFormatter => "json", "js", "javascript"), directive!(for sexpr::SExpressionFormatter => "s-expression", "sexpr", "lisp", "lexpr"), directive!(for cbor::CborFormatter => "cbor"), ]; /// Directives in a lookup stream pub static DIRECTIVES: &[&'static FormatDirective; 3] = &[ &FORMATS[0].1, &FORMATS[1].1, &FORMATS[2].1, ]; pub(crate) const FORMAT_KIND_JSON: u32 = FormatKind::Json as u32; pub(crate) const FORMAT_KIND_SEXPR: u32 = FormatKind::SExpr as u32; pub(crate) const FORMAT_KIND_CBOR: u32 = FormatKind::CBor as u32; /// The formats available for conversion #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] #[repr(C)] pub enum FormatKind { Json = 1, SExpr = 2, CBor = 3, } impl FormatKind { /// Get the directive for this format kind #[inline] pub fn directive(&self) -> &FormatDirective { DIRECTIVES[u32::from(*self) as usize] } } impl From for u32 { fn from(from: FormatKind) -> Self { from as Self } } impl TryFrom for FormatKind { type Error = ErrorKind; fn try_from(from: u32) -> Result { Ok(match from { FORMAT_KIND_JSON => Self::Json, FORMAT_KIND_SEXPR => Self::SExpr, FORMAT_KIND_CBOR => Self::CBor, _ => return Err(ErrorKind::UnknownFormat(from)), }) } } //const _: &[u8; 0] = &[0u8; std::mem::size_of::()]; // Size of error type check (unboxed 56 -> boxed 16)