1use 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#[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 Object(IndexMap<Box<str>, Datum>),
32}
33
34impl Datum {
35 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 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 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 #[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 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 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 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
190pub 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
213pub 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
224pub 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
256pub 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#[derive(Clone, Copy, Debug, PartialEq, Eq)]
299pub enum Duplicates {
300 Reject,
302 LastWins,
304 FirstWins,
306}
307
308#[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 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 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 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 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 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 #[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}