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