Skip to main content

substrate_data/schema/
named_type.rs

1//! [`NamedType`]: a type of a format's own (`color`, `date`, `money`) that
2//! is stored as another schema's data, and the shape tools know it by.
3
4use super::{Reader, Schema, Shape, ShapeFn};
5use crate::ValueRef;
6
7/// A type of a format's own, stored as [`NamedType::Stored`] in every form
8/// (text, binary, frames) and described by [`NamedType::NAME`], so a tool
9/// that knows the name shows its own editor (a colour picker, a calendar)
10/// and one that doesn't edits the stored data. [`crate::named_schema!`]
11/// implements [`Schema`] for it.
12pub trait NamedType: Sized {
13    /// What tools know it by: `"color"`, `"date"`.
14    const NAME: &'static str;
15    /// What it's stored as.
16    type Stored: Schema;
17    /// Its stored form.
18    fn to_stored(&self) -> Self::Stored;
19    /// The value `stored` holds, if it's a valid one.
20    fn from_stored(stored: Self::Stored) -> Option<Self>;
21}
22
23/// The shape of a [`NamedType`]: its name and its stored shape.
24#[derive(Debug, Clone, Copy)]
25pub struct NamedShape {
26    name: &'static str,
27    stored: ShapeFn,
28}
29
30impl NamedShape {
31    /// The shape of `T`.
32    #[must_use]
33    pub fn of<T: NamedType>() -> NamedShape {
34        NamedShape {
35            name: T::NAME,
36            stored: <T::Stored as Schema>::shape,
37        }
38    }
39
40    /// What tools know it by.
41    #[must_use]
42    pub fn name(&self) -> &'static str {
43        self.name
44    }
45
46    /// What it's stored as.
47    #[must_use]
48    pub fn stored(&self) -> Shape {
49        (self.stored)()
50    }
51}
52
53/// Reads a [`NamedType`] through its stored form (what [`crate::named_schema!`] calls).
54pub fn read_named<T: NamedType>(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<T> {
55    let stored = T::Stored::read(v, cx)?;
56    T::from_stored(stored).or_else(|| {
57        cx.problem(format!("not a valid {}", T::NAME));
58        None
59    })
60}
61
62/// Implements [`Schema`] for a [`NamedType`]: every form is its stored
63/// form's, so a reader that only knows the shape reads it as stored.
64#[macro_export]
65macro_rules! named_schema {
66    ($t:ty) => {
67        impl $crate::Schema for $t {
68            fn shape() -> $crate::Shape {
69                $crate::Shape::named::<$t>()
70            }
71            fn read(
72                v: &$crate::ValueRef<'_>,
73                cx: &mut $crate::Reader<'_>,
74            ) -> ::std::option::Option<Self> {
75                $crate::schema::read_named::<$t>(v, cx)
76            }
77            fn write(&self) -> $crate::Value {
78                $crate::Schema::write(&$crate::schema::NamedType::to_stored(self))
79            }
80            fn encode(&self, w: &mut $crate::binary::Writer) {
81                $crate::Schema::encode(&$crate::schema::NamedType::to_stored(self), w);
82            }
83            fn decode(d: &mut $crate::binary::Decoder<'_>) -> ::std::option::Option<Self> {
84                <<$t as $crate::schema::NamedType>::Stored as $crate::Schema>::decode(d)
85                    .and_then(<$t as $crate::schema::NamedType>::from_stored)
86            }
87            fn pack(&self, p: &mut $crate::frame::Packer) {
88                $crate::Schema::pack(&$crate::schema::NamedType::to_stored(self), p);
89            }
90            fn unpack(u: &mut $crate::frame::Unpacker<'_>) -> ::std::option::Option<Self> {
91                <<$t as $crate::schema::NamedType>::Stored as $crate::Schema>::unpack(u)
92                    .and_then(<$t as $crate::schema::NamedType>::from_stored)
93            }
94        }
95    };
96}