Skip to main content

substrate_data/schema/
with.rs

1//! Field codecs: `#[data(with = "…")]` reads and writes a field through a
2//! type other than its own — like serde's `with`. The field keeps the plain
3//! type a program uses (`String`), the format says what it holds (a
4//! reference to a file), checked and resolved by the [`Reader`]'s
5//! [`Resolve`](crate::schema::Resolve).
6//!
7//! ```
8//! use substrate_data::with::{Opt, RefTo};
9//!
10//! substrate_data::kind!(File = "file", User = "user");
11//!
12//! #[derive(substrate_data::Schema)]
13//! struct Attachment {
14//!     /// `@file:…`, kept as the plain id.
15//!     #[data(with = "RefTo<File>")]
16//!     file: String,
17//!     #[data(with = "Opt<RefTo<User>>")]
18//!     owner: Option<String>,
19//! }
20//!
21//! let a: Attachment =
22//!     substrate_data::from_text(r#"{ file: "@file:images/logo.png" }"#).unwrap().value;
23//! assert_eq!(a.file, "images/logo.png");
24//! assert_eq!(a.owner, None);
25//! ```
26
27use std::collections::{BTreeMap, HashMap};
28use std::marker::PhantomData;
29
30pub use super::expand::Expand;
31use crate::binary::{Decoder, Writer};
32use crate::frame::{Packer, Unpacker};
33use crate::model::borrowed::ValueRef;
34use crate::model::value::{Map, Ref, Seg, Value};
35use crate::schema::{Kinds, Reader, Schema, Shape, is_metadata_key};
36
37/// How a field of type `F` is read and written.
38pub trait With<F> {
39    /// The field's shape.
40    fn shape() -> Shape;
41    /// Reads the field.
42    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<F>;
43    /// Writes the field.
44    fn write(f: &F) -> Value;
45    /// The field's value when it isn't there (`None`: it's required).
46    #[must_use]
47    fn absent() -> Option<F> {
48        None
49    }
50    /// Whether a struct leaves the field out.
51    fn skip(_f: &F) -> bool {
52        false
53    }
54    /// The field in the binary form, straight: its value encoded unless
55    /// the codec knows better.
56    fn encode(f: &F, w: &mut Writer) {
57        w.value(&Self::write(f));
58    }
59    /// The field from the binary form, straight; `None` sends the read the
60    /// slow way (see [`Schema::decode`]).
61    fn decode(d: &mut Decoder<'_>) -> Option<F> {
62        let arena = bumpalo::Bump::new();
63        let v = d.value_ref(&arena).ok()?;
64        let mut cx = Reader::new();
65        let f = Self::read(&v, &mut cx)?;
66        cx.problems.is_empty().then_some(f)
67    }
68    /// The field packed into a frame: its binary form as bytes unless the
69    /// codec knows better.
70    fn pack(f: &F, p: &mut Packer) {
71        let mut w = Writer::body();
72        Self::encode(f, &mut w);
73        p.put_bytes(&w.finish());
74    }
75    /// The field out of a frame.
76    fn unpack(u: &mut Unpacker<'_>) -> Option<F> {
77        let mut d = Decoder::body(u.bytes()?);
78        let f = Self::decode(&mut d)?;
79        d.at_end().then_some(f)
80    }
81}
82
83/// A reference of kind(s) `K`, kept as the resolved id.
84#[derive(Debug)]
85pub struct RefTo<K>(PhantomData<K>);
86
87impl<K: Kinds> With<K::Id> for RefTo<K> {
88    fn shape() -> Shape {
89        super::ref_shape::<K>()
90    }
91    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<K::Id> {
92        super::read_id::<K>(v, cx)
93    }
94    fn write(f: &K::Id) -> Value {
95        Value::Ref(Ref::new(
96            K::first(),
97            crate::model::value::RefKey::spelled(&crate::schema::RefId::spell(f)),
98        ))
99    }
100    fn pack(f: &K::Id, p: &mut Packer) {
101        f.pack(p);
102    }
103    fn unpack(u: &mut Unpacker<'_>) -> Option<K::Id> {
104        K::Id::unpack(u)
105    }
106}
107
108/// Text as it's spelled — markup's attribute, which may spell a reference
109/// (`@file:images/logo.png`): a string kept as written, a typed value as its
110/// spelling. Nothing is checked or resolved here.
111#[derive(Debug)]
112pub struct Spelled;
113
114impl With<String> for Spelled {
115    fn shape() -> Shape {
116        Shape::Str
117    }
118    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<String> {
119        if let ValueRef::Str(s) = v {
120            return Some(s.to_string());
121        }
122        let spelled = crate::typed::spelling(&v.to_value());
123        if spelled.is_none() {
124            cx.expected(super::Expected::Text, v);
125        }
126        spelled
127    }
128    fn write(f: &String) -> Value {
129        Value::Str(f.clone())
130    }
131}
132
133/// An optional field through `W`.
134#[derive(Debug)]
135pub struct Opt<W>(PhantomData<W>);
136
137impl<F, W: With<F>> With<Option<F>> for Opt<W> {
138    fn shape() -> Shape {
139        Shape::Optional(W::shape)
140    }
141    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Option<F>> {
142        if v.is_null() {
143            Some(None)
144        } else {
145            W::read(v, cx).map(Some)
146        }
147    }
148    fn write(f: &Option<F>) -> Value {
149        f.as_ref().map_or(Value::Null, W::write)
150    }
151    fn absent() -> Option<Option<F>> {
152        Some(None)
153    }
154    fn skip(f: &Option<F>) -> bool {
155        f.is_none()
156    }
157}
158
159/// A list, each item through `W`.
160#[derive(Debug)]
161pub struct List<W>(PhantomData<W>);
162
163impl<F, W: With<F>> With<Vec<F>> for List<W> {
164    fn shape() -> Shape {
165        Shape::List(W::shape)
166    }
167    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Vec<F>> {
168        let ValueRef::List(items) = v else {
169            cx.expected(super::Expected::List, v);
170            return None;
171        };
172        let mut out = Vec::with_capacity(items.len());
173        let mut ok = true;
174        for (i, item) in items.iter().enumerate() {
175            match cx.at(Seg::Index(i), |cx| W::read(item, cx)) {
176                Some(x) => out.push(x),
177                None => ok = false,
178            }
179        }
180        ok.then_some(out)
181    }
182    fn write(f: &Vec<F>) -> Value {
183        Value::List(f.iter().map(W::write).collect())
184    }
185}
186
187/// An object of any keys, each value through `W`.
188#[derive(Debug)]
189pub struct Values<W>(PhantomData<W>);
190
191impl<F, W: With<F>> With<BTreeMap<String, F>> for Values<W> {
192    fn shape() -> Shape {
193        Shape::Map(W::shape)
194    }
195    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<BTreeMap<String, F>> {
196        read_values::<F, W, _>(v, cx)
197    }
198    fn write(f: &BTreeMap<String, F>) -> Value {
199        write_values::<F, W>(f.iter())
200    }
201}
202
203impl<F, W: With<F>> With<HashMap<String, F>> for Values<W> {
204    fn shape() -> Shape {
205        Shape::Map(W::shape)
206    }
207    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<HashMap<String, F>> {
208        read_values::<F, W, _>(v, cx)
209    }
210    fn write(f: &HashMap<String, F>) -> Value {
211        write_values::<F, W>(f.iter())
212    }
213}
214
215/// An object's entries (its notes left out), each value through `W`.
216fn read_values<F, W: With<F>, M: Default + Extend<(String, F)>>(
217    v: &ValueRef<'_>,
218    cx: &mut Reader<'_>,
219) -> Option<M> {
220    let map = cx.map(v)?;
221    let mut out = M::default();
222    let mut ok = true;
223    for (k, item) in map.iter().filter(|(k, _)| !is_metadata_key(k)) {
224        match cx.at(Seg::Key(k.to_string()), |cx| W::read(item, cx)) {
225            Some(x) => out.extend([(k.to_string(), x)]),
226            None => ok = false,
227        }
228    }
229    ok.then_some(out)
230}
231
232fn write_values<'a, F: 'a, W: With<F>>(
233    entries: impl Iterator<Item = (&'a String, &'a F)>,
234) -> Value {
235    Value::Map(
236        entries
237            .map(|(k, v)| (k.clone(), W::write(v)))
238            .collect::<Map>(),
239    )
240}
241
242/// The field's own schema — `with` spelled out (`List<Plain>` for a `Vec<T: Schema>`).
243#[derive(Debug)]
244pub struct Plain;
245
246impl<F: Schema> With<F> for Plain {
247    fn shape() -> Shape {
248        F::shape()
249    }
250    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<F> {
251        F::read(v, cx)
252    }
253    fn write(f: &F) -> Value {
254        f.write()
255    }
256    fn absent() -> Option<F> {
257        F::absent()
258    }
259    fn skip(f: &F) -> bool {
260        f.skip()
261    }
262    fn encode(f: &F, w: &mut Writer) {
263        f.encode(w);
264    }
265    fn decode(d: &mut Decoder<'_>) -> Option<F> {
266        F::decode(d)
267    }
268    fn pack(f: &F, p: &mut Packer) {
269        f.pack(p);
270    }
271    fn unpack(u: &mut Unpacker<'_>) -> Option<F> {
272        F::unpack(u)
273    }
274}
275
276/// Bytes as they are (`Vec<u8>`): a payload a format doesn't look into.
277#[derive(Debug)]
278pub struct Raw;
279
280impl With<Vec<u8>> for Raw {
281    fn shape() -> Shape {
282        Shape::Bytes
283    }
284    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Vec<u8>> {
285        match v {
286            ValueRef::Bytes(b) => Some(b.to_vec()),
287            // As text: `@bytes:<base64>`.
288            ValueRef::Str(s) => {
289                if let crate::typed::Spelled::Bytes(b) = crate::typed::classify(s)
290                    .map_err(|e| cx.problem_of(crate::Problem::BadTyped, e.to_string()))
291                    .ok()?
292                {
293                    Some(b)
294                } else {
295                    cx.expected(super::Expected::Bytes, v);
296                    None
297                }
298            }
299            other => {
300                cx.expected(super::Expected::Bytes, other);
301                None
302            }
303        }
304    }
305    fn write(f: &Vec<u8>) -> Value {
306        Value::Bytes(f.clone())
307    }
308    fn encode(f: &Vec<u8>, w: &mut Writer) {
309        w.bytes(f);
310    }
311    fn decode(d: &mut Decoder<'_>) -> Option<Vec<u8>> {
312        d.bytes().map(<[u8]>::to_vec)
313    }
314    fn pack(f: &Vec<u8>, p: &mut Packer) {
315        p.put_bytes(f);
316    }
317    fn unpack(u: &mut Unpacker<'_>) -> Option<Vec<u8>> {
318        u.bytes().map(<[u8]>::to_vec)
319    }
320    fn absent() -> Option<Vec<u8>> {
321        Some(Vec::new())
322    }
323}