//! The runtime support library for compiled Schemas. #[doc(hidden)] /// Reexport lazy_static for generated code to use. pub use lazy_static::lazy_static; pub use preserves; pub use preserves::value::boundary as B; pub use preserves::value::Reader; pub mod interpret; use preserves::value::ArcValue; use preserves::value::Domain; use preserves::value::IOValue; use preserves::value::NestedValue; use preserves::value::NoEmbeddedDomainCodec; use preserves::value::Value; use std::convert::From; use std::convert::Into; use std::convert::TryFrom; use std::io; use std::sync::Arc; use thiserror::Error; /// Every [language][crate::define_language] implements [NestedValueCodec] as a marker trait. pub trait NestedValueCodec {} // marker trait impl NestedValueCodec for () {} /// Implementors of [Parse] can produce instances of themselves from a [Value], given a /// supporting [language][crate::define_language]. All Schema-compiler-produced types implement /// [Parse]. pub trait Parse: Sized { /// Decode the given `value` (using auxiliary structure from the `language` instance) to /// produce an instance of [Self]. fn parse(language: L, value: &Value) -> Result; } impl<'a, T: NestedValueCodec, Value: NestedValue> Parse<&'a T, Value> for Value { fn parse(_language: &'a T, value: &Value) -> Result { Ok(value.clone()) } } /// Implementors of [Unparse] can convert themselves into a [Value], given a supporting /// [language][crate::define_language]. All Schema-compiler-produced types implement [Unparse]. pub trait Unparse { /// Encode `self` into a [Value] (using auxiliary structure from the `language` instance). fn unparse(&self, language: L) -> Value; } impl<'a, T: NestedValueCodec, Value: NestedValue> Unparse<&'a T, Value> for Value { fn unparse(&self, _language: &'a T) -> Value { self.clone() } } /// Every [language][crate::define_language] implements [Codec], which supplies convenient /// shorthand for invoking [Parse::parse] and [Unparse::unparse]. pub trait Codec { /// Delegates to [`T::parse`][Parse::parse], using `self` as language and the given `value` /// as input. fn parse<'a, T: Parse<&'a Self, N>>(&'a self, value: &N) -> Result; /// Delegates to [`value.unparse`][Unparse::unparse], using `self` as language. fn unparse<'a, T: Unparse<&'a Self, N>>(&'a self, value: &T) -> N; } impl Codec for L { fn parse<'a, T: Parse<&'a L, N>>(&'a self, value: &N) -> Result { T::parse(self, value) } fn unparse<'a, T: Unparse<&'a L, N>>(&'a self, value: &T) -> N { value.unparse(self) } } /// Implementors of [Deserialize] can produce instances of themselves from a [Value]. All /// Schema-compiler-produced types implement [Deserialize]. /// /// The difference between [Deserialize] and [Parse] is that implementors of [Deserialize] know /// which [language][crate::define_language] to use. pub trait Deserialize where Self: Sized, { fn deserialize<'de, R: Reader<'de, N>>(r: &mut R) -> Result; } /// Extracts a simple literal term from a byte array using /// [PackedReader][preserves::value::packed::PackedReader]. No embedded values are permitted. pub fn decode_lit(bs: &[u8]) -> io::Result { preserves::value::packed::from_bytes(bs, NoEmbeddedDomainCodec) } /// When `D` can parse itself from an [IOValue], this function parses all embedded [IOValue]s /// into `D`s. pub fn decode_embedded(v: &IOValue) -> Result>, ParseError> where for<'a> D: TryFrom<&'a IOValue, Error = ParseError>, { v.copy_via(&mut |d| Ok(Value::Embedded(Arc::new(D::try_from(d)?)))) } /// When `D` can unparse itself into an [IOValue], this function converts all embedded `D`s /// into [IOValue]s. pub fn encode_embedded(v: &ArcValue>) -> IOValue where for<'a> IOValue: From<&'a D>, { v.copy_via::<_, _, std::convert::Infallible>(&mut |d| Ok(Value::Embedded(IOValue::from(d)))) .unwrap() } /// Error value yielded when parsing of an [IOValue] into a Schema-compiler-produced type. #[derive(Error, Debug)] pub enum ParseError { /// Signalled when the input does not match the Preserves Schema associated with the type. #[error("Input not conformant with Schema: {0}")] ConformanceError(&'static str), /// Signalled when the underlying Preserves library signals an error. #[error(transparent)] Preserves(preserves::error::Error), } impl From for ParseError { fn from(v: preserves::error::Error) -> Self { match v { preserves::error::Error::Expected(_, _) => { ParseError::ConformanceError("preserves::error::Error::Expected") } _ => ParseError::Preserves(v), } } } impl From for ParseError { fn from(v: io::Error) -> Self { preserves::error::Error::from(v).into() } } impl From for io::Error { fn from(v: ParseError) -> Self { match v { ParseError::ConformanceError(_) => io::Error::new(io::ErrorKind::InvalidData, v), ParseError::Preserves(e) => e.into(), } } } impl ParseError { /// Constructs a [ParseError::ConformanceError]. pub fn conformance_error(context: &'static str) -> Self { ParseError::ConformanceError(context) } /// True iff `self` is a [ParseError::ConformanceError]. pub fn is_conformance_error(&self) -> bool { return if let ParseError::ConformanceError(_) = self { true } else { false }; } }