From 5ac12414ebae69468a408d3bf76bdc49c7695970 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 24 May 2021 20:16:14 +0100 Subject: [PATCH] begin Format impl wrapper for FORMATS array --- src/formats.rs | 128 ++++++++++++++++++++++++++++++++++++++++++-- src/formats/json.rs | 14 +++++ 2 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/formats/json.rs diff --git a/src/formats.rs b/src/formats.rs index 79cd553..e0280f1 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -1,17 +1,31 @@ //! 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 -pub struct Config; +pub struct Config; //TODO: What goes here? /// 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) -> io::Result, - decode: fn (&Config, &mut dyn io::Read) -> io::Result<(Object, usize)>, + encode: fn (&Config, &mut dyn io::Write, &Object) -> Result, + decode: fn (&Config, &mut dyn io::Read) -> Result<(Object, usize), Error>, +} + +/// 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; //TODO: An `io::Read` wrapper that counter num of bytes read internally. That way we can extract `(Object, usize)` from just `Object` here. } macro_rules! directive { @@ -21,11 +35,117 @@ macro_rules! directive { decode: $decode, }) }; + (for $fmt:path => $($name:literal),+) => { + //TODO: $fmt will be a struct implementing `Format`. + // Will perform input conversions to trait methods. + // Will perform input/output conversions for `Format::decode` to extract `(Object, usize)` from `Object` function output and a `io::Read` input wrapper that counts bytes read from the stream. + directive!($($name),+ => |c, w, o| { + <$fmt as Format>::encode(c, w, o) + }, |c, r| { + todo!("We need a io::Read stream wrapper that counts the bytes read `r` to satisfy the return value requirements of this function pointer") + }) + } } /// All format directives and their name(s) pub static FORMATS: &[(&'static [&'static str], FormatDirective)] = &[ - directive!("json", "js", "javascript" => |_, _, _| todo!(), |_, _| todo!()), + 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 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) -> Self + { + Self(kind.into(), true) + } + /// A decode error + #[inline] pub fn decode(kind: impl Into) -> 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 for io::Error +{ + fn from(from: Error) -> Self + { + match from.0 + { + ErrorKind::IO(io) => io, + _ => io::Error::new(io::ErrorKind::Other, from), + } + } +} diff --git a/src/formats/json.rs b/src/formats/json.rs new file mode 100644 index 0000000..022a143 --- /dev/null +++ b/src/formats/json.rs @@ -0,0 +1,14 @@ +use super::*; + +#[derive(Debug)] +pub struct JsonFormatter; + +impl Format for JsonFormatter +{ + fn encode(cfg: &Config, to: W, obj: &Object) -> Result { + todo!() + } + fn decode(cfg: &Config, from: R) -> Result { + todo!() + } +}