1use crate::error::BridgeError;
11use crate::traits::ToCore;
12use tidepool_eval::Value;
13use tidepool_repr::{DataConTable, Literal};
14
15impl ToCore for serde_json::Value {
21 fn to_value(&self, table: &DataConTable) -> Result<Value, BridgeError> {
22 match self {
25 serde_json::Value::Null => {
26 let id = table
27 .get_by_name_arity("Null", 0)
28 .ok_or_else(|| BridgeError::UnknownDataConName("Null".into()))?;
29 Ok(Value::Con(id, vec![]))
30 }
31
32 serde_json::Value::Bool(b) => {
33 let id = table
34 .get_by_name_arity("Bool", 1)
35 .ok_or_else(|| BridgeError::UnknownDataConName("Bool".into()))?;
36 let inner = (*b).to_value(table)?;
37 Ok(Value::Con(id, vec![inner]))
38 }
39
40 serde_json::Value::Number(n) => {
41 let id = table
42 .get_by_name_arity("Number", 1)
43 .ok_or_else(|| BridgeError::UnknownDataConName("Number".into()))?;
44 let f = n.as_f64().unwrap_or(0.0);
45 Ok(Value::Con(
46 id,
47 vec![Value::Lit(Literal::LitDouble(f.to_bits()))],
48 ))
49 }
50
51 serde_json::Value::String(s) => {
52 let id = table
53 .get_by_name_arity("String", 1)
54 .ok_or_else(|| BridgeError::UnknownDataConName("String".into()))?;
55 let inner = s.clone().to_value(table)?;
56 Ok(Value::Con(id, vec![inner]))
57 }
58
59 serde_json::Value::Array(arr) => {
60 let id = table
61 .get_by_name_arity("Array", 1)
62 .ok_or_else(|| BridgeError::UnknownDataConName("Array".into()))?;
63 let elements: Result<Vec<Value>, BridgeError> =
65 arr.iter().map(|v| v.to_value(table)).collect();
66 let list = elements?.to_value(table)?;
67 Ok(Value::Con(id, vec![list]))
68 }
69
70 serde_json::Value::Object(map) => {
71 let id = table
72 .get_by_name_arity("Object", 1)
73 .ok_or_else(|| BridgeError::UnknownDataConName("Object".into()))?;
74 let map_val = keymap_to_value(map, table)?;
78 Ok(Value::Con(id, vec![map_val]))
79 }
80 }
81 }
82}
83
84fn keymap_to_value(
92 map: &serde_json::Map<std::string::String, serde_json::Value>,
93 table: &DataConTable,
94) -> Result<Value, BridgeError> {
95 let bin_id = table
97 .get_by_qualified_name("Data.Map.Bin")
98 .or_else(|| table.get_by_name_arity("Bin", 5))
99 .ok_or_else(|| BridgeError::UnknownDataConName("Bin".into()))?;
100 let tip_id = table
101 .get_by_qualified_name("Data.Map.Tip")
102 .or_else(|| table.get_companion(bin_id, "Tip", 0))
103 .or_else(|| table.get_by_name_arity("Tip", 0))
104 .ok_or_else(|| BridgeError::UnknownDataConName("Tip".into()))?;
105 let i_hash_id = table
107 .get_by_name_arity("I#", 1)
108 .ok_or_else(|| BridgeError::UnknownDataConName("I#".into()))?;
109
110 let mut entries: Vec<(&std::string::String, &serde_json::Value)> = map.iter().collect();
112 entries.sort_by(|a, b| a.0.cmp(b.0));
113
114 fn build_tree(
115 entries: &[(&std::string::String, &serde_json::Value)],
116 bin_id: tidepool_repr::DataConId,
117 tip_id: tidepool_repr::DataConId,
118 i_hash_id: tidepool_repr::DataConId,
119 table: &DataConTable,
120 ) -> Result<Value, BridgeError> {
121 if entries.is_empty() {
122 return Ok(Value::Con(tip_id, vec![]));
123 }
124 let mid = entries.len() / 2;
125 let (k, v) = entries[mid];
126 let left = build_tree(&entries[..mid], bin_id, tip_id, i_hash_id, table)?;
127 let right = build_tree(&entries[mid + 1..], bin_id, tip_id, i_hash_id, table)?;
128
129 let key_val = k.clone().to_value(table)?;
131
132 let json_val = v.to_value(table)?;
133 let size = Value::Con(
135 i_hash_id,
136 vec![Value::Lit(Literal::LitInt(entries.len() as i64))],
137 );
138
139 Ok(Value::Con(
141 bin_id,
142 vec![size, key_val, json_val, left, right],
143 ))
144 }
145
146 build_tree(&entries, bin_id, tip_id, i_hash_id, table)
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use tidepool_repr::{DataCon, DataConId};
153
154 fn json_test_table() -> DataConTable {
156 let mut t = DataConTable::new();
157 let cons = [
158 ("Object", 0, 1),
160 ("Array", 1, 1),
161 ("String", 2, 1),
162 ("Number", 3, 1),
163 ("Bool", 4, 1),
164 ("Null", 5, 0),
165 ("Bin", 6, 5),
167 ("Tip", 7, 0),
168 ("True", 8, 0),
170 ("False", 9, 0),
171 ("[]", 10, 0),
173 (":", 11, 2),
174 ("Text", 12, 3),
176 ("I#", 13, 1),
178 ];
179
180 for (i, (name, tag, arity)) in cons.iter().enumerate() {
181 t.insert(DataCon {
182 id: DataConId(i as u64),
183 name: (*name).into(),
184 tag: *tag,
185 rep_arity: *arity,
186 field_bangs: vec![],
187 qualified_name: None,
188 });
189 }
190 t
191 }
192
193 #[test]
194 fn test_null_to_value() {
195 let table = json_test_table();
196 let json = serde_json::Value::Null;
197 let val = json.to_value(&table).unwrap();
198 match val {
199 Value::Con(id, fields) => {
200 assert_eq!(table.name_of(id), Some("Null"));
201 assert!(fields.is_empty());
202 }
203 _ => panic!("Expected Con(Null)"),
204 }
205 }
206
207 #[test]
208 fn test_bool_to_value() {
209 let table = json_test_table();
210 let json = serde_json::json!(true);
211 let val = json.to_value(&table).unwrap();
212 match &val {
213 Value::Con(id, fields) => {
214 assert_eq!(table.name_of(*id), Some("Bool"));
215 assert_eq!(fields.len(), 1);
216 match &fields[0] {
218 Value::Con(inner_id, _) => {
219 assert_eq!(table.name_of(*inner_id), Some("True"));
220 }
221 _ => panic!("Expected Con(True)"),
222 }
223 }
224 _ => panic!("Expected Con(Bool)"),
225 }
226 }
227
228 #[test]
229 fn test_string_to_value() {
230 let table = json_test_table();
231 let json = serde_json::json!("hello");
232 let val = json.to_value(&table).unwrap();
233 match &val {
234 Value::Con(id, fields) => {
235 assert_eq!(table.name_of(*id), Some("String"));
236 assert_eq!(fields.len(), 1);
237 match &fields[0] {
239 Value::Con(inner_id, _) => {
240 assert_eq!(table.name_of(*inner_id), Some("Text"));
241 }
242 _ => panic!("Expected Con(Text), got {:?}", fields[0]),
243 }
244 }
245 _ => panic!("Expected Con(String)"),
246 }
247 }
248
249 #[test]
250 fn test_number_to_value() {
251 let table = json_test_table();
252 let json = serde_json::json!(42);
253 let val = json.to_value(&table).unwrap();
254 match &val {
255 Value::Con(id, fields) => {
256 assert_eq!(table.name_of(*id), Some("Number"));
257 assert_eq!(fields.len(), 1);
258 match &fields[0] {
260 Value::Lit(Literal::LitDouble(bits)) => {
261 assert_eq!(f64::from_bits(*bits), 42.0);
262 }
263 _ => panic!("Expected Lit(LitDouble), got {:?}", fields[0]),
264 }
265 }
266 _ => panic!("Expected Con(Number)"),
267 }
268 }
269
270 #[test]
271 fn test_number_double_to_value() {
272 let table = json_test_table();
273 let json = serde_json::json!(3.14);
274 let val = json.to_value(&table).unwrap();
275 match &val {
276 Value::Con(id, fields) => {
277 assert_eq!(table.name_of(*id), Some("Number"));
278 assert_eq!(fields.len(), 1);
279 match &fields[0] {
280 Value::Lit(Literal::LitDouble(bits)) => {
281 let f = f64::from_bits(*bits);
282 assert!((f - 3.14).abs() < 1e-10);
283 }
284 _ => panic!("Expected Lit(LitDouble), got {:?}", fields[0]),
285 }
286 }
287 _ => panic!("Expected Con(Number)"),
288 }
289 }
290
291 #[test]
292 fn test_array_to_value() {
293 let table = json_test_table();
294 let json = serde_json::json!([1, 2, 3]);
295 let val = json.to_value(&table).unwrap();
296 match &val {
297 Value::Con(id, fields) => {
298 assert_eq!(table.name_of(*id), Some("Array"));
299 assert_eq!(fields.len(), 1);
300 }
302 _ => panic!("Expected Con(Array)"),
303 }
304 }
305
306 #[test]
307 fn test_object_to_value() {
308 let table = json_test_table();
309 let json = serde_json::json!({"name": "Alice", "age": 30});
310 let val = json.to_value(&table).unwrap();
311 match &val {
312 Value::Con(id, fields) => {
313 assert_eq!(table.name_of(*id), Some("Object"));
314 assert_eq!(fields.len(), 1);
315 }
317 _ => panic!("Expected Con(Object)"),
318 }
319 }
320
321 #[test]
322 fn test_nested_json() {
323 let table = json_test_table();
324 let json = serde_json::json!({
325 "users": [
326 {"name": "Alice", "active": true},
327 {"name": "Bob", "active": false}
328 ],
329 "count": 2
330 });
331 let val = json.to_value(&table).unwrap();
332 match &val {
333 Value::Con(id, _) => {
334 assert_eq!(table.name_of(*id), Some("Object"));
335 }
336 _ => panic!("Expected Con(Object)"),
337 }
338 }
339
340 #[test]
343 fn test_bool_false_to_value() {
344 let table = json_test_table();
345 let val = serde_json::json!(false).to_value(&table).unwrap();
346 match &val {
347 Value::Con(id, fields) => {
348 assert_eq!(table.name_of(*id), Some("Bool"));
349 match &fields[0] {
350 Value::Con(inner_id, _) => assert_eq!(table.name_of(*inner_id), Some("False")),
351 _ => panic!("Expected Con(False)"),
352 }
353 }
354 _ => panic!("Expected Con(Bool)"),
355 }
356 }
357
358 #[test]
359 fn test_number_negative() {
360 let table = json_test_table();
361 let val = serde_json::json!(-1).to_value(&table).unwrap();
362 match &val {
363 Value::Con(id, fields) => {
364 assert_eq!(table.name_of(*id), Some("Number"));
365 match &fields[0] {
366 Value::Lit(Literal::LitDouble(bits)) => {
367 assert_eq!(f64::from_bits(*bits), -1.0);
368 }
369 _ => panic!("Expected LitDouble"),
370 }
371 }
372 _ => panic!("Expected Con(Number)"),
373 }
374 }
375
376 #[test]
377 fn test_number_zero() {
378 let table = json_test_table();
379 let val = serde_json::json!(0).to_value(&table).unwrap();
380 match &val {
381 Value::Con(id, fields) => {
382 assert_eq!(table.name_of(*id), Some("Number"));
383 match &fields[0] {
384 Value::Lit(Literal::LitDouble(bits)) => {
385 assert_eq!(f64::from_bits(*bits), 0.0);
386 }
387 _ => panic!("Expected LitDouble"),
388 }
389 }
390 _ => panic!("Expected Con(Number)"),
391 }
392 }
393
394 #[test]
395 fn test_string_empty() {
396 let table = json_test_table();
397 let val = serde_json::json!("").to_value(&table).unwrap();
398 match &val {
399 Value::Con(id, fields) => {
400 assert_eq!(table.name_of(*id), Some("String"));
401 assert_eq!(fields.len(), 1);
402 match &fields[0] {
403 Value::Con(inner_id, _) => {
404 assert_eq!(table.name_of(*inner_id), Some("Text"));
405 }
406 _ => panic!("Expected Con(Text)"),
407 }
408 }
409 _ => panic!("Expected Con(String)"),
410 }
411 }
412
413 #[test]
414 fn test_string_unicode() {
415 let table = json_test_table();
416 let val = serde_json::json!("héllo 🌊").to_value(&table).unwrap();
417 match &val {
418 Value::Con(id, fields) => {
419 assert_eq!(table.name_of(*id), Some("String"));
420 assert_eq!(fields.len(), 1);
421 }
422 _ => panic!("Expected Con(String)"),
423 }
424 }
425
426 #[test]
427 fn test_array_empty() {
428 let table = json_test_table();
429 let val = serde_json::json!([]).to_value(&table).unwrap();
430 match &val {
431 Value::Con(id, fields) => {
432 assert_eq!(table.name_of(*id), Some("Array"));
433 assert_eq!(fields.len(), 1);
434 match &fields[0] {
436 Value::Con(nil_id, nil_fields) => {
437 assert_eq!(table.name_of(*nil_id), Some("[]"));
438 assert!(nil_fields.is_empty());
439 }
440 _ => panic!("Expected Con([])"),
441 }
442 }
443 _ => panic!("Expected Con(Array)"),
444 }
445 }
446
447 #[test]
448 fn test_array_single() {
449 let table = json_test_table();
450 let val = serde_json::json!([1]).to_value(&table).unwrap();
451 match &val {
452 Value::Con(id, fields) => {
453 assert_eq!(table.name_of(*id), Some("Array"));
454 match &fields[0] {
456 Value::Con(cons_id, cons_fields) => {
457 assert_eq!(table.name_of(*cons_id), Some(":"));
458 assert_eq!(cons_fields.len(), 2);
459 match &cons_fields[0] {
461 Value::Con(num_id, _) => {
462 assert_eq!(table.name_of(*num_id), Some("Number"));
463 }
464 _ => panic!("Expected Con(Number)"),
465 }
466 match &cons_fields[1] {
468 Value::Con(nil_id, _) => {
469 assert_eq!(table.name_of(*nil_id), Some("[]"));
470 }
471 _ => panic!("Expected Con([])"),
472 }
473 }
474 _ => panic!("Expected Con(:)"),
475 }
476 }
477 _ => panic!("Expected Con(Array)"),
478 }
479 }
480
481 #[test]
482 fn test_array_nested() {
483 let table = json_test_table();
484 let val = serde_json::json!([[1, 2], [3]]).to_value(&table).unwrap();
485 match &val {
486 Value::Con(id, _) => assert_eq!(table.name_of(*id), Some("Array")),
487 _ => panic!("Expected Con(Array)"),
488 }
489 }
490
491 #[test]
492 fn test_object_empty() {
493 let table = json_test_table();
494 let val = serde_json::json!({}).to_value(&table).unwrap();
495 match &val {
496 Value::Con(id, fields) => {
497 assert_eq!(table.name_of(*id), Some("Object"));
498 assert_eq!(fields.len(), 1);
499 match &fields[0] {
501 Value::Con(tip_id, tip_fields) => {
502 assert_eq!(table.name_of(*tip_id), Some("Tip"));
503 assert!(tip_fields.is_empty());
504 }
505 _ => panic!("Expected Con(Tip)"),
506 }
507 }
508 _ => panic!("Expected Con(Object)"),
509 }
510 }
511
512 #[test]
513 fn test_object_single_key() {
514 let table = json_test_table();
515 let val = serde_json::json!({"a": 1}).to_value(&table).unwrap();
516 match &val {
517 Value::Con(id, fields) => {
518 assert_eq!(table.name_of(*id), Some("Object"));
519 match &fields[0] {
521 Value::Con(bin_id, bin_fields) => {
522 assert_eq!(table.name_of(*bin_id), Some("Bin"));
523 assert_eq!(bin_fields.len(), 5);
524 match &bin_fields[0] {
526 Value::Con(i_id, i_fields) => {
527 assert_eq!(table.name_of(*i_id), Some("I#"));
528 match &i_fields[0] {
529 Value::Lit(Literal::LitInt(n)) => assert_eq!(*n, 1),
530 _ => panic!("Expected LitInt(1)"),
531 }
532 }
533 _ => panic!("Expected Con(I#)"),
534 }
535 match &bin_fields[3] {
537 Value::Con(tip_id, _) => {
538 assert_eq!(table.name_of(*tip_id), Some("Tip"));
539 }
540 _ => panic!("Expected Con(Tip)"),
541 }
542 match &bin_fields[4] {
543 Value::Con(tip_id, _) => {
544 assert_eq!(table.name_of(*tip_id), Some("Tip"));
545 }
546 _ => panic!("Expected Con(Tip)"),
547 }
548 }
549 _ => panic!("Expected Con(Bin)"),
550 }
551 }
552 _ => panic!("Expected Con(Object)"),
553 }
554 }
555
556 #[test]
557 fn test_object_two_keys() {
558 let table = json_test_table();
559 let val = serde_json::json!({"a": 1, "b": 2})
560 .to_value(&table)
561 .unwrap();
562 match &val {
563 Value::Con(id, fields) => {
564 assert_eq!(table.name_of(*id), Some("Object"));
565 match &fields[0] {
567 Value::Con(bin_id, bin_fields) => {
568 assert_eq!(table.name_of(*bin_id), Some("Bin"));
569 assert_eq!(bin_fields.len(), 5);
570 match &bin_fields[0] {
572 Value::Con(_, i_fields) => match &i_fields[0] {
573 Value::Lit(Literal::LitInt(n)) => assert_eq!(*n, 2),
574 _ => panic!("Expected LitInt(2)"),
575 },
576 _ => panic!("Expected I#"),
577 }
578 }
579 _ => panic!("Expected Con(Bin)"),
580 }
581 }
582 _ => panic!("Expected Con(Object)"),
583 }
584 }
585
586 #[test]
587 fn test_object_three_keys_balanced() {
588 let table = json_test_table();
589 let val = serde_json::json!({"a": 1, "b": 2, "c": 3})
590 .to_value(&table)
591 .unwrap();
592 match &val {
593 Value::Con(id, fields) => {
594 assert_eq!(table.name_of(*id), Some("Object"));
595 match &fields[0] {
597 Value::Con(bin_id, bin_fields) => {
598 assert_eq!(table.name_of(*bin_id), Some("Bin"));
599 let left_is_bin = matches!(&bin_fields[3], Value::Con(id, _) if table.name_of(*id) == Some("Bin"));
601 let right_is_bin = matches!(&bin_fields[4], Value::Con(id, _) if table.name_of(*id) == Some("Bin"));
602 assert!(
603 left_is_bin || right_is_bin,
604 "Expected at least one Bin child for 3-entry map"
605 );
606 }
607 _ => panic!("Expected Con(Bin)"),
608 }
609 }
610 _ => panic!("Expected Con(Object)"),
611 }
612 }
613
614 #[test]
615 fn test_object_large() {
616 let table = json_test_table();
617 let mut map = serde_json::Map::new();
618 for i in 0..12 {
619 map.insert(format!("key_{}", i), serde_json::json!(i));
620 }
621 let json = serde_json::Value::Object(map);
622 let val = json.to_value(&table).unwrap();
623 match &val {
624 Value::Con(id, _) => assert_eq!(table.name_of(*id), Some("Object")),
625 _ => panic!("Expected Con(Object)"),
626 }
627 }
628
629 #[test]
630 fn test_deep_nesting() {
631 let table = json_test_table();
632 let json = serde_json::json!({"a": {"b": {"c": 1}}});
633 let val = json.to_value(&table).unwrap();
634 match &val {
635 Value::Con(id, fields) => {
636 assert_eq!(table.name_of(*id), Some("Object"));
637 assert_eq!(fields.len(), 1);
640 }
641 _ => panic!("Expected Con(Object)"),
642 }
643 }
644
645 #[test]
646 fn test_mixed_types() {
647 let table = json_test_table();
648 let json = serde_json::json!({
649 "s": "str",
650 "n": 42,
651 "b": true,
652 "a": [1, 2],
653 "o": {"x": 1},
654 "null": null
655 });
656 let val = json.to_value(&table).unwrap();
657 match &val {
658 Value::Con(id, _) => assert_eq!(table.name_of(*id), Some("Object")),
659 _ => panic!("Expected Con(Object)"),
660 }
661 }
662
663 #[test]
664 fn test_ambiguous_tip_with_companion() {
665 let mut table = json_test_table();
667 table.insert(DataCon {
669 id: DataConId(500),
670 name: "Tip".into(),
671 tag: 1,
672 rep_arity: 0,
673 field_bangs: vec![],
674 qualified_name: None,
675 });
676 let json = serde_json::json!({"key": "value"});
679 let val = json.to_value(&table).unwrap();
680 match &val {
681 Value::Con(id, _) => assert_eq!(table.name_of(*id), Some("Object")),
682 _ => panic!("Expected Con(Object)"),
683 }
684 }
685
686 #[test]
687 fn test_qualified_name_resolves_ambiguous_map_constructors() {
688 let mut t = DataConTable::new();
691 let cons: &[(&str, u32, u32)] = &[
692 ("Object", 0, 1),
693 ("Array", 1, 1),
694 ("String", 2, 1),
695 ("Number", 3, 1),
696 ("Bool", 4, 1),
697 ("Null", 5, 0),
698 ("True", 8, 0),
699 ("False", 9, 0),
700 ("[]", 10, 0),
701 (":", 11, 2),
702 ("Text", 12, 3),
703 ("I#", 13, 1),
704 ];
705 for (i, (name, tag, arity)) in cons.iter().enumerate() {
706 t.insert(DataCon {
707 id: DataConId(i as u64),
708 name: (*name).into(),
709 tag: *tag,
710 rep_arity: *arity,
711 field_bangs: vec![],
712 qualified_name: None,
713 });
714 }
715 t.insert(DataCon {
717 id: DataConId(100),
718 name: "Bin".into(),
719 tag: 1,
720 rep_arity: 5,
721 field_bangs: vec![],
722 qualified_name: Some("Data.Map.Bin".into()),
723 });
724 t.insert(DataCon {
725 id: DataConId(101),
726 name: "Tip".into(),
727 tag: 2,
728 rep_arity: 0,
729 field_bangs: vec![],
730 qualified_name: Some("Data.Map.Tip".into()),
731 });
732 t.insert(DataCon {
734 id: DataConId(200),
735 name: "Bin".into(),
736 tag: 1,
737 rep_arity: 3,
738 field_bangs: vec![],
739 qualified_name: Some("Data.Set.Bin".into()),
740 });
741 t.insert(DataCon {
742 id: DataConId(201),
743 name: "Tip".into(),
744 tag: 2,
745 rep_arity: 0,
746 field_bangs: vec![],
747 qualified_name: Some("Data.Set.Tip".into()),
748 });
749
750 let json = serde_json::json!({"a": 1, "b": 2});
752 let val = json.to_value(&t).unwrap();
753 match &val {
754 Value::Con(id, fields) => {
755 assert_eq!(t.name_of(*id), Some("Object"));
756 match &fields[0] {
758 Value::Con(bin_id, _) => {
759 assert_eq!(*bin_id, DataConId(100));
760 }
761 _ => panic!("Expected Con(Bin)"),
762 }
763 }
764 _ => panic!("Expected Con(Object)"),
765 }
766 }
767}