You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
3.3 KiB
129 lines
3.3 KiB
//! 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<usize, Error>,
|
|
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<usize, Error>
|
|
{
|
|
let call = self.encode;
|
|
call(cfg, &mut stream, obj)
|
|
}
|
|
}
|
|
|
|
/// Trait for statically implementing formatters to/from `Object`.
|
|
pub trait Format
|
|
{
|
|
fn encode<W: io::Write>(cfg: &Config, to: W, obj: &Object) -> Result<usize, ErrorKind>;
|
|
fn decode<R: io::Read>(cfg: &Config, from: R) -> Result<Object, ErrorKind>;
|
|
}
|
|
|
|
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<FormatKind> for u32
|
|
{
|
|
fn from(from: FormatKind) -> Self
|
|
{
|
|
from as Self
|
|
}
|
|
}
|
|
|
|
impl TryFrom<u32> for FormatKind
|
|
{
|
|
type Error = ErrorKind;
|
|
|
|
fn try_from(from: u32) -> Result<Self, Self::Error>
|
|
{
|
|
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::<Error>()]; // Size of error type check (unboxed 56 -> boxed 16)
|