diff --git a/src/conv.rs b/src/conv.rs new file mode 100644 index 0000000..06b7394 --- /dev/null +++ b/src/conv.rs @@ -0,0 +1,22 @@ +//! Conversion operations +use super::*; +use std::io::{ + self, Write, Read, +}; +use error::Error; + +/// Convert from a reader to a writer +/// # Returns +/// The number of bytes read from the `input` stream, and the number of bytes written to the `output` stream. +pub fn conv_reader_writer(input: R, input_format: FormatKind, output: W, output_format: FormatKind) -> Result<(usize, usize), Error> +{ + let cfg = formats::config::Config::default(); + + let input_format = input_format.directive(); + let output_format = output_format.directive(); + + let (obj, read) = input_format.call_decode(&cfg, input)?; + let write = output_format.call_encode(&cfg, output, &obj)?; + + Ok((read, write)) +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..8966c67 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,167 @@ +//! Formatting error(s). +use super::*; +use std::{ + error, fmt, + io, +}; + +/// A formatting error kind. See `Error`. +#[derive(Debug)] +pub enum ErrorKind +{ + IO(io::Error), + Json(serde_json::Error), + Cbor(serde_cbor::Error), + Lexpr(serde_lexpr::Error), + /// Unknown format ID + UnknownFormat(u32), + /// Unknown error + Unknown, +} + +impl error::Error for ErrorKind +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match &self { + ErrorKind::IO(i) => i, + ErrorKind::Json(i) => i, + ErrorKind::Cbor(i) => i, + ErrorKind::Lexpr(i) => i, + _ => return None, + }) + } +} +impl fmt::Display for ErrorKind +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self { + Self::IO(_) => write!(f, "io"), + + Self::Json(_) => write!(f, "conv json"), + Self::Cbor(_) => write!(f, "conv cbor"), + Self::Lexpr(_) => write!(f, "conv lexpr"), + + Self::UnknownFormat(fmt) => write!(f, "unknown format ID: {}", fmt), + + _ => write!(f, "unknown error") + } + } +} + + +impl From for ErrorKind +{ + fn from(from: io::Error) -> Self + { + Self::IO(from) + } +} + +impl From for ErrorKind +{ + fn from(from: serde_json::Error) -> Self + { + Self::Json(from) + } +} + +impl From for ErrorKind +{ + fn from(from: serde_cbor::Error) -> Self + { + Self::Cbor(from) + } +} + +impl From for ErrorKind +{ + fn from(from: serde_lexpr::Error) -> Self + { + Self::Lexpr(from) + } +} + + +/// A formatting error. +#[derive(Debug)] +pub struct Error(Box, bool); + +impl Error +{ + /// An encode error + #[inline] pub fn encode(kind: impl Into) -> Self + { + Self(Box::new(kind.into()), true) + } + /// A decode error + #[inline] pub fn decode(kind: impl Into) -> Self + { + Self(Box::new(kind.into()), false) + } + + /// What kind of error was it? + #[inline] pub fn kind(&self) -> &ErrorKind + { + &self.0 + } + + /// Consume into the kind of error, which contains the original error object from the conversion (if there is one) + #[inline] pub fn into_inner(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 +{ + #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { + use error::Error; + self.0.source() + } +} + +impl fmt::Display for Error +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "formatting error in ")?; + 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(Box::new(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.rs b/src/formats.rs index f9479ed..0009204 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -6,13 +6,12 @@ use std::convert::TryFrom; use object::Object; /// `Format` impl for JSON. -mod json; +pub mod json; /// `Format` impl for S expressions. -mod sexpr; +pub mod sexpr; /// `Format` impl for CBOR. -mod cbor; +pub mod cbor; -pub mod error; use error::*; pub mod config; @@ -26,6 +25,22 @@ pub struct FormatDirective 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 { @@ -58,6 +73,13 @@ pub static FORMATS: &[(&'static [&'static str], FormatDirective)] = &[ 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; @@ -71,6 +93,15 @@ pub enum FormatKind 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 diff --git a/src/formats/.#error.rs b/src/formats/.#error.rs new file mode 120000 index 0000000..60413f0 --- /dev/null +++ b/src/formats/.#error.rs @@ -0,0 +1 @@ +avril@eientei.14063:1621696860 \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 2cf4ab4..24fa8c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,13 @@ mod ext; use ext::*; // Internal modules pub mod object; pub mod formats; +pub mod error; pub use formats::FormatKind; // TODO: External modules/functions/types/whatever +mod conv; +pub use conv::*; // TODO: FFI module, export C interface