Skip to main content

yog_data/schema/
plain.rs

1//! The schemas of plain types: numbers, strings, lists, maps.
2use super::{
3    BTreeMap, Decoder, HashMap, Packer, Reader, Schema, Seg, Shape, Unpacker, Value, ValueRef,
4    Writer, is_metadata_key, typed,
5};
6
7/// What a typed value's string starts with (`@item:…`).
8fn typed_mark() -> char {
9    yog_ids::sep::TYPED.chars().next().unwrap_or_default()
10}
11
12// ── Plain types ─────────────────────────────────────────────────────────────
13
14impl Schema for Value {
15    fn shape() -> Shape {
16        Shape::Any
17    }
18    fn read(v: &ValueRef<'_>, _: &mut Reader) -> Option<Self> {
19        Some(v.to_value())
20    }
21    fn write(&self) -> Value {
22        self.clone()
23    }
24}
25
26impl Schema for bool {
27    fn shape() -> Shape {
28        Shape::Bool
29    }
30    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
31        v.as_bool().or_else(|| {
32            cx.expected("true or false", v);
33            None
34        })
35    }
36    fn write(&self) -> Value {
37        Value::Bool(*self)
38    }
39    fn encode(&self, w: &mut Writer) {
40        w.bool(*self);
41    }
42    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
43        d.bool()
44    }
45    fn pack(&self, p: &mut Packer) {
46        p.put_bool(*self);
47    }
48    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
49        u.get_bool()
50    }
51}
52
53macro_rules! int_schema {
54    ($($t:ty => $to_bits:ident, $of_bits:ident);*) => {$(
55        impl Schema for $t {
56            fn shape() -> Shape {
57                Shape::Int { min: <$t>::MIN as i64, max: (<$t>::MAX as u64).min(i64::MAX as u64) as i64 }
58            }
59            fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
60                let Some(n) = v.as_i64() else {
61                    cx.expected("an integer", v);
62                    return None;
63                };
64                <$t>::try_from(n).ok().or_else(|| {
65                    cx.problem(format!("{n} is out of range ({}..={})", <$t>::MIN, <$t>::MAX));
66                    None
67                })
68            }
69            fn write(&self) -> Value {
70                Value::Int(*self as i64)
71            }
72            fn encode(&self, w: &mut Writer) {
73                w.int(*self as i64);
74            }
75            fn decode(d: &mut Decoder<'_>) -> Option<Self> {
76                d.int().and_then(|n| <$t>::try_from(n).ok())
77            }
78            fn pack(&self, p: &mut Packer) {
79                p.put_i(*self as i64);
80            }
81            fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
82                u.get_i().and_then(|n| <$t>::try_from(n).ok())
83            }
84            fn pack_list(items: &[Self], p: &mut Packer) {
85                p.put_uints(items.len(), items.iter().map(|&n| $to_bits(n as i128)));
86            }
87            fn unpack_list(u: &mut Unpacker<'_>) -> Option<Vec<Self>> {
88                u.get_uints(|v| <$t>::try_from($of_bits(v)).ok())
89            }
90            fn encode_list(items: &[Self], w: &mut Writer) {
91                w.ints(items.iter().map(|&n| n as i64));
92            }
93            fn decode_list(d: &mut Decoder<'_>) -> Option<Vec<Self>> {
94                let n = d.ints()?;
95                let mut out = Vec::with_capacity(n);
96                for _ in 0..n {
97                    out.push(<$t>::try_from(d.packed_int()?).ok()?);
98                }
99                Some(out)
100            }
101        }
102    )*};
103}
104int_schema!(
105    i8 => signed_bits, signed_of; i16 => signed_bits, signed_of; i32 => signed_bits, signed_of; i64 => signed_bits, signed_of;
106    u8 => unsigned_bits, unsigned_of; u16 => unsigned_bits, unsigned_of; u32 => unsigned_bits, unsigned_of;
107    u64 => unsigned_bits, unsigned_of; usize => unsigned_bits, unsigned_of
108);
109
110/// A signed number as a bit-packed list's bits: zigzagged, small either way.
111fn signed_bits(n: i128) -> u64 {
112    crate::binary::zigzag(n as i64)
113}
114
115fn signed_of(v: u64) -> i128 {
116    i128::from(crate::binary::unzigzag(v))
117}
118
119/// An unsigned number as a bit-packed list's bits: itself.
120fn unsigned_bits(n: i128) -> u64 {
121    n as u64
122}
123
124fn unsigned_of(v: u64) -> i128 {
125    i128::from(v)
126}
127
128macro_rules! float_schema {
129    ($($t:ty => $one:ident, $many:ident, $read_many:ident, $put:ident, $get:ident, $puts:ident, $gets:ident);*) => {$(
130        impl Schema for $t {
131            fn shape() -> Shape {
132                Shape::Float { bits: u8::BITS * std::mem::size_of::<$t>() as u32 }
133            }
134            fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
135                v.as_f64().map(|f| f as $t).or_else(|| {
136                    cx.expected("a number", v);
137                    None
138                })
139            }
140            fn write(&self) -> Value {
141                Value::Float(*self as f64)
142            }
143            fn encode(&self, w: &mut Writer) {
144                w.$one(*self);
145            }
146            fn decode(d: &mut Decoder<'_>) -> Option<Self> {
147                d.float().map(|f| f as $t)
148            }
149            fn encode_list(items: &[Self], w: &mut Writer) {
150                w.$many(items);
151            }
152            fn decode_list(d: &mut Decoder<'_>) -> Option<Vec<Self>> {
153                d.$read_many()
154            }
155            fn pack(&self, p: &mut Packer) {
156                p.$put(*self);
157            }
158            fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
159                u.$get()
160            }
161            fn pack_list(items: &[Self], p: &mut Packer) {
162                p.$puts(items);
163            }
164            fn unpack_list(u: &mut Unpacker<'_>) -> Option<Vec<Self>> {
165                u.$gets()
166            }
167        }
168    )*};
169}
170float_schema!(
171    f32 => float32, floats32, floats32, put_f32, get_f32, put_f32s, get_f32s;
172    f64 => float, floats, floats, put_f64, get_f64, put_f64s, get_f64s
173);
174
175impl Schema for String {
176    fn shape() -> Shape {
177        Shape::Str
178    }
179    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
180        match v {
181            // Plain text, the usual case: copied once, into the result.
182            ValueRef::Str(s) if !s.starts_with('@') => Some(s.to_string()),
183            ValueRef::Str(s) => match typed::classify(s) {
184                Ok(Value::Str(s)) => Some(s),
185                Ok(other) => {
186                    cx.problem(format!(
187                        "expected plain text, found {} (write `@@` for a literal `@`)",
188                        other.kind_name()
189                    ));
190                    None
191                }
192                Err(e) => {
193                    cx.problem_of(yog_ids::data_problem::BAD_TYPED, e);
194                    None
195                }
196            },
197            other => {
198                cx.expected("a string", other);
199                None
200            }
201        }
202    }
203    fn write(&self) -> Value {
204        Value::Str(self.clone())
205    }
206    fn encode(&self, w: &mut Writer) {
207        w.str(self);
208    }
209    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
210        // A typed value (`@…`) is the slow way's to tell apart.
211        d.str()
212            .filter(|s| !s.starts_with(typed_mark()))
213            .map(str::to_owned)
214    }
215    fn pack(&self, p: &mut Packer) {
216        p.put_str(self);
217    }
218    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
219        u.get_str().map(str::to_owned)
220    }
221}
222
223/// Text that may be a constant: borrowed where it's written, owned once read.
224impl Schema for std::borrow::Cow<'static, str> {
225    fn shape() -> Shape {
226        Shape::Str
227    }
228    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
229        String::read(v, cx).map(Self::Owned)
230    }
231    fn write(&self) -> Value {
232        Value::Str(self.to_string())
233    }
234    fn encode(&self, w: &mut Writer) {
235        w.str(self);
236    }
237    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
238        String::decode(d).map(Self::Owned)
239    }
240    fn pack(&self, p: &mut Packer) {
241        p.put_str(self);
242    }
243    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
244        String::unpack(u).map(Self::Owned)
245    }
246}
247
248/// A file's path, as text (a path that isn't Unicode loses what isn't).
249impl Schema for std::path::PathBuf {
250    fn shape() -> Shape {
251        Shape::Str
252    }
253    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
254        String::read(v, cx).map(Self::from)
255    }
256    fn write(&self) -> Value {
257        Value::Str(self.to_string_lossy().into_owned())
258    }
259    fn encode(&self, w: &mut Writer) {
260        w.str(&self.to_string_lossy());
261    }
262    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
263        String::decode(d).map(Self::from)
264    }
265    fn pack(&self, p: &mut Packer) {
266        p.put_str(&self.to_string_lossy());
267    }
268    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
269        u.get_str().map(Self::from)
270    }
271}
272
273/// Text everywhere but in a frame, which carries its number.
274impl Schema for crate::Atom {
275    fn shape() -> Shape {
276        Shape::Atom
277    }
278    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
279        String::read(v, cx).map(|s| crate::Atom::new(&s))
280    }
281    fn write(&self) -> Value {
282        Value::Str(self.as_str().to_owned())
283    }
284    fn encode(&self, w: &mut Writer) {
285        w.str(self.as_str());
286    }
287    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
288        d.str()
289            .filter(|s| !s.starts_with(typed_mark()))
290            .map(crate::Atom::new)
291    }
292    fn pack(&self, p: &mut Packer) {
293        p.put_u(u64::from(self.number()));
294    }
295    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
296        crate::Atom::from_number(u32::try_from(u.get_u()?).ok()?)
297    }
298}
299
300impl<T: Schema> Schema for Option<T> {
301    fn shape() -> Shape {
302        Shape::Optional(T::shape)
303    }
304    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
305        if v.is_null() {
306            Some(None)
307        } else {
308            T::read(v, cx).map(Some)
309        }
310    }
311    fn write(&self) -> Value {
312        self.as_ref().map_or(Value::Null, T::write)
313    }
314    fn encode(&self, w: &mut Writer) {
315        match self {
316            Some(v) => v.encode(w),
317            None => {
318                w.null();
319            }
320        }
321    }
322    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
323        if d.null() {
324            Some(None)
325        } else {
326            T::decode(d).map(Some)
327        }
328    }
329    fn pack(&self, p: &mut Packer) {
330        p.put_bool(self.is_some());
331        if let Some(v) = self {
332            v.pack(p);
333        }
334    }
335    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
336        if u.get_bool()? {
337            T::unpack(u).map(Some)
338        } else {
339            Some(None)
340        }
341    }
342    fn absent() -> Option<Self> {
343        Some(None)
344    }
345    fn skip(&self) -> bool {
346        self.is_none()
347    }
348}
349
350impl<T: Schema> Schema for Box<T> {
351    fn shape() -> Shape {
352        T::shape()
353    }
354    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
355        T::read(v, cx).map(Box::new)
356    }
357    fn write(&self) -> Value {
358        (**self).write()
359    }
360    fn encode(&self, w: &mut Writer) {
361        (**self).encode(w);
362    }
363    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
364        T::decode(d).map(Box::new)
365    }
366    fn pack(&self, p: &mut Packer) {
367        (**self).pack(p);
368    }
369    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
370        T::unpack(u).map(Box::new)
371    }
372    fn absent() -> Option<Self> {
373        T::absent().map(Box::new)
374    }
375    fn skip(&self) -> bool {
376        (**self).skip()
377    }
378}
379
380impl<T: Schema> Schema for Vec<T> {
381    fn shape() -> Shape {
382        Shape::List(T::shape)
383    }
384    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
385        let ValueRef::List(items) = v else {
386            cx.expected("a list", v);
387            return None;
388        };
389        let mut out = Vec::with_capacity(items.len());
390        let mut ok = true;
391        for (i, item) in items.iter().enumerate() {
392            match cx.at(Seg::Index(i), |cx| T::read(item, cx)) {
393                Some(x) => out.push(x),
394                None => ok = false,
395            }
396        }
397        ok.then_some(out)
398    }
399    fn write(&self) -> Value {
400        Value::List(self.iter().map(T::write).collect())
401    }
402    fn encode(&self, w: &mut Writer) {
403        T::encode_list(self, w);
404    }
405    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
406        T::decode_list(d)
407    }
408    fn pack(&self, p: &mut Packer) {
409        T::pack_list(self, p);
410    }
411    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
412        T::unpack_list(u)
413    }
414}
415
416/// A set: a list, in order, each once.
417impl<T: Schema + Ord + Clone> Schema for std::collections::BTreeSet<T> {
418    fn shape() -> Shape {
419        Shape::List(T::shape)
420    }
421    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
422        Vec::<T>::read(v, cx).map(Self::from_iter)
423    }
424    fn write(&self) -> Value {
425        Value::List(self.iter().map(T::write).collect())
426    }
427    fn encode(&self, w: &mut Writer) {
428        // As a list of them is written (numbers packed).
429        T::encode_list(&self.iter().cloned().collect::<Vec<_>>(), w);
430    }
431    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
432        Vec::<T>::decode(d).map(Self::from_iter)
433    }
434}
435
436/// A string that won't change: a pointer and a length, no spare capacity
437/// (`String`'s third word) — what big tables of names keep.
438impl Schema for Box<str> {
439    fn shape() -> Shape {
440        Shape::Str
441    }
442    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
443        String::read(v, cx).map(String::into_boxed_str)
444    }
445    fn write(&self) -> Value {
446        Value::Str(self.to_string())
447    }
448    fn encode(&self, w: &mut Writer) {
449        w.str(self);
450    }
451    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
452        String::decode(d).map(String::into_boxed_str)
453    }
454    fn pack(&self, p: &mut Packer) {
455        p.put_str(self);
456    }
457    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
458        u.get_str().map(Into::into)
459    }
460}
461
462/// A string shared without copying.
463impl Schema for yog_sync::Arc<str> {
464    fn shape() -> Shape {
465        Shape::Str
466    }
467    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
468        String::read(v, cx).map(Into::into)
469    }
470    fn write(&self) -> Value {
471        Value::Str(self.to_string())
472    }
473    fn encode(&self, w: &mut Writer) {
474        w.str(self);
475    }
476    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
477        String::decode(d).map(Into::into)
478    }
479    fn pack(&self, p: &mut Packer) {
480        p.put_str(self);
481    }
482    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
483        u.get_shared_str()
484    }
485}
486
487/// A list that won't change: no spare capacity.
488impl<T: Schema> Schema for Box<[T]> {
489    fn shape() -> Shape {
490        Shape::List(T::shape)
491    }
492    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
493        Vec::<T>::read(v, cx).map(Vec::into_boxed_slice)
494    }
495    fn write(&self) -> Value {
496        Value::List(self.iter().map(T::write).collect())
497    }
498    fn encode(&self, w: &mut Writer) {
499        T::encode_list(self, w);
500    }
501    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
502        T::decode_list(d).map(Vec::into_boxed_slice)
503    }
504    fn pack(&self, p: &mut Packer) {
505        T::pack_list(self, p);
506    }
507    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
508        T::unpack_list(u).map(Vec::into_boxed_slice)
509    }
510}
511
512impl<T: Schema, const N: usize> Schema for [T; N] {
513    fn shape() -> Shape {
514        Shape::List(T::shape)
515    }
516    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
517        let items = Vec::<T>::read(v, cx)?;
518        let len = items.len();
519        items.try_into().ok().or_else(|| {
520            cx.problem(format!("expected {N} items, found {len}"));
521            None
522        })
523    }
524    fn write(&self) -> Value {
525        Value::List(self.iter().map(T::write).collect())
526    }
527    fn encode(&self, w: &mut Writer) {
528        T::encode_list(self, w);
529    }
530    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
531        T::decode_list(d)?.try_into().ok()
532    }
533    fn pack(&self, p: &mut Packer) {
534        T::pack_list(self, p);
535    }
536    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
537        T::unpack_list(u)?.try_into().ok()
538    }
539}
540
541/// Nothing: what a call answers when it only says it's done.
542impl Schema for () {
543    fn shape() -> Shape {
544        Shape::Any
545    }
546    fn read(_v: &ValueRef<'_>, _cx: &mut Reader) -> Option<Self> {
547        Some(())
548    }
549    fn write(&self) -> Value {
550        Value::Null
551    }
552}
553
554/// What may fail: `{ "ok": T }` or `{ "err": E }`.
555impl<T: Schema, E: Schema> Schema for Result<T, E> {
556    fn shape() -> Shape {
557        Shape::Any
558    }
559    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
560        let ValueRef::Map(m) = v else {
561            cx.expected("{ ok } or { err }", v);
562            return None;
563        };
564        if let Some(ok) = m.get(RESULT_OK) {
565            return cx
566                .at(Seg::Key(RESULT_OK.into()), |cx| T::read(ok, cx))
567                .map(Ok);
568        }
569        let Some(err) = m.get(RESULT_ERR) else {
570            cx.expected("{ ok } or { err }", v);
571            return None;
572        };
573        cx.at(Seg::Key(RESULT_ERR.into()), |cx| E::read(err, cx))
574            .map(Err)
575    }
576    fn write(&self) -> Value {
577        let (key, value) = match self {
578            Ok(t) => (RESULT_OK, t.write()),
579            Err(e) => (RESULT_ERR, e.write()),
580        };
581        Value::Map([(key.to_owned(), value)].into_iter().collect())
582    }
583}
584
585/// The keys of a [`Result`]'s two sides.
586pub(crate) const RESULT_OK: &str = "ok";
587pub(crate) const RESULT_ERR: &str = "err";
588
589/// A tuple, written as a list of its items in order: a pair `[a, b]` (a
590/// point, a size), a triple `[x, y, z]` (a position).
591macro_rules! tuples {
592    ($($what:literal: $n:literal => ($($t:ident $i:tt),+);)+) => {$(
593        impl<$($t: Schema),+> Schema for ($($t,)+) {
594            fn shape() -> Shape {
595                Shape::List(Value::shape)
596            }
597            fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
598                let ValueRef::List(items) = v else {
599                    cx.expected($what, v);
600                    return None;
601                };
602                if items.len() != $n {
603                    cx.problem(format!("expected {} items, found {}", $n, items.len()));
604                    return None;
605                }
606                let read = ($(cx.at(Seg::Index($i), |cx| $t::read(&items[$i], cx)),)+);
607                Some(($(read.$i?,)+))
608            }
609            fn write(&self) -> Value {
610                Value::List(vec![$(self.$i.write()),+])
611            }
612        }
613    )+};
614}
615
616tuples! {
617    "a pair [a, b]": 2 => (A 0, B 1);
618    "a triple [a, b, c]": 3 => (A 0, B 1, C 2);
619    "four [a, b, c, d]": 4 => (A 0, B 1, C 2, D 3);
620}
621
622fn read_map<T: Schema>(
623    v: &ValueRef,
624    cx: &mut Reader,
625    mut put: impl FnMut(String, T),
626) -> Option<()> {
627    let map = cx.map(v)?;
628    let mut ok = true;
629    for (k, item) in map.iter() {
630        if is_metadata_key(k) {
631            continue;
632        }
633        match cx.at(Seg::Key(k.to_string()), |cx| T::read(item, cx)) {
634            Some(x) => put(k.to_string(), x),
635            None => ok = false,
636        }
637    }
638    ok.then_some(())
639}
640
641impl<T: Schema> Schema for BTreeMap<String, T> {
642    fn shape() -> Shape {
643        Shape::Map(T::shape)
644    }
645    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
646        let mut out = BTreeMap::new();
647        read_map(v, cx, |k, x| {
648            out.insert(k, x);
649        })?;
650        Some(out)
651    }
652    fn write(&self) -> Value {
653        Value::Map(self.iter().map(|(k, v)| (k.clone(), v.write())).collect())
654    }
655}
656
657impl<T: Schema> Schema for HashMap<String, T> {
658    fn shape() -> Shape {
659        Shape::Map(T::shape)
660    }
661    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
662        let mut out = HashMap::new();
663        read_map(v, cx, |k, x| {
664            out.insert(k, x);
665        })?;
666        Some(out)
667    }
668    fn write(&self) -> Value {
669        let mut keys: Vec<&String> = self.keys().collect();
670        keys.sort();
671        Value::Map(
672            keys.into_iter()
673                .map(|k| (k.clone(), self[k].write()))
674                .collect(),
675        )
676    }
677}
678
679/// An object kept in file order, values of one schema.
680#[derive(Debug, Clone, PartialEq)]
681pub struct Ordered<T>(pub Vec<(String, T)>);
682
683impl<T> Default for Ordered<T> {
684    fn default() -> Self {
685        Self(Vec::new())
686    }
687}
688
689impl<T: Schema> Schema for Ordered<T> {
690    fn shape() -> Shape {
691        Shape::Map(T::shape)
692    }
693    fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
694        let mut out = Vec::new();
695        read_map(v, cx, |k, x| out.push((k, x)))?;
696        Some(Ordered(out))
697    }
698    fn write(&self) -> Value {
699        Value::Map(self.0.iter().map(|(k, v)| (k.clone(), v.write())).collect())
700    }
701}