169 lines
5.7 KiB
Rust
169 lines
5.7 KiB
Rust
//! 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<L, Value: NestedValue>: 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<Self, ParseError>;
|
|
}
|
|
|
|
impl<'a, T: NestedValueCodec, Value: NestedValue> Parse<&'a T, Value> for Value {
|
|
fn parse(_language: &'a T, value: &Value) -> Result<Self, ParseError> {
|
|
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<L, Value: NestedValue> {
|
|
/// 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<N: NestedValue> {
|
|
/// 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<T, ParseError>;
|
|
/// Delegates to [`value.unparse`][Unparse::unparse], using `self` as language.
|
|
fn unparse<'a, T: Unparse<&'a Self, N>>(&'a self, value: &T) -> N;
|
|
}
|
|
|
|
impl<L, N: NestedValue> Codec<N> for L {
|
|
fn parse<'a, T: Parse<&'a L, N>>(&'a self, value: &N) -> Result<T, ParseError> {
|
|
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<N: NestedValue>
|
|
where
|
|
Self: Sized,
|
|
{
|
|
fn deserialize<'de, R: Reader<'de, N>>(r: &mut R) -> Result<Self, ParseError>;
|
|
}
|
|
|
|
/// Extracts a simple literal term from a byte array using
|
|
/// [PackedReader][preserves::value::packed::PackedReader]. No embedded values are permitted.
|
|
pub fn decode_lit<N: NestedValue>(bs: &[u8]) -> io::Result<N> {
|
|
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<D: Domain>(v: &IOValue) -> Result<ArcValue<Arc<D>>, 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<D: Domain>(v: &ArcValue<Arc<D>>) -> 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<preserves::error::Error> 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<io::Error> for ParseError {
|
|
fn from(v: io::Error) -> Self {
|
|
preserves::error::Error::from(v).into()
|
|
}
|
|
}
|
|
|
|
impl From<ParseError> 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
|
|
};
|
|
}
|
|
}
|