1#![doc = include_str!("../README.md")]
2
3mod config;
4mod error;
5
6pub use config::Config;
7pub use error::{EureToJsonError, JsonToEureError};
8use eure::data_model::VariantRepr;
9use eure::document::node::NodeValue;
10use eure::document::{EureDocument, NodeId};
11use eure::query::{ParseDocument, TextFile, read_text_file};
12use eure::value::{ObjectKey, PrimitiveValue};
13use eure_document::text::Text;
14use num_bigint::BigInt;
15use query_flow::{Db, QueryError, query};
16use serde_json::Value as JsonValue;
17
18#[query]
19pub fn eure_to_json(
20 db: &impl Db,
21 text_file: TextFile,
22 config: Config,
23) -> Result<JsonValue, QueryError> {
24 let parsed = db.query(ParseDocument::new(text_file.clone()))?;
25 Ok(document_to_value(&parsed.doc, &config)?)
26}
27
28#[query]
32pub fn json_to_eure(
33 db: &impl Db,
34 json_file: TextFile,
35 config: Config,
36) -> Result<EureDocument, QueryError> {
37 let content = read_text_file(db, json_file)?;
38 let json: JsonValue = serde_json::from_str(&content)?;
39 Ok(value_to_document(&json, &config)?)
40}
41
42pub fn document_to_value(
43 doc: &EureDocument,
44 config: &Config,
45) -> Result<JsonValue, EureToJsonError> {
46 let root_id = doc.get_root_id();
47 convert_node(doc, root_id, config)
48}
49
50fn convert_node(
51 doc: &EureDocument,
52 node_id: NodeId,
53 config: &Config,
54) -> Result<JsonValue, EureToJsonError> {
55 let node = doc.node(node_id);
56
57 let variant_ext: Option<&str> = node
59 .extensions
60 .iter()
61 .find(|(k, _)| k.as_ref() == "variant")
62 .and_then(|(_, &ext_id)| {
63 if let NodeValue::Primitive(PrimitiveValue::Text(t)) = &doc.node(ext_id).content {
64 Some(t.as_str())
65 } else {
66 None
67 }
68 });
69
70 if let Some(tag) = variant_ext {
72 return convert_variant_node(doc, node_id, tag, config);
73 }
74
75 match &node.content {
76 NodeValue::Hole(_) => Err(EureToJsonError::HoleNotSupported),
77 NodeValue::Primitive(prim) => convert_primitive(prim),
78 NodeValue::Array(arr) => {
79 let mut result = Vec::new();
80 for &child_id in &arr.0 {
81 result.push(convert_node(doc, child_id, config)?);
82 }
83 Ok(JsonValue::Array(result))
84 }
85 NodeValue::Tuple(tuple) => {
86 let mut result = Vec::new();
87 for &child_id in &tuple.0 {
88 result.push(convert_node(doc, child_id, config)?);
89 }
90 Ok(JsonValue::Array(result))
91 }
92 NodeValue::Map(map) => {
93 let mut result = serde_json::Map::new();
94 for (key, &child_id) in &map.0 {
95 let key_string = convert_object_key(key)?;
96 let value = convert_node(doc, child_id, config)?;
97 result.insert(key_string, value);
98 }
99 Ok(JsonValue::Object(result))
100 }
101 }
102}
103
104fn convert_primitive(prim: &PrimitiveValue) -> Result<JsonValue, EureToJsonError> {
105 match prim {
106 PrimitiveValue::Null => Ok(JsonValue::Null),
107 PrimitiveValue::Bool(b) => Ok(JsonValue::Bool(*b)),
108 PrimitiveValue::Integer(bi) => {
109 let i64_value = bi.to_string().parse::<i64>();
111 if let Ok(i) = i64_value {
112 return Ok(JsonValue::Number(i.into()));
113 }
114
115 let u64_value = bi.to_string().parse::<u64>();
117 if let Ok(u) = u64_value {
118 return Ok(JsonValue::Number(u.into()));
119 }
120
121 Err(EureToJsonError::BigIntOutOfRange)
122 }
123 PrimitiveValue::F32(f) => {
124 if let Some(num) = serde_json::Number::from_f64(*f as f64) {
125 Ok(JsonValue::Number(num))
126 } else {
127 Err(EureToJsonError::NonFiniteFloat)
129 }
130 }
131 PrimitiveValue::F64(f) => {
132 if let Some(num) = serde_json::Number::from_f64(*f) {
133 Ok(JsonValue::Number(num))
134 } else {
135 Err(EureToJsonError::NonFiniteFloat)
137 }
138 }
139 PrimitiveValue::Text(text) => Ok(JsonValue::String(text.content.clone())),
140 }
141}
142
143fn convert_variant_node(
145 doc: &EureDocument,
146 node_id: NodeId,
147 tag: &str,
148 config: &Config,
149) -> Result<JsonValue, EureToJsonError> {
150 let content_json = convert_node_content_only(doc, node_id, config)?;
152
153 match &config.variant_repr {
154 VariantRepr::External => {
155 let mut map = serde_json::Map::new();
157 map.insert(tag.to_string(), content_json);
158 Ok(JsonValue::Object(map))
159 }
160 VariantRepr::Internal { tag: tag_field } => {
161 if let JsonValue::Object(mut content_map) = content_json {
164 if content_map.contains_key(tag_field) {
166 return Err(EureToJsonError::VariantTagConflict {
167 tag: tag_field.clone(),
168 });
169 }
170 content_map.insert(tag_field.clone(), JsonValue::String(tag.to_string()));
171 Ok(JsonValue::Object(content_map))
172 } else {
173 let mut map = serde_json::Map::new();
175 map.insert(tag.to_string(), content_json);
176 Ok(JsonValue::Object(map))
177 }
178 }
179 VariantRepr::Adjacent {
180 tag: tag_field,
181 content: content_key,
182 } => {
183 if tag_field == content_key {
186 return Err(EureToJsonError::VariantAdjacentConflict {
187 field: tag_field.clone(),
188 });
189 }
190 let mut map = serde_json::Map::new();
191 map.insert(tag_field.clone(), JsonValue::String(tag.to_string()));
192 map.insert(content_key.clone(), content_json);
193 Ok(JsonValue::Object(map))
194 }
195 VariantRepr::Untagged => {
196 Ok(content_json)
198 }
199 }
200}
201
202fn convert_node_content_only(
204 doc: &EureDocument,
205 node_id: NodeId,
206 config: &Config,
207) -> Result<JsonValue, EureToJsonError> {
208 let node = doc.node(node_id);
209
210 match &node.content {
211 NodeValue::Hole(_) => Err(EureToJsonError::HoleNotSupported),
212 NodeValue::Primitive(prim) => convert_primitive(prim),
213 NodeValue::Array(arr) => {
214 let mut result = Vec::new();
215 for &child_id in &arr.0 {
216 result.push(convert_node(doc, child_id, config)?);
217 }
218 Ok(JsonValue::Array(result))
219 }
220 NodeValue::Tuple(tuple) => {
221 let mut result = Vec::new();
222 for &child_id in &tuple.0 {
223 result.push(convert_node(doc, child_id, config)?);
224 }
225 Ok(JsonValue::Array(result))
226 }
227 NodeValue::Map(map) => {
228 let mut result = serde_json::Map::new();
229 for (key, &child_id) in &map.0 {
230 let key_string = convert_object_key(key)?;
231 let value = convert_node(doc, child_id, config)?;
232 result.insert(key_string, value);
233 }
234 Ok(JsonValue::Object(result))
235 }
236 }
237}
238
239fn convert_object_key(key: &ObjectKey) -> Result<String, EureToJsonError> {
240 match key {
241 ObjectKey::Number(n) => Ok(n.to_string()),
242 ObjectKey::String(s) => Ok(s.clone()),
243 ObjectKey::Tuple(tuple) => {
244 let mut parts = Vec::new();
245 for item in &tuple.0 {
246 parts.push(convert_object_key(item)?);
247 }
248 Ok(format!("({})", parts.join(", ")))
249 }
250 }
251}
252
253pub fn value_to_document(
276 value: &JsonValue,
277 _config: &Config,
278) -> Result<EureDocument, JsonToEureError> {
279 let mut doc = EureDocument::new();
280 let root_id = doc.get_root_id();
281 convert_json_to_node(&mut doc, root_id, value);
282 Ok(doc)
283}
284
285fn convert_json_to_node(doc: &mut EureDocument, node_id: NodeId, value: &JsonValue) {
287 match value {
288 JsonValue::Null => {
289 doc.node_mut(node_id).content = NodeValue::Primitive(PrimitiveValue::Null);
290 }
291 JsonValue::Bool(b) => {
292 doc.node_mut(node_id).content = NodeValue::Primitive(PrimitiveValue::Bool(*b));
293 }
294 JsonValue::Number(n) => {
295 if let Some(i) = n.as_i64() {
296 doc.node_mut(node_id).content =
297 NodeValue::Primitive(PrimitiveValue::Integer(BigInt::from(i)));
298 } else if let Some(u) = n.as_u64() {
299 doc.node_mut(node_id).content =
300 NodeValue::Primitive(PrimitiveValue::Integer(BigInt::from(u)));
301 } else if let Some(f) = n.as_f64() {
302 doc.node_mut(node_id).content = NodeValue::Primitive(PrimitiveValue::F64(f));
303 }
304 }
305 JsonValue::String(s) => {
306 doc.node_mut(node_id).content =
307 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext(s.clone())));
308 }
309 JsonValue::Array(arr) => {
310 doc.node_mut(node_id).content = NodeValue::empty_array();
311 for item in arr {
312 let child_id = doc.create_node(NodeValue::hole());
313 convert_json_to_node(doc, child_id, item);
314 if let NodeValue::Array(ref mut array) = doc.node_mut(node_id).content {
315 array.0.push(child_id);
316 }
317 }
318 }
319 JsonValue::Object(obj) => {
320 doc.node_mut(node_id).content = NodeValue::empty_map();
321 for (key, val) in obj {
322 let child_id = doc.create_node(NodeValue::hole());
323 convert_json_to_node(doc, child_id, val);
324 if let NodeValue::Map(ref mut map) = doc.node_mut(node_id).content {
325 map.0.insert(ObjectKey::String(key.clone()), child_id);
326 }
327 }
328 }
329 }
330}
331
332#[cfg(test)]
333mod tests {
334 use super::*;
335 use eure::data_model::VariantRepr;
336 use eure_document::eure;
337 use serde_json::json;
338
339 #[test]
344 fn test_null() {
345 let eure = eure!({ = null });
346 let json = json!(null);
347 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
348 }
349
350 #[test]
351 fn test_bool_true() {
352 let eure = eure!({ = true });
353 let json = json!(true);
354 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
355 }
356
357 #[test]
358 fn test_bool_false() {
359 let eure = eure!({ = false });
360 let json = json!(false);
361 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
362 }
363
364 #[test]
365 fn test_integer() {
366 let eure = eure!({ = 42 });
367 let json = json!(42);
368 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
369 }
370
371 #[test]
372 fn test_negative_integer() {
373 let eure = eure!({ = -42 });
374 let json = json!(-42);
375 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
376 }
377
378 #[test]
379 fn test_float() {
380 let eure = eure!({ = 1.5f64 });
381 let json = json!(1.5);
382 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
383 }
384
385 #[test]
386 fn test_string() {
387 let eure = eure!({ = "hello world" });
388 let json = json!("hello world");
389 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
390 }
391
392 #[test]
393 fn test_array() {
394 let eure = eure!({
395 items[] = 1,
396 items[] = 2,
397 items[] = 3,
398 });
399 let json = json!({"items": [1, 2, 3]});
400 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
401 }
402
403 #[test]
404 fn test_tuple() {
405 let eure = eure!({
406 point.#0 = 1.5f64,
407 point.#1 = 2.5f64,
408 });
409 let json = json!({"point": [1.5, 2.5]});
410 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
411 }
412
413 #[test]
414 fn test_empty_map() {
415 let eure = eure!({});
416 let json = json!({});
417 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
418 }
419
420 #[test]
421 fn test_map_with_fields() {
422 let eure = eure!({ key = true });
423 let json = json!({"key": true});
424 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
425 }
426
427 #[test]
428 fn test_nested_map() {
429 let eure = eure!({
430 user.name = "Alice",
431 user.age = 30,
432 });
433 let json = json!({"user": {"name": "Alice", "age": 30}});
434 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
435 }
436
437 #[test]
438 fn test_array_of_maps() {
439 let eure = eure!({
440 users[].name = "Alice",
441 users[].name = "Bob",
442 });
443 let json = json!({"users": [{"name": "Alice"}, {"name": "Bob"}]});
444 assert_eq!(document_to_value(&eure, &Config::default()).unwrap(), json);
445 }
446
447 #[test]
449 fn test_variant_external() {
450 let eure = eure!({
451 = true,
452 %variant = "Success",
453 });
454 let config = Config {
455 variant_repr: VariantRepr::External,
456 };
457 let json = json!({"Success": true});
458 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
459 }
460
461 #[test]
462 fn test_variant_untagged() {
463 let eure = eure!({
464 = true,
465 %variant = "Success",
466 });
467 let config = Config {
468 variant_repr: VariantRepr::Untagged,
469 };
470 let json = json!(true);
471 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
472 }
473
474 #[test]
475 fn test_variant_internal() {
476 let eure = eure!({
477 field = 42,
478 %variant = "Success",
479 });
480 let config = Config {
481 variant_repr: VariantRepr::Internal {
482 tag: "type".to_string(),
483 },
484 };
485 let json = json!({"type": "Success", "field": 42});
486 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
487 }
488
489 #[test]
490 fn test_variant_adjacent() {
491 let eure = eure!({
492 = true,
493 %variant = "Success",
494 });
495 let config = Config {
496 variant_repr: VariantRepr::Adjacent {
497 tag: "tag".to_string(),
498 content: "content".to_string(),
499 },
500 };
501 let json = json!({"tag": "Success", "content": true});
502 assert_eq!(document_to_value(&eure, &config).unwrap(), json);
503 }
504
505 #[test]
507 fn test_hole_error() {
508 let eure = eure!({ placeholder = ! });
509 let result = document_to_value(&eure, &Config::default());
510 assert_eq!(result, Err(EureToJsonError::HoleNotSupported));
511 }
512
513 #[test]
514 fn test_f64_nan_error() {
515 let nan_value = f64::NAN;
516 let eure = eure!({ = nan_value });
517 let result = document_to_value(&eure, &Config::default());
518 assert_eq!(result, Err(EureToJsonError::NonFiniteFloat));
519 }
520
521 #[test]
522 fn test_f64_infinity_error() {
523 let inf_value = f64::INFINITY;
524 let eure = eure!({ = inf_value });
525 let result = document_to_value(&eure, &Config::default());
526 assert_eq!(result, Err(EureToJsonError::NonFiniteFloat));
527 }
528
529 #[test]
534 fn test_json_to_eure_null() {
535 let json = json!(null);
536 let expected = eure!({ = null });
537 assert_eq!(
538 value_to_document(&json, &Config::default()).unwrap(),
539 expected
540 );
541 }
542
543 #[test]
544 fn test_json_to_eure_bool() {
545 let json = json!(true);
546 let expected = eure!({ = true });
547 assert_eq!(
548 value_to_document(&json, &Config::default()).unwrap(),
549 expected
550 );
551 }
552
553 #[test]
554 fn test_json_to_eure_integer() {
555 let json = json!(42);
556 let expected = eure!({ = 42 });
557 assert_eq!(
558 value_to_document(&json, &Config::default()).unwrap(),
559 expected
560 );
561 }
562
563 #[test]
564 fn test_json_to_eure_float() {
565 let json = json!(1.5);
566 let expected = eure!({ = 1.5f64 });
567 assert_eq!(
568 value_to_document(&json, &Config::default()).unwrap(),
569 expected
570 );
571 }
572
573 #[test]
574 fn test_json_to_eure_string() {
575 let json = json!("hello");
576 let expected = eure!({ = "hello" });
577 assert_eq!(
578 value_to_document(&json, &Config::default()).unwrap(),
579 expected
580 );
581 }
582
583 #[test]
584 fn test_json_to_eure_array() {
585 let json = json!([1, 2, 3]);
587 let doc = value_to_document(&json, &Config::default()).unwrap();
588 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
589 assert_eq!(json, roundtrip);
590 }
591
592 #[test]
593 fn test_json_to_eure_empty_object() {
594 let json = json!({});
595 let expected = eure!({});
596 assert_eq!(
597 value_to_document(&json, &Config::default()).unwrap(),
598 expected
599 );
600 }
601
602 #[test]
603 fn test_json_to_eure_object() {
604 let json = json!({"name": "Alice", "age": 30});
605 let expected = eure!({
606 name = "Alice",
607 age = 30,
608 });
609 assert_eq!(
610 value_to_document(&json, &Config::default()).unwrap(),
611 expected
612 );
613 }
614
615 #[test]
616 fn test_json_to_eure_nested() {
617 let json = json!({"user": {"name": "Alice"}});
618 let expected = eure!({ user.name = "Alice" });
619 assert_eq!(
620 value_to_document(&json, &Config::default()).unwrap(),
621 expected
622 );
623 }
624
625 #[test]
626 fn test_json_to_eure_array_of_objects() {
627 let json = json!({"users": [{"name": "Alice"}, {"name": "Bob"}]});
628 let expected = eure!({
629 users[].name = "Alice",
630 users[].name = "Bob",
631 });
632 assert_eq!(
633 value_to_document(&json, &Config::default()).unwrap(),
634 expected
635 );
636 }
637
638 #[test]
643 fn test_roundtrip_primitives() {
644 for json in [
645 json!(null),
646 json!(true),
647 json!(42),
648 json!(1.5),
649 json!("hello"),
650 ] {
651 let doc = value_to_document(&json, &Config::default()).unwrap();
652 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
653 assert_eq!(json, roundtrip);
654 }
655 }
656
657 #[test]
658 fn test_roundtrip_array() {
659 let json = json!([1, 2, 3, "hello", true, null]);
660 let doc = value_to_document(&json, &Config::default()).unwrap();
661 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
662 assert_eq!(json, roundtrip);
663 }
664
665 #[test]
666 fn test_roundtrip_nested() {
667 let json = json!({"name": "test", "nested": {"a": 1, "b": [true, false]}});
668 let doc = value_to_document(&json, &Config::default()).unwrap();
669 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
670 assert_eq!(json, roundtrip);
671 }
672
673 #[test]
674 fn test_roundtrip_deeply_nested() {
675 let json = json!({"Ok": {"Some": {"method": "add"}}});
676 let doc = value_to_document(&json, &Config::default()).unwrap();
677 let roundtrip = document_to_value(&doc, &Config::default()).unwrap();
678 assert_eq!(json, roundtrip);
679 }
680}