use super::{Reader, Schema, Shape, ShapeFn};
use crate::ValueRef;
pub trait NamedType: Sized {
const NAME: &'static str;
type Stored: Schema;
fn to_stored(&self) -> Self::Stored;
fn from_stored(stored: Self::Stored) -> Option<Self>;
}
#[derive(Debug, Clone, Copy)]
pub struct NamedShape {
name: &'static str,
stored: ShapeFn,
}
impl NamedShape {
#[must_use]
pub fn of<T: NamedType>() -> NamedShape {
NamedShape {
name: T::NAME,
stored: <T::Stored as Schema>::shape,
}
}
#[must_use]
pub fn name(&self) -> &'static str {
self.name
}
#[must_use]
pub fn stored(&self) -> Shape {
(self.stored)()
}
}
pub fn read_named<T: NamedType>(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<T> {
let stored = T::Stored::read(v, cx)?;
T::from_stored(stored).or_else(|| {
cx.problem(format!("not a valid {}", T::NAME));
None
})
}
#[macro_export]
macro_rules! named_schema {
($t:ty) => {
impl $crate::Schema for $t {
fn shape() -> $crate::Shape {
$crate::Shape::named::<$t>()
}
fn read(
v: &$crate::ValueRef<'_>,
cx: &mut $crate::Reader<'_>,
) -> ::std::option::Option<Self> {
$crate::schema::read_named::<$t>(v, cx)
}
fn write(&self) -> $crate::Value {
$crate::Schema::write(&$crate::schema::NamedType::to_stored(self))
}
fn encode(&self, w: &mut $crate::binary::Writer) {
$crate::Schema::encode(&$crate::schema::NamedType::to_stored(self), w);
}
fn decode(d: &mut $crate::binary::Decoder<'_>) -> ::std::option::Option<Self> {
<<$t as $crate::schema::NamedType>::Stored as $crate::Schema>::decode(d)
.and_then(<$t as $crate::schema::NamedType>::from_stored)
}
fn pack(&self, p: &mut $crate::frame::Packer) {
$crate::Schema::pack(&$crate::schema::NamedType::to_stored(self), p);
}
fn unpack(u: &mut $crate::frame::Unpacker<'_>) -> ::std::option::Option<Self> {
<<$t as $crate::schema::NamedType>::Stored as $crate::Schema>::unpack(u)
.and_then(<$t as $crate::schema::NamedType>::from_stored)
}
}
};
}