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.

156 lines
3.2 KiB

//! The available formats to convert
use super::*;
use std::io;
use std::{
error, fmt,
};
use object::Object;
/// `Format` impl for JSON.
mod json;
/// Config for the encode/decode
#[derive(Debug)]
pub struct Config{
//TODO: What goes here?
/// Any arbitrary data.
pub user: Option<Anything>,
}
/// 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>,
}
/// Trait for statically implementing formatters to/from `Object`.
pub trait Format
{
fn encode<W: io::Write>(cfg: &Config, to: W, obj: &Object) -> Result<usize, Error>;
fn decode<R: io::Read>(cfg: &Config, from: R) -> Result<Object, Error>;
}
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)
}, |c, r| {
let mut r = r.with_counter();
let obj = <$fmt as Format>::decode(c, &mut r)?;
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!("s-expression", "sexpr", "lisp", "lexpr" => |_, _, _| todo!(), |_, _| todo!()),
directive!("cbor" => |_, _, _| todo!(), |_, _| todo!()),
];
/// A formatting error kind. See `Error`.
#[derive(Debug)]
pub enum ErrorKind
{
IO(io::Error),
Unknown,
}
impl From<io::Error> for ErrorKind
{
fn from(from: io::Error) -> Self
{
Self::IO(from)
}
}
/// A formatting error.
#[derive(Debug)]
pub struct Error(ErrorKind, bool);
impl Error
{
/// An encode error
#[inline] pub fn encode(kind: impl Into<ErrorKind>) -> Self
{
Self(kind.into(), true)
}
/// A decode error
#[inline] pub fn decode(kind: impl Into<ErrorKind>) -> Self
{
Self(kind.into(), false)
}
/// What kind of error was it?
#[inline] pub fn kind(&self) -> &ErrorKind
{
&self.0
}
/// Is an encode error?
#[inline] pub fn is_encode(&self) -> bool
{
self.1
}
/// Is a decode error?
#[inline] pub fn is_decode(&self) -> bool
{
!self.1
}
}
impl error::Error for Error
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(match &self.0 {
ErrorKind::IO(i) => i,
_ => return None,
})
}
}
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "formatting error: ")?;
if self.1 {
write!(f, "encode")
} else {
write!(f, "decode")
}
}
}
impl From<(io::Error, bool)> for Error
{
#[inline] fn from(from: (io::Error, bool)) -> Self
{
Self(ErrorKind::IO(from.0), from.1)
}
}
impl From<Error> for io::Error
{
fn from(from: Error) -> Self
{
match from.0
{
ErrorKind::IO(io) => io,
_ => io::Error::new(io::ErrorKind::Other, from),
}
}
}