1use std::collections::HashMap;
27
28use serde_json::Value;
29
30use super::ast::{Grammar, NonTerminalId, Rule, Symbol};
31
32#[derive(Debug, Clone)]
38pub enum JsonSchemaCompileError {
39 InvalidSchema(String),
41 UnsupportedKeyword(String),
43 DanglingRef(String),
45 DepthExceeded {
47 limit: usize,
49 },
50 InvalidJson(String),
52}
53
54impl std::fmt::Display for JsonSchemaCompileError {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 match self {
57 Self::InvalidSchema(msg) => write!(f, "invalid JSON schema: {msg}"),
58 Self::UnsupportedKeyword(kw) => write!(f, "unsupported JSON schema keyword: {kw}"),
59 Self::DanglingRef(r) => write!(f, "unresolvable $ref: {r}"),
60 Self::DepthExceeded { limit } => {
61 write!(f, "schema nesting depth exceeded limit of {limit}")
62 }
63 Self::InvalidJson(msg) => write!(f, "invalid JSON input: {msg}"),
64 }
65 }
66}
67
68impl std::error::Error for JsonSchemaCompileError {}
69
70pub fn compile_json_schema(schema: &Value) -> Result<Grammar, JsonSchemaCompileError> {
87 Compiler::new().compile(schema)
88}
89
90pub fn compile_json_schema_str(schema_json: &str) -> Result<Grammar, JsonSchemaCompileError> {
99 let value: Value = serde_json::from_str(schema_json)
100 .map_err(|e| JsonSchemaCompileError::InvalidJson(e.to_string()))?;
101 compile_json_schema(&value)
102}
103
104const MAX_DEPTH: usize = 32;
110
111struct Compiler {
113 grammar: Grammar,
114 defs_nt: HashMap<String, NonTerminalId>,
116 defs_compiled: HashMap<String, bool>,
119 string_nt: Option<NonTerminalId>,
122 digit_nt: Option<NonTerminalId>,
124}
125
126impl Compiler {
127 fn new() -> Self {
128 let grammar = Grammar::new(0);
131 Self {
132 grammar,
133 defs_nt: HashMap::new(),
134 defs_compiled: HashMap::new(),
135 string_nt: None,
136 digit_nt: None,
137 }
138 }
139
140 fn compile(mut self, root: &Value) -> Result<Grammar, JsonSchemaCompileError> {
142 self.pass1_alloc_defs(root);
144
145 let def_keys: Vec<String> = self.defs_nt.keys().cloned().collect();
148 for key in &def_keys {
149 self.pass2_compile_def(key, root)?;
150 }
151
152 let start_nt = self.compile_schema(root, 0)?;
154 self.grammar.start = start_nt;
155
156 Ok(self.grammar)
157 }
158
159 fn pass1_alloc_defs(&mut self, root: &Value) {
167 let defs = root
168 .get("$defs")
169 .or_else(|| root.get("definitions"))
170 .and_then(|v| v.as_object());
171
172 if let Some(map) = defs {
173 for key in map.keys() {
174 if !self.defs_nt.contains_key(key) {
175 let nt = self.grammar.alloc_nt(format!("$def_{key}"));
176 self.defs_nt.insert(key.clone(), nt);
177 self.defs_compiled.insert(key.clone(), false);
178 }
179 }
180 }
181 }
182
183 fn pass2_compile_def(&mut self, key: &str, root: &Value) -> Result<(), JsonSchemaCompileError> {
189 if *self.defs_compiled.get(key).unwrap_or(&false) {
191 return Ok(());
192 }
193 self.defs_compiled.insert(key.to_string(), true);
195
196 let def_nt = *self.defs_nt.get(key).expect("NT pre-allocated in pass 1");
197
198 let body_value = root
199 .get("$defs")
200 .or_else(|| root.get("definitions"))
201 .and_then(|v| v.get(key))
202 .ok_or_else(|| {
203 JsonSchemaCompileError::InvalidSchema(format!("$defs key '{key}' not found"))
204 })?;
205
206 let compiled_nt = self.compile_schema(body_value, 0)?;
210 if compiled_nt != def_nt {
211 self.grammar
212 .add_rule(Rule::new(def_nt, vec![Symbol::NonTerminal(compiled_nt)]));
213 }
214
215 Ok(())
216 }
217
218 fn compile_schema(
225 &mut self,
226 schema: &Value,
227 depth: usize,
228 ) -> Result<NonTerminalId, JsonSchemaCompileError> {
229 if depth > MAX_DEPTH {
230 return Err(JsonSchemaCompileError::DepthExceeded { limit: MAX_DEPTH });
231 }
232
233 if schema.is_boolean() {
237 let nt = self.grammar.alloc_nt("__bool_schema");
241 self.grammar
242 .add_rule(Rule::new(nt, vec![Symbol::Terminal(vec![])]));
243 return Ok(nt);
244 }
245
246 let obj = match schema.as_object() {
247 Some(o) => o,
248 None => {
249 return Err(JsonSchemaCompileError::InvalidSchema(
250 "schema must be a JSON object or boolean".to_string(),
251 ));
252 }
253 };
254
255 for unsupported in &[
257 "not",
258 "if",
259 "then",
260 "else",
261 "patternProperties",
262 "pattern",
263 "format",
264 "multipleOf",
265 "exclusiveMinimum",
266 "exclusiveMaximum",
267 ] {
268 if obj.contains_key(*unsupported) {
269 return Err(JsonSchemaCompileError::UnsupportedKeyword(
270 unsupported.to_string(),
271 ));
272 }
273 }
274
275 if let Some(ref_val) = obj.get("$ref") {
277 return self.compile_ref(ref_val);
278 }
279
280 if let Some(enum_val) = obj.get("enum") {
282 return self.compile_enum(enum_val, depth);
283 }
284
285 if let Some(any_of) = obj.get("anyOf") {
287 return self.compile_any_of(any_of, depth);
288 }
289
290 if let Some(one_of) = obj.get("oneOf") {
292 return self.compile_any_of(one_of, depth);
293 }
294
295 if let Some(all_of) = obj.get("allOf") {
297 return self.compile_all_of(all_of, schema, depth);
298 }
299
300 match obj.get("type").and_then(|v| v.as_str()) {
302 Some("string") => self.compile_string_type(),
303 Some("integer") => self.compile_integer_type(),
304 Some("number") => self.compile_number_type(),
305 Some("boolean") => Ok(self.compile_boolean_type()),
306 Some("null") => Ok(self.compile_null_type()),
307 Some("object") => self.compile_object_type(schema, depth),
308 Some("array") => self.compile_array_type(schema, depth),
309 Some(other) => Err(JsonSchemaCompileError::InvalidSchema(format!(
310 "unknown type: '{other}'"
311 ))),
312 None => {
313 Ok(self.compile_any_value_type())
317 }
318 }
319 }
320
321 fn compile_ref(&mut self, ref_val: &Value) -> Result<NonTerminalId, JsonSchemaCompileError> {
326 let ref_str = ref_val.as_str().ok_or_else(|| {
327 JsonSchemaCompileError::InvalidSchema("$ref must be a string".to_string())
328 })?;
329
330 let key = if let Some(k) = ref_str.strip_prefix("#/$defs/") {
332 k
333 } else if let Some(k) = ref_str.strip_prefix("#/definitions/") {
334 k
335 } else {
336 return Err(JsonSchemaCompileError::UnsupportedKeyword(format!(
337 "$ref to external schema or unsupported path: {ref_str}"
338 )));
339 };
340
341 self.defs_nt
342 .get(key)
343 .copied()
344 .ok_or_else(|| JsonSchemaCompileError::DanglingRef(ref_str.to_string()))
345 }
346
347 fn compile_enum(
352 &mut self,
353 enum_val: &Value,
354 _depth: usize,
355 ) -> Result<NonTerminalId, JsonSchemaCompileError> {
356 let values = enum_val.as_array().ok_or_else(|| {
357 JsonSchemaCompileError::InvalidSchema("\"enum\" value must be a JSON array".to_string())
358 })?;
359
360 if values.is_empty() {
361 return Err(JsonSchemaCompileError::InvalidSchema(
362 "\"enum\" array must not be empty".to_string(),
363 ));
364 }
365
366 let enum_nt = self.grammar.alloc_nt("__enum");
367
368 for v in values {
369 let literal = json_value_to_literal(v)?;
370 self.grammar
372 .add_rule(Rule::new(enum_nt, vec![Symbol::Terminal(literal)]));
373 }
374
375 Ok(enum_nt)
376 }
377
378 fn compile_any_of(
383 &mut self,
384 arr: &Value,
385 depth: usize,
386 ) -> Result<NonTerminalId, JsonSchemaCompileError> {
387 let variants = arr.as_array().ok_or_else(|| {
388 JsonSchemaCompileError::InvalidSchema("anyOf/oneOf must be an array".to_string())
389 })?;
390
391 if variants.is_empty() {
392 return Err(JsonSchemaCompileError::InvalidSchema(
393 "anyOf/oneOf must have at least one variant".to_string(),
394 ));
395 }
396
397 let any_nt = self.grammar.alloc_nt("__anyOf");
398
399 for variant in variants {
400 let var_nt = self.compile_schema(variant, depth + 1)?;
401 self.grammar
403 .add_rule(Rule::new(any_nt, vec![Symbol::NonTerminal(var_nt)]));
404 }
405
406 Ok(any_nt)
407 }
408
409 fn compile_all_of(
416 &mut self,
417 all_of_arr: &Value,
418 _parent: &Value,
419 depth: usize,
420 ) -> Result<NonTerminalId, JsonSchemaCompileError> {
421 let variants = all_of_arr.as_array().ok_or_else(|| {
422 JsonSchemaCompileError::InvalidSchema("allOf must be an array".to_string())
423 })?;
424
425 if variants.is_empty() {
426 return Err(JsonSchemaCompileError::InvalidSchema(
427 "allOf must have at least one element".to_string(),
428 ));
429 }
430
431 for variant in variants {
434 let is_object = variant
435 .get("type")
436 .and_then(|v| v.as_str())
437 .map(|t| t == "object")
438 .unwrap_or(false)
439 || variant.get("properties").is_some();
440
441 if !is_object {
442 return Err(JsonSchemaCompileError::UnsupportedKeyword(
443 "allOf can only merge object schemas in this compiler".to_string(),
444 ));
445 }
446 }
447
448 let mut merged_props: serde_json::Map<String, Value> = serde_json::Map::new();
450 let mut merged_required: Vec<String> = Vec::new();
451 let mut has_additional_false = false;
452
453 for variant in variants {
454 if let Some(props) = variant.get("properties").and_then(|v| v.as_object()) {
455 for (k, v) in props {
456 merged_props.insert(k.clone(), v.clone());
457 }
458 }
459 if let Some(req) = variant.get("required").and_then(|v| v.as_array()) {
460 for r in req {
461 if let Some(s) = r.as_str() {
462 if !merged_required.contains(&s.to_string()) {
463 merged_required.push(s.to_string());
464 }
465 }
466 }
467 }
468 if variant
469 .get("additionalProperties")
470 .and_then(|v| v.as_bool())
471 == Some(false)
472 {
473 has_additional_false = true;
474 }
475 }
476
477 let mut merged = serde_json::json!({
479 "type": "object",
480 "properties": merged_props,
481 "required": merged_required,
482 });
483 if has_additional_false {
484 if let Some(obj) = merged.as_object_mut() {
485 obj.insert("additionalProperties".to_string(), Value::Bool(false));
486 }
487 }
488
489 self.compile_object_type(&merged, depth)
490 }
491
492 fn compile_string_type(&mut self) -> Result<NonTerminalId, JsonSchemaCompileError> {
506 if let Some(nt) = self.string_nt {
507 return Ok(nt);
508 }
509
510 let str_nt = self.grammar.alloc_nt("__string");
511 let chars_nt = self.grammar.alloc_nt("__string_chars");
512 let char_nt = self.grammar.alloc_nt("__string_char");
513
514 self.grammar.add_rule(Rule::new(
516 str_nt,
517 vec![Symbol::Terminal(vec![b'"']), Symbol::Terminal(vec![b'"'])],
518 ));
519 self.grammar.add_rule(Rule::new(
521 str_nt,
522 vec![
523 Symbol::Terminal(vec![b'"']),
524 Symbol::NonTerminal(chars_nt),
525 Symbol::Terminal(vec![b'"']),
526 ],
527 ));
528
529 self.grammar
531 .add_rule(Rule::new(chars_nt, vec![Symbol::NonTerminal(char_nt)]));
532 self.grammar.add_rule(Rule::new(
534 chars_nt,
535 vec![Symbol::NonTerminal(char_nt), Symbol::NonTerminal(chars_nt)],
536 ));
537
538 for b in 0x20u8..=0x21u8 {
541 self.grammar
542 .add_rule(Rule::new(char_nt, vec![Symbol::Terminal(vec![b])]));
543 }
544 for b in 0x23u8..=0x5Bu8 {
545 self.grammar
546 .add_rule(Rule::new(char_nt, vec![Symbol::Terminal(vec![b])]));
547 }
548 for b in 0x5Du8..=0x7Eu8 {
549 self.grammar
550 .add_rule(Rule::new(char_nt, vec![Symbol::Terminal(vec![b])]));
551 }
552
553 self.string_nt = Some(str_nt);
554 Ok(str_nt)
555 }
556
557 fn ensure_digit_nt(&mut self) -> NonTerminalId {
559 if let Some(nt) = self.digit_nt {
560 return nt;
561 }
562 let digit_nt = self.grammar.alloc_nt("__digit");
563 for b in b'0'..=b'9' {
564 self.grammar
565 .add_rule(Rule::new(digit_nt, vec![Symbol::Terminal(vec![b])]));
566 }
567 self.digit_nt = Some(digit_nt);
568 digit_nt
569 }
570
571 fn compile_integer_type(&mut self) -> Result<NonTerminalId, JsonSchemaCompileError> {
580 let digit_nt = self.ensure_digit_nt();
581
582 let digits_nt = self.grammar.alloc_nt("__digits");
583 self.grammar
585 .add_rule(Rule::new(digits_nt, vec![Symbol::NonTerminal(digit_nt)]));
586 self.grammar.add_rule(Rule::new(
588 digits_nt,
589 vec![
590 Symbol::NonTerminal(digit_nt),
591 Symbol::NonTerminal(digits_nt),
592 ],
593 ));
594
595 let int_nt = self.grammar.alloc_nt("__integer");
596 self.grammar
598 .add_rule(Rule::new(int_nt, vec![Symbol::NonTerminal(digits_nt)]));
599 self.grammar.add_rule(Rule::new(
601 int_nt,
602 vec![Symbol::Terminal(vec![b'-']), Symbol::NonTerminal(digits_nt)],
603 ));
604
605 Ok(int_nt)
606 }
607
608 fn compile_number_type(&mut self) -> Result<NonTerminalId, JsonSchemaCompileError> {
615 let int_nt = self.compile_integer_type()?;
616 let digit_nt = self.ensure_digit_nt();
619
620 let frac_digits_nt = self.grammar.alloc_nt("__frac_digits");
621 self.grammar.add_rule(Rule::new(
623 frac_digits_nt,
624 vec![Symbol::NonTerminal(digit_nt)],
625 ));
626 self.grammar.add_rule(Rule::new(
628 frac_digits_nt,
629 vec![
630 Symbol::NonTerminal(digit_nt),
631 Symbol::NonTerminal(frac_digits_nt),
632 ],
633 ));
634
635 let num_nt = self.grammar.alloc_nt("__number");
636 self.grammar
638 .add_rule(Rule::new(num_nt, vec![Symbol::NonTerminal(int_nt)]));
639 self.grammar.add_rule(Rule::new(
641 num_nt,
642 vec![
643 Symbol::NonTerminal(int_nt),
644 Symbol::Terminal(vec![b'.']),
645 Symbol::NonTerminal(frac_digits_nt),
646 ],
647 ));
648
649 Ok(num_nt)
650 }
651
652 fn compile_boolean_type(&mut self) -> NonTerminalId {
654 let bool_nt = self.grammar.alloc_nt("__boolean");
655 self.grammar
656 .add_rule(Rule::new(bool_nt, vec![Symbol::Terminal(b"true".to_vec())]));
657 self.grammar.add_rule(Rule::new(
658 bool_nt,
659 vec![Symbol::Terminal(b"false".to_vec())],
660 ));
661 bool_nt
662 }
663
664 fn compile_null_type(&mut self) -> NonTerminalId {
666 let null_nt = self.grammar.alloc_nt("__null");
667 self.grammar
668 .add_rule(Rule::new(null_nt, vec![Symbol::Terminal(b"null".to_vec())]));
669 null_nt
670 }
671
672 fn compile_any_value_type(&mut self) -> NonTerminalId {
679 let val_nt = self.grammar.alloc_nt("__any_value");
680
681 let str_nt = self.string_nt.unwrap_or_else(|| {
683 self.compile_string_type().expect("string type compile")
685 });
686 let bool_nt = self.compile_boolean_type();
687 let null_nt = self.compile_null_type();
688
689 let digit_nt = self.ensure_digit_nt();
691 let digits_nt = self.grammar.alloc_nt("__any_val_digits");
692 self.grammar
693 .add_rule(Rule::new(digits_nt, vec![Symbol::NonTerminal(digit_nt)]));
694 self.grammar.add_rule(Rule::new(
695 digits_nt,
696 vec![
697 Symbol::NonTerminal(digit_nt),
698 Symbol::NonTerminal(digits_nt),
699 ],
700 ));
701
702 let num_nt = self.grammar.alloc_nt("__any_val_num");
703 self.grammar
704 .add_rule(Rule::new(num_nt, vec![Symbol::NonTerminal(digits_nt)]));
705 self.grammar.add_rule(Rule::new(
706 num_nt,
707 vec![Symbol::Terminal(vec![b'-']), Symbol::NonTerminal(digits_nt)],
708 ));
709
710 let obj_stub_nt = self.grammar.alloc_nt("__any_val_obj");
712 self.grammar.add_rule(Rule::new(
713 obj_stub_nt,
714 vec![Symbol::Terminal(vec![b'{']), Symbol::Terminal(vec![b'}'])],
715 ));
716
717 let arr_stub_nt = self.grammar.alloc_nt("__any_val_arr");
719 self.grammar.add_rule(Rule::new(
720 arr_stub_nt,
721 vec![Symbol::Terminal(vec![b'[']), Symbol::Terminal(vec![b']'])],
722 ));
723
724 self.grammar
726 .add_rule(Rule::new(val_nt, vec![Symbol::NonTerminal(str_nt)]));
727 self.grammar
728 .add_rule(Rule::new(val_nt, vec![Symbol::NonTerminal(bool_nt)]));
729 self.grammar
730 .add_rule(Rule::new(val_nt, vec![Symbol::NonTerminal(null_nt)]));
731 self.grammar
732 .add_rule(Rule::new(val_nt, vec![Symbol::NonTerminal(num_nt)]));
733 self.grammar
734 .add_rule(Rule::new(val_nt, vec![Symbol::NonTerminal(obj_stub_nt)]));
735 self.grammar
736 .add_rule(Rule::new(val_nt, vec![Symbol::NonTerminal(arr_stub_nt)]));
737
738 val_nt
739 }
740
741 fn compile_object_type(
756 &mut self,
757 schema: &Value,
758 depth: usize,
759 ) -> Result<NonTerminalId, JsonSchemaCompileError> {
760 if let Some(ap) = schema.get("additionalProperties") {
762 if !ap.is_boolean() {
763 return Err(JsonSchemaCompileError::UnsupportedKeyword(
764 "additionalProperties as a subschema is not supported; use false or omit it"
765 .to_string(),
766 ));
767 }
768 }
769
770 let properties = schema
771 .get("properties")
772 .and_then(|v| v.as_object())
773 .cloned()
774 .unwrap_or_default();
775
776 let required: Vec<String> = schema
777 .get("required")
778 .and_then(|v| v.as_array())
779 .map(|arr| {
780 arr.iter()
781 .filter_map(|v| v.as_str().map(|s| s.to_string()))
782 .collect()
783 })
784 .unwrap_or_default();
785
786 let obj_nt = self.grammar.alloc_nt("__object");
788
789 if required.is_empty() {
790 self.grammar.add_rule(Rule::new(
792 obj_nt,
793 vec![Symbol::Terminal(vec![b'{']), Symbol::Terminal(vec![b'}'])],
794 ));
795 return Ok(obj_nt);
796 }
797
798 let mut prop_nts: Vec<(String, NonTerminalId)> = Vec::new();
802 for prop_name in &required {
803 let sub_schema = properties.get(prop_name).ok_or_else(|| {
804 JsonSchemaCompileError::InvalidSchema(format!(
805 "required property '{prop_name}' not found in 'properties'"
806 ))
807 })?;
808 let val_nt = self.compile_schema(sub_schema, depth + 1)?;
809 prop_nts.push((prop_name.clone(), val_nt));
810 }
811
812 let mut body: Vec<Symbol> = Vec::new();
815 body.push(Symbol::Terminal(vec![b'{']));
816
817 for (i, (prop_name, val_nt)) in prop_nts.iter().enumerate() {
818 if i > 0 {
819 body.push(Symbol::Terminal(vec![b',']));
820 }
821 let key_bytes = json_string_literal_bytes(prop_name);
823 body.push(Symbol::Terminal(key_bytes));
824 body.push(Symbol::Terminal(vec![b':']));
825 body.push(Symbol::NonTerminal(*val_nt));
826 }
827
828 body.push(Symbol::Terminal(vec![b'}']));
829 self.grammar.add_rule(Rule::new(obj_nt, body));
830
831 Ok(obj_nt)
832 }
833
834 fn compile_array_type(
848 &mut self,
849 schema: &Value,
850 depth: usize,
851 ) -> Result<NonTerminalId, JsonSchemaCompileError> {
852 let items_schema = schema.get("items");
853
854 let item_nt = if let Some(items) = items_schema {
855 self.compile_schema(items, depth + 1)?
856 } else {
857 self.compile_any_value_type()
859 };
860
861 let items_nt = self.grammar.alloc_nt("__array_items");
862 self.grammar
864 .add_rule(Rule::new(items_nt, vec![Symbol::NonTerminal(item_nt)]));
865 self.grammar.add_rule(Rule::new(
867 items_nt,
868 vec![
869 Symbol::NonTerminal(item_nt),
870 Symbol::Terminal(vec![b',']),
871 Symbol::NonTerminal(items_nt),
872 ],
873 ));
874
875 let arr_nt = self.grammar.alloc_nt("__array");
876 self.grammar.add_rule(Rule::new(
878 arr_nt,
879 vec![Symbol::Terminal(vec![b'[']), Symbol::Terminal(vec![b']'])],
880 ));
881 self.grammar.add_rule(Rule::new(
883 arr_nt,
884 vec![
885 Symbol::Terminal(vec![b'[']),
886 Symbol::NonTerminal(items_nt),
887 Symbol::Terminal(vec![b']']),
888 ],
889 ));
890
891 Ok(arr_nt)
892 }
893}
894
895fn json_value_to_literal(v: &Value) -> Result<Vec<u8>, JsonSchemaCompileError> {
906 match v {
907 Value::String(_) => {
908 let json_repr = serde_json::to_string(v)
910 .map_err(|e| JsonSchemaCompileError::InvalidSchema(e.to_string()))?;
911 Ok(json_repr.into_bytes())
912 }
913 Value::Number(n) => {
914 if n.is_i64() || n.is_u64() {
916 Ok(n.to_string().into_bytes())
917 } else {
918 Err(JsonSchemaCompileError::UnsupportedKeyword(
919 "float enum values are not supported".to_string(),
920 ))
921 }
922 }
923 Value::Bool(b) => {
924 if *b {
925 Ok(b"true".to_vec())
926 } else {
927 Ok(b"false".to_vec())
928 }
929 }
930 Value::Null => Ok(b"null".to_vec()),
931 _ => Err(JsonSchemaCompileError::UnsupportedKeyword(
932 "enum values must be strings, integers, booleans, or null".to_string(),
933 )),
934 }
935}
936
937fn json_string_literal_bytes(key: &str) -> Vec<u8> {
942 serde_json::to_string(key)
943 .expect("key serialization must succeed")
944 .into_bytes()
945}
946
947#[cfg(test)]
952mod tests {
953 use super::*;
954
955 #[test]
956 fn compile_string_gives_grammar() {
957 let g = compile_json_schema_str(r#"{"type":"string"}"#).expect("should compile");
958 assert!(!g.rules.is_empty());
959 }
960
961 #[test]
962 fn compile_boolean_gives_grammar() {
963 let g = compile_json_schema_str(r#"{"type":"boolean"}"#).expect("should compile");
964 assert!(!g.rules.is_empty());
965 }
966
967 #[test]
968 fn json_value_to_literal_string() {
969 let v = Value::String("hello".to_string());
970 let b = json_value_to_literal(&v).expect("ok");
971 assert_eq!(b, br#""hello""#);
972 }
973
974 #[test]
975 fn json_value_to_literal_integer() {
976 let v = Value::Number(serde_json::Number::from(42));
977 let b = json_value_to_literal(&v).expect("ok");
978 assert_eq!(b, b"42");
979 }
980
981 #[test]
982 fn json_value_to_literal_bool() {
983 let b = json_value_to_literal(&Value::Bool(true)).expect("ok");
984 assert_eq!(b, b"true");
985 }
986
987 #[test]
988 fn json_value_to_literal_null() {
989 let b = json_value_to_literal(&Value::Null).expect("ok");
990 assert_eq!(b, b"null");
991 }
992
993 #[test]
994 fn json_string_literal_bytes_simple() {
995 let b = json_string_literal_bytes("name");
996 assert_eq!(b, br#""name""#);
997 }
998}