Skip to main content

tabnas_alchemy/shared/
datum.rs

1//! The retained value type.
2//!
3//! What a capture materializes and what a projected cell holds. Distinct
4//! from the engine's `Value` on purpose: a datum keeps a number's lexeme,
5//! measures its own size against limits, and is owned by the transducer
6//! rather than shared with a parse.
7
8use std::fmt;
9
10use indexmap::IndexMap;
11
12use crate::shared::error::{Code, Fail};
13use crate::shared::event::{JsonEvent, Number};
14use crate::shared::limits::NODE_BYTES;
15use crate::shared::selector::Segment;
16use crate::shared::sink::{Flow, Sink};
17
18/// A retained JSON-like value.
19#[derive(Clone, Debug, PartialEq)]
20pub enum Datum {
21    Null,
22    Bool(bool),
23    Number {
24        value: f64,
25        lexeme: Option<Box<str>>,
26    },
27    String(Box<str>),
28    Array(Vec<Datum>),
29    /// Members in source order. A repeated member replaces the earlier one
30    /// (last value wins) unless the builder's policy rejected it first.
31    Object(IndexMap<Box<str>, Datum>),
32}
33
34impl Datum {
35    /// Payload bytes plus [`NODE_BYTES`] per node: the measure limits use.
36    pub fn byte_size(&self) -> usize {
37        match self {
38            Datum::Null | Datum::Bool(_) => NODE_BYTES,
39            Datum::Number { lexeme, .. } => NODE_BYTES + lexeme.as_ref().map_or(8, |l| l.len()),
40            Datum::String(s) => NODE_BYTES + s.len(),
41            Datum::Array(items) => NODE_BYTES + items.iter().map(Datum::byte_size).sum::<usize>(),
42            Datum::Object(members) => {
43                NODE_BYTES
44                    + members
45                        .iter()
46                        .map(|(k, v)| k.len() + v.byte_size())
47                        .sum::<usize>()
48            }
49        }
50    }
51
52    /// The value at a concrete path below this one.
53    pub fn get_path(&self, path: &[Segment]) -> Option<&Datum> {
54        let mut here = self;
55        for seg in path {
56            here = match (seg, here) {
57                (Segment::Key(k), Datum::Object(m)) => m.get(k.as_ref())?,
58                (Segment::Index(i), Datum::Array(a)) => a.get(*i)?,
59                _ => return None,
60            };
61        }
62        Some(here)
63    }
64
65    /// The value at a concrete path below this one, moved out and replaced
66    /// by `Null`. For a consumer that owns the datum and reads each path
67    /// once: a later read of the same path, or of one below it, finds the
68    /// `Null`, so the caller checks its paths are disjoint first.
69    pub fn take_path(&mut self, path: &[Segment]) -> Option<Datum> {
70        let mut here = self;
71        for seg in path {
72            here = match (seg, here) {
73                (Segment::Key(k), Datum::Object(m)) => m.get_mut(k.as_ref())?,
74                (Segment::Index(i), Datum::Array(a)) => a.get_mut(*i)?,
75                _ => return None,
76            };
77        }
78        Some(std::mem::replace(here, Datum::Null))
79    }
80
81    pub fn is_container(&self) -> bool {
82        matches!(self, Datum::Array(_) | Datum::Object(_))
83    }
84
85    pub fn as_str(&self) -> Option<&str> {
86        match self {
87            Datum::String(s) => Some(s),
88            _ => None,
89        }
90    }
91
92    pub fn as_array(&self) -> Option<&[Datum]> {
93        match self {
94            Datum::Array(a) => Some(a),
95            _ => None,
96        }
97    }
98
99    pub fn as_object(&self) -> Option<&IndexMap<Box<str>, Datum>> {
100        match self {
101            Datum::Object(m) => Some(m),
102            _ => None,
103        }
104    }
105
106    /// From an engine value. `Undefined` becomes `Null`, as the engine's
107    /// own serialization has it; the metadata wrappers unwrap. With the
108    /// `tabnas` feature, which the `language` feature turns on.
109    #[cfg(feature = "tabnas")]
110    pub fn from_tabnas(value: &tabnas::Value) -> Datum {
111        match value {
112            tabnas::Value::Undefined | tabnas::Value::Null => Datum::Null,
113            tabnas::Value::Bool(b) => Datum::Bool(*b),
114            tabnas::Value::Number(n) => Datum::Number {
115                value: *n,
116                lexeme: None,
117            },
118            tabnas::Value::String(s) => Datum::String(s.as_str().into()),
119            tabnas::Value::Text(t) => Datum::String(t.string.as_str().into()),
120            tabnas::Value::Array(a) => Datum::Array(a.iter().map(Datum::from_tabnas).collect()),
121            tabnas::Value::ListRef(l) => {
122                Datum::Array(l.value.iter().map(Datum::from_tabnas).collect())
123            }
124            tabnas::Value::Object(m) => Datum::Object(
125                m.iter()
126                    .map(|(k, v)| (k.as_str().into(), Datum::from_tabnas(v)))
127                    .collect(),
128            ),
129            tabnas::Value::MapRef(m) => Datum::Object(
130                m.value
131                    .iter()
132                    .map(|(k, v)| (k.as_str().into(), Datum::from_tabnas(v)))
133                    .collect(),
134            ),
135        }
136    }
137
138    /// As a `serde_json` value, for oracles and tests. serde_json's number
139    /// is an f64 (or an integer that fits), so a lexeme with more digits
140    /// than that loses them here; [`Datum`]'s `Display` keeps them.
141    pub fn to_json(&self) -> serde_json::Value {
142        match self {
143            Datum::Null => serde_json::Value::Null,
144            Datum::Bool(b) => serde_json::Value::Bool(*b),
145            Datum::Number { value, lexeme } => lexeme
146                .as_deref()
147                .and_then(|l| l.parse::<serde_json::Number>().ok())
148                .map(serde_json::Value::Number)
149                .or_else(|| serde_json::Number::from_f64(*value).map(serde_json::Value::Number))
150                .unwrap_or(serde_json::Value::Null),
151            Datum::String(s) => serde_json::Value::String(s.to_string()),
152            Datum::Array(a) => serde_json::Value::Array(a.iter().map(Datum::to_json).collect()),
153            Datum::Object(m) => serde_json::Value::Object(
154                m.iter()
155                    .map(|(k, v)| (k.to_string(), v.to_json()))
156                    .collect(),
157            ),
158        }
159    }
160
161    /// From a `serde_json` value, for tests.
162    pub fn from_json(value: &serde_json::Value) -> Datum {
163        match value {
164            serde_json::Value::Null => Datum::Null,
165            serde_json::Value::Bool(b) => Datum::Bool(*b),
166            serde_json::Value::Number(n) => Datum::Number {
167                value: n.as_f64().unwrap_or(f64::NAN),
168                lexeme: Some(n.to_string().into()),
169            },
170            serde_json::Value::String(s) => Datum::String(s.as_str().into()),
171            serde_json::Value::Array(a) => Datum::Array(a.iter().map(Datum::from_json).collect()),
172            serde_json::Value::Object(m) => Datum::Object(
173                m.iter()
174                    .map(|(k, v)| (k.as_str().into(), Datum::from_json(v)))
175                    .collect(),
176            ),
177        }
178    }
179}
180
181impl fmt::Display for Datum {
182    /// Compact JSON, keeping number lexemes.
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        let mut out = String::new();
185        write_json(self, &mut out);
186        f.write_str(&out)
187    }
188}
189
190/// Append `s` as a JSON string literal, escaped as RFC 8259 requires:
191/// `"` and `\\` escaped, control characters as `\\uXXXX` (with the short
192/// forms for `\\b \\f \\n \\r \\t`), everything else as itself.
193pub fn write_json_string(s: &str, out: &mut String) {
194    out.push('"');
195    for c in s.chars() {
196        match c {
197            '"' => out.push_str("\\\""),
198            '\\' => out.push_str("\\\\"),
199            '\u{8}' => out.push_str("\\b"),
200            '\u{c}' => out.push_str("\\f"),
201            '\n' => out.push_str("\\n"),
202            '\r' => out.push_str("\\r"),
203            '\t' => out.push_str("\\t"),
204            c if (c as u32) < 0x20 => {
205                out.push_str(&format!("\\u{:04x}", c as u32));
206            }
207            c => out.push(c),
208        }
209    }
210    out.push('"');
211}
212
213/// Append a number: its lexeme when known, else the shortest text that
214/// reads back as the same f64. A non-finite value has no JSON form and is
215/// written as `null`; renderers reject it before it gets here.
216pub fn write_json_number(value: f64, lexeme: Option<&str>, out: &mut String) {
217    match lexeme {
218        Some(l) => out.push_str(l),
219        None if value.is_finite() => out.push_str(&format!("{value}")),
220        None => out.push_str("null"),
221    }
222}
223
224/// Append a datum as compact JSON.
225pub fn write_json(d: &Datum, out: &mut String) {
226    match d {
227        Datum::Null => out.push_str("null"),
228        Datum::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
229        Datum::Number { value, lexeme } => write_json_number(*value, lexeme.as_deref(), out),
230        Datum::String(s) => write_json_string(s, out),
231        Datum::Array(items) => {
232            out.push('[');
233            for (i, item) in items.iter().enumerate() {
234                if i > 0 {
235                    out.push(',');
236                }
237                write_json(item, out);
238            }
239            out.push(']');
240        }
241        Datum::Object(members) => {
242            out.push('{');
243            for (i, (k, v)) in members.iter().enumerate() {
244                if i > 0 {
245                    out.push(',');
246                }
247                write_json_string(k, out);
248                out.push(':');
249                write_json(v, out);
250            }
251            out.push('}');
252        }
253    }
254}
255
256/// Emit a datum as `JsonEvents/1` (without the final `End`, so a datum can
257/// stand in for any part of a document).
258pub fn walk_datum(datum: &Datum, sink: &mut dyn Sink) -> Result<Flow, Fail> {
259    macro_rules! send {
260        ($ev:expr) => {
261            if sink.event($ev)? == Flow::Stop {
262                return Ok(Flow::Stop);
263            }
264        };
265    }
266    match datum {
267        Datum::Null => send!(JsonEvent::Null),
268        Datum::Bool(b) => send!(JsonEvent::Bool(*b)),
269        Datum::Number { value, lexeme } => send!(JsonEvent::Number(Number {
270            value: *value,
271            lexeme: lexeme.as_deref(),
272        })),
273        Datum::String(s) => send!(JsonEvent::String(s)),
274        Datum::Array(items) => {
275            send!(JsonEvent::ArrayStart);
276            for item in items {
277                if walk_datum(item, sink)? == Flow::Stop {
278                    return Ok(Flow::Stop);
279                }
280            }
281            send!(JsonEvent::ArrayEnd);
282        }
283        Datum::Object(members) => {
284            send!(JsonEvent::ObjectStart);
285            for (k, v) in members {
286                send!(JsonEvent::Key(k));
287                if walk_datum(v, sink)? == Flow::Stop {
288                    return Ok(Flow::Stop);
289                }
290            }
291            send!(JsonEvent::ObjectEnd);
292        }
293    }
294    Ok(Flow::Continue)
295}
296
297/// How a builder treats a repeated member name.
298#[derive(Clone, Copy, Debug, PartialEq, Eq)]
299pub enum Duplicates {
300    /// Fail with [`Code::DuplicateMember`].
301    Reject,
302    /// The later value replaces the earlier one.
303    LastWins,
304    /// The earlier value stays.
305    FirstWins,
306}
307
308/// Builds one [`Datum`] from the events of one value, under a byte limit.
309///
310/// Feed it every event from the value's first to its last; `finished()`
311/// says when the value is complete. Bytes are counted as they arrive, and
312/// the limit fails at the first byte over it rather than after the value
313/// is whole. The builder knows nothing of where in a document its value
314/// sits: a failure leaves `path` unset and the stage that placed the
315/// builder adds it, so no path is built for the values that succeed.
316#[derive(Debug)]
317pub struct DatumBuilder {
318    stack: Vec<Frame>,
319    done: Option<Datum>,
320    bytes: usize,
321    limit: usize,
322    limit_name: &'static str,
323    duplicates: Duplicates,
324}
325
326#[derive(Debug)]
327enum Frame {
328    Array(Vec<Datum>),
329    Object {
330        members: IndexMap<Box<str>, Datum>,
331        key: Option<Box<str>>,
332    },
333}
334
335impl DatumBuilder {
336    /// A builder whose limit failure names `limit_name` (a `Limits` field).
337    pub fn new(limit: usize, limit_name: &'static str, duplicates: Duplicates) -> Self {
338        DatumBuilder {
339            stack: Vec::new(),
340            done: None,
341            bytes: 0,
342            limit,
343            limit_name,
344            duplicates,
345        }
346    }
347
348    pub fn bytes(&self) -> usize {
349        self.bytes
350    }
351
352    pub fn finished(&self) -> bool {
353        self.done.is_some()
354    }
355
356    /// The value, once [`finished`](Self::finished). Probing an unfinished
357    /// builder returns `None` and leaves the charge for the partial value in
358    /// place: the bytes it holds are still held.
359    pub fn take(&mut self) -> Option<Datum> {
360        let done = self.done.take();
361        if done.is_some() {
362            self.bytes = 0;
363        }
364        done
365    }
366
367    fn charge(&mut self, n: usize) -> Result<(), Fail> {
368        self.bytes += n;
369        if self.bytes > self.limit {
370            return Err(Fail::limit(
371                self.limit_name,
372                self.limit as u64,
373                format!("a value is larger than {} bytes", self.limit),
374            ));
375        }
376        Ok(())
377    }
378
379    fn place(&mut self, value: Datum) -> Result<(), Fail> {
380        match self.stack.last_mut() {
381            None => self.done = Some(value),
382            Some(Frame::Array(items)) => items.push(value),
383            Some(Frame::Object { members, key }) => {
384                let key = key.take().ok_or_else(|| {
385                    Fail::protocol("a value arrived inside an object without a key")
386                })?;
387                // A repeated member was charged in full as its events arrived,
388                // which is right: for a moment both were held. Whichever one
389                // goes now gives its bytes back, so an object that keeps
390                // repeating a small key does not grow towards the limit while
391                // the value it holds stays the same size. A completed value's
392                // `byte_size` is exactly what its events were charged.
393                let mut released = 0;
394                if let Some(existing) = members.get(&key) {
395                    match self.duplicates {
396                        Duplicates::Reject => {
397                            return Err(Fail::new(
398                                Code::DuplicateMember,
399                                format!("member {key:?} appears twice"),
400                            ));
401                        }
402                        Duplicates::FirstWins => {
403                            self.bytes = self.bytes.saturating_sub(key.len() + value.byte_size());
404                            return Ok(());
405                        }
406                        Duplicates::LastWins => released = key.len() + existing.byte_size(),
407                    }
408                }
409                members.insert(key, value);
410                self.bytes = self.bytes.saturating_sub(released);
411            }
412        }
413        Ok(())
414    }
415
416    /// One event of the value being built.
417    pub fn event(&mut self, ev: JsonEvent<'_>) -> Result<(), Fail> {
418        if self.done.is_some() {
419            return Err(Fail::protocol(
420                "an event arrived after the value was complete",
421            ));
422        }
423        match ev {
424            JsonEvent::ObjectStart => {
425                self.charge(NODE_BYTES)?;
426                self.stack.push(Frame::Object {
427                    members: IndexMap::new(),
428                    key: None,
429                });
430            }
431            JsonEvent::ArrayStart => {
432                self.charge(NODE_BYTES)?;
433                self.stack.push(Frame::Array(Vec::new()));
434            }
435            JsonEvent::Key(k) => {
436                self.charge(k.len())?;
437                match self.stack.last_mut() {
438                    Some(Frame::Object { key, .. }) if key.is_none() => *key = Some(k.into()),
439                    _ => return Err(Fail::protocol("a key arrived where no member was expected")),
440                }
441            }
442            JsonEvent::ObjectEnd => match self.stack.pop() {
443                Some(Frame::Object { members, key: None }) => self.place(Datum::Object(members))?,
444                Some(Frame::Object { key: Some(_), .. }) => {
445                    return Err(Fail::protocol(
446                        "an object ended after a key without its value",
447                    ))
448                }
449                _ => return Err(Fail::protocol("an object ended that had not started")),
450            },
451            JsonEvent::ArrayEnd => match self.stack.pop() {
452                Some(Frame::Array(items)) => self.place(Datum::Array(items))?,
453                _ => return Err(Fail::protocol("an array ended that had not started")),
454            },
455            JsonEvent::Null => {
456                self.charge(NODE_BYTES)?;
457                self.place(Datum::Null)?;
458            }
459            JsonEvent::Bool(b) => {
460                self.charge(NODE_BYTES)?;
461                self.place(Datum::Bool(b))?;
462            }
463            JsonEvent::Number(n) => {
464                self.charge(NODE_BYTES + n.lexeme.map_or(8, str::len))?;
465                self.place(Datum::Number {
466                    value: n.value,
467                    lexeme: n.lexeme.map(Into::into),
468                })?;
469            }
470            JsonEvent::String(s) => {
471                self.charge(NODE_BYTES + s.len())?;
472                self.place(Datum::String(s.into()))?;
473            }
474            JsonEvent::End => {
475                return Err(Fail::protocol(
476                    "the document ended inside a value being captured",
477                ))
478            }
479        }
480        Ok(())
481    }
482}
483
484#[cfg(test)]
485mod tests {
486    use super::*;
487    use crate::shared::event::OwnedJsonEvent;
488
489    fn build(events: &[OwnedJsonEvent], limit: usize) -> Result<Datum, Fail> {
490        let mut b = DatumBuilder::new(limit, "max_capture_bytes", Duplicates::Reject);
491        for ev in events {
492            b.event(ev.as_event())?;
493        }
494        assert!(b.finished());
495        Ok(b.take().unwrap())
496    }
497
498    #[test]
499    fn walk_and_build_round_trip() {
500        let src = serde_json::json!({"a": [1, "x", null, true], "b": {"c": 2.5}});
501        let d = Datum::from_json(&src);
502        let mut rec: Vec<OwnedJsonEvent> = Vec::new();
503        walk_datum(&d, &mut rec).unwrap();
504        let back = build(&rec, usize::MAX).unwrap();
505        assert_eq!(back, d);
506        assert_eq!(back.to_json(), src);
507        assert_eq!(back.to_string(), r#"{"a":[1,"x",null,true],"b":{"c":2.5}}"#);
508    }
509
510    #[test]
511    fn lexemes_survive() {
512        let d = Datum::from_json(&serde_json::json!({"n": 50.25}));
513        assert_eq!(
514            d.get_path(&[Segment::Key("n".into())]).unwrap().to_string(),
515            "50.25"
516        );
517        let big = Datum::Number {
518            value: 1.2345678901234568e29,
519            lexeme: Some("123456789012345678901234567890".into()),
520        };
521        assert_eq!(big.to_string(), "123456789012345678901234567890");
522        assert_eq!(
523            Datum::Number {
524                value: 72.0,
525                lexeme: None
526            }
527            .to_string(),
528            "72"
529        );
530    }
531
532    #[test]
533    fn strings_escape_as_rfc_8259() {
534        let d = Datum::String("a\"b\\c\n\u{1}\u{7f}\u{e9}".into());
535        assert_eq!(d.to_string(), "\"a\\\"b\\\\c\\n\\u0001\u{7f}\u{e9}\"");
536        let back: serde_json::Value = serde_json::from_str(&d.to_string()).unwrap();
537        assert_eq!(
538            back,
539            serde_json::Value::String("a\"b\\c\n\u{1}\u{7f}\u{e9}".into())
540        );
541    }
542
543    #[test]
544    fn get_path() {
545        let d = Datum::from_json(&serde_json::json!({"a": [{"b": 1}]}));
546        let p = [
547            Segment::Key("a".into()),
548            Segment::Index(0),
549            Segment::Key("b".into()),
550        ];
551        assert_eq!(d.get_path(&p).unwrap().to_string(), "1");
552        assert!(d.get_path(&[Segment::Key("z".into())]).is_none());
553        assert!(d.get_path(&[Segment::Index(0)]).is_none());
554        assert!(d.get_path(&[]).is_some());
555    }
556
557    #[test]
558    fn take_path_moves_the_value_out_and_leaves_null() {
559        let mut d = Datum::from_json(&serde_json::json!({"a": [{"b": "x"}], "c": 2}));
560        let p = [
561            Segment::Key("a".into()),
562            Segment::Index(0),
563            Segment::Key("b".into()),
564        ];
565        assert_eq!(d.take_path(&p), Some(Datum::String("x".into())));
566        assert_eq!(d.get_path(&p), Some(&Datum::Null));
567        assert!(d.take_path(&[Segment::Key("z".into())]).is_none());
568        assert_eq!(d.to_string(), r#"{"a":[{"b":null}],"c":2}"#);
569        assert_eq!(
570            d.take_path(&[]).unwrap().to_string(),
571            r#"{"a":[{"b":null}],"c":2}"#
572        );
573        assert_eq!(d, Datum::Null);
574    }
575
576    #[test]
577    fn size_and_limit() {
578        let d = Datum::from_json(&serde_json::json!(["abcd", "ef"]));
579        assert_eq!(d.byte_size(), NODE_BYTES * 3 + 6);
580        let mut rec: Vec<OwnedJsonEvent> = Vec::new();
581        walk_datum(&d, &mut rec).unwrap();
582        let err = build(&rec, NODE_BYTES * 2 + 5).unwrap_err();
583        assert_eq!(err.code, Code::ResourceLimitExceeded);
584        assert_eq!(err.limit.as_ref().unwrap().name, "max_capture_bytes");
585    }
586
587    #[test]
588    fn duplicates_policy() {
589        let events = [
590            OwnedJsonEvent::ObjectStart,
591            OwnedJsonEvent::Key("a".into()),
592            OwnedJsonEvent::Bool(true),
593            OwnedJsonEvent::Key("a".into()),
594            OwnedJsonEvent::Bool(false),
595            OwnedJsonEvent::ObjectEnd,
596        ];
597        let run = |policy| {
598            let mut b = DatumBuilder::new(usize::MAX, "max_capture_bytes", policy);
599            for ev in &events {
600                b.event(ev.as_event())?;
601            }
602            Ok::<Datum, Fail>(b.take().unwrap())
603        };
604        assert_eq!(
605            run(Duplicates::Reject).unwrap_err().code,
606            Code::DuplicateMember
607        );
608        assert_eq!(
609            run(Duplicates::LastWins).unwrap().to_string(),
610            r#"{"a":false}"#
611        );
612        assert_eq!(
613            run(Duplicates::FirstWins).unwrap().to_string(),
614            r#"{"a":true}"#
615        );
616    }
617
618    #[test]
619    fn probing_an_unfinished_builder_keeps_its_charge() {
620        let mut b = DatumBuilder::new(usize::MAX, "max_capture_bytes", Duplicates::Reject);
621        b.event(JsonEvent::ArrayStart).unwrap();
622        b.event(JsonEvent::String("abcd")).unwrap();
623        let held = b.bytes();
624        assert!(b.take().is_none());
625        assert_eq!(b.bytes(), held, "a None from take() releases nothing");
626        b.event(JsonEvent::ArrayEnd).unwrap();
627        assert!(b.take().is_some());
628        assert_eq!(b.bytes(), 0);
629    }
630
631    #[test]
632    fn a_repeated_member_does_not_grow_the_charge() {
633        for policy in [Duplicates::FirstWins, Duplicates::LastWins] {
634            let mut b = DatumBuilder::new(usize::MAX, "max_capture_bytes", policy);
635            b.event(JsonEvent::ObjectStart).unwrap();
636            b.event(JsonEvent::Key("k")).unwrap();
637            b.event(JsonEvent::String("first")).unwrap();
638            let once = b.bytes();
639            for _ in 0..100 {
640                b.event(JsonEvent::Key("k")).unwrap();
641                b.event(JsonEvent::String("again")).unwrap();
642            }
643            assert_eq!(
644                b.bytes(),
645                once,
646                "{policy:?}: the charge is the object's size"
647            );
648            b.event(JsonEvent::ObjectEnd).unwrap();
649            let d = b.take().unwrap();
650            assert_eq!(d.byte_size(), once);
651        }
652    }
653
654    #[test]
655    fn a_repeated_member_still_trips_the_limit_while_both_are_held() {
656        // Both values are held for a moment, and that moment is what the
657        // limit protects: the second value is charged before the first is
658        // released.
659        let mut b = DatumBuilder::new(
660            NODE_BYTES * 2 + 1 + 5 + 3,
661            "max_capture_bytes",
662            Duplicates::LastWins,
663        );
664        b.event(JsonEvent::ObjectStart).unwrap();
665        b.event(JsonEvent::Key("k")).unwrap();
666        b.event(JsonEvent::String("first")).unwrap();
667        b.event(JsonEvent::Key("k")).unwrap();
668        assert_eq!(
669            b.event(JsonEvent::String("second")).unwrap_err().code,
670            Code::ResourceLimitExceeded
671        );
672    }
673
674    #[test]
675    fn protocol_errors() {
676        let mut b = DatumBuilder::new(usize::MAX, "max_capture_bytes", Duplicates::Reject);
677        assert_eq!(
678            b.event(JsonEvent::ObjectEnd).unwrap_err().code,
679            Code::ProtocolOrderError
680        );
681        let mut b = DatumBuilder::new(usize::MAX, "max_capture_bytes", Duplicates::Reject);
682        b.event(JsonEvent::ObjectStart).unwrap();
683        assert_eq!(
684            b.event(JsonEvent::Null).unwrap_err().code,
685            Code::ProtocolOrderError
686        );
687        let mut b = DatumBuilder::new(usize::MAX, "max_capture_bytes", Duplicates::Reject);
688        b.event(JsonEvent::ArrayStart).unwrap();
689        assert_eq!(
690            b.event(JsonEvent::End).unwrap_err().code,
691            Code::ProtocolOrderError
692        );
693    }
694
695    /// Read with the JSON grammar, which the `language` feature brings.
696    #[cfg(feature = "language")]
697    #[test]
698    fn from_tabnas_unwraps() {
699        let v = tabnas_json::parse(r#"{"a":[1,2],"b":"x","c":null}"#).unwrap();
700        let d = Datum::from_tabnas(&v);
701        assert_eq!(d.to_string(), r#"{"a":[1,2],"b":"x","c":null}"#);
702    }
703}