1extern crate alloc;
4
5pub mod record;
6pub mod tuple;
7
8pub use record::RecordWriter;
9pub use tuple::TupleWriter;
10
11use crate::document::constructor::DocumentConstructor;
12
13use alloc::borrow::{Cow, ToOwned};
14use alloc::string::String;
15use num_bigint::BigInt;
16
17use indexmap::IndexMap;
18
19use crate::document::InsertError;
20use crate::document::constructor::ScopeError;
21use crate::identifier::IdentifierError;
22use crate::parse::VariantPath;
23use crate::path::{ArrayIndexKind, PathSegment};
24use crate::prelude_internal::*;
25use crate::text::Text;
26use crate::value::ValueKind;
27use core::any::type_name;
28
29#[derive(Debug, thiserror::Error, Clone)]
31pub enum WriteError {
32 #[error("insert error: {0}")]
34 Insert(#[from] InsertError),
35
36 #[error("scope error: {0}")]
38 Scope(#[from] ScopeError),
39
40 #[error("invalid identifier: {0}")]
42 InvalidIdentifier(String),
43
44 #[error("invalid $variant extension type: expected text, got {actual}")]
46 InvalidVariantExtensionType { actual: ValueKind },
47
48 #[error("invalid $variant path: {source}")]
50 InvalidVariantPath { source: IdentifierError },
51
52 #[error("non-exhaustive enum variant for {type_name}")]
54 NonExhaustiveVariant { type_name: &'static str },
55
56 #[error("flatten target is not record-like: {type_name}")]
58 FlattenTargetNotRecordLike { type_name: &'static str },
59}
60
61pub trait IntoEure<T = Self>: Sized {
103 type Error: From<WriteError>;
108
109 fn write(value: T, c: &mut DocumentConstructor) -> Result<(), Self::Error>;
111
112 fn write_flatten(value: T, rec: &mut RecordWriter<'_>) -> Result<(), Self::Error> {
118 let _ = value;
119 let _ = rec;
120 Err(WriteError::FlattenTargetNotRecordLike {
121 type_name: type_name::<T>(),
122 }
123 .into())
124 }
125}
126
127impl IntoEure for EureDocument {
128 type Error = WriteError;
129
130 fn write(value: Self, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
131 c.write_subtree(&value, value.get_root_id())
132 }
133}
134
135fn write_subtree_node(
136 src: &EureDocument,
137 node_id: NodeId,
138 c: &mut DocumentConstructor,
139) -> Result<(), WriteError> {
140 let node = src.node(node_id);
141
142 match &node.content {
143 NodeValue::Hole(label) => {
144 c.bind_hole(label.clone())?;
145 }
146 NodeValue::Primitive(prim) => {
147 c.bind_primitive(prim.clone())?;
148 }
149 NodeValue::Array(array) => {
150 c.bind_empty_array()?;
151 for &child_id in array.iter() {
152 let scope = c.begin_scope();
153 c.navigate(PathSegment::ArrayIndex(ArrayIndexKind::Push))?;
154 write_subtree_node(src, child_id, c)?;
155 c.end_scope(scope)?;
156 }
157 }
158 NodeValue::Tuple(tuple) => {
159 c.bind_empty_tuple()?;
160 for (index, &child_id) in tuple.iter().enumerate() {
161 let scope = c.begin_scope();
162 c.navigate(PathSegment::TupleIndex(index as u8))?;
163 write_subtree_node(src, child_id, c)?;
164 c.end_scope(scope)?;
165 }
166 }
167 NodeValue::Map(map) => {
168 c.bind_empty_map()?;
169 for (key, &child_id) in map.iter() {
170 let scope = c.begin_scope();
171 c.navigate(PathSegment::Value(key.clone()))?;
172 write_subtree_node(src, child_id, c)?;
173 c.end_scope(scope)?;
174 }
175 }
176 NodeValue::PartialMap(map) => {
177 c.bind_empty_partial_map()?;
178 for (key, &child_id) in map.iter() {
179 let scope = c.begin_scope();
180 c.navigate_partial_map_entry(key.clone())?;
181 write_subtree_node(src, child_id, c)?;
182 c.end_scope(scope)?;
183 }
184 }
185 }
186
187 for (ident, &ext_node_id) in node.extensions.iter() {
188 let scope = c.begin_scope();
189 c.navigate(PathSegment::Extension(ident.clone()))?;
190 write_subtree_node(src, ext_node_id, c)?;
191 c.end_scope(scope)?;
192 }
193
194 Ok(())
195}
196
197impl IntoEure for bool {
202 type Error = WriteError;
203
204 fn write(value: bool, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
205 c.bind_primitive(PrimitiveValue::Bool(value))
206 .map_err(WriteError::from)?;
207 Ok(())
208 }
209}
210
211macro_rules! impl_into_eure_int {
212 ($($ty:ty),*) => {
213 $(
214 impl IntoEure for $ty {
215 type Error = WriteError;
216
217 fn write(value: $ty, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
218 c.bind_primitive(PrimitiveValue::Integer(BigInt::from(value)))
219 .map_err(WriteError::from)?;
220 Ok(())
221 }
222 }
223 )*
224 };
225}
226
227impl_into_eure_int!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
228
229impl IntoEure for f32 {
230 type Error = WriteError;
231
232 fn write(value: f32, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
233 c.bind_primitive(PrimitiveValue::F32(value))
234 .map_err(WriteError::from)?;
235 Ok(())
236 }
237}
238
239impl IntoEure for f64 {
240 type Error = WriteError;
241
242 fn write(value: f64, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
243 c.bind_primitive(PrimitiveValue::F64(value))
244 .map_err(WriteError::from)?;
245 Ok(())
246 }
247}
248
249impl IntoEure for BigInt {
250 type Error = WriteError;
251
252 fn write(value: BigInt, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
253 c.bind_primitive(PrimitiveValue::Integer(value))
254 .map_err(WriteError::from)?;
255 Ok(())
256 }
257}
258
259impl IntoEure for String {
260 type Error = WriteError;
261
262 fn write(value: String, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
263 c.bind_primitive(PrimitiveValue::Text(Text::plaintext(value)))
264 .map_err(WriteError::from)?;
265 Ok(())
266 }
267}
268
269impl<'a> IntoEure for &'a str {
270 type Error = WriteError;
271
272 fn write(value: &'a str, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
273 c.bind_primitive(PrimitiveValue::Text(Text::plaintext(value)))
274 .map_err(WriteError::from)?;
275 Ok(())
276 }
277}
278
279impl<'a, T> IntoEure<Cow<'a, T>> for Cow<'a, T>
280where
281 T: ToOwned + ?Sized,
282 T::Owned: IntoEure,
283{
284 type Error = <T::Owned as IntoEure>::Error;
285
286 fn write(value: Cow<'a, T>, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
287 <T::Owned as IntoEure>::write(value.into_owned(), c)
288 }
289}
290
291impl IntoEure for Text {
292 type Error = WriteError;
293
294 fn write(value: Text, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
295 c.bind_primitive(PrimitiveValue::Text(value))
296 .map_err(WriteError::from)?;
297 Ok(())
298 }
299}
300
301impl IntoEure for PrimitiveValue {
302 type Error = WriteError;
303
304 fn write(value: PrimitiveValue, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
305 c.bind_primitive(value).map_err(WriteError::from)?;
306 Ok(())
307 }
308}
309
310impl IntoEure for Identifier {
311 type Error = WriteError;
312
313 fn write(value: Identifier, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
314 c.bind_primitive(PrimitiveValue::Text(Text::plaintext(value.into_string())))
315 .map_err(WriteError::from)?;
316 Ok(())
317 }
318}
319
320impl<M, T> IntoEure<Vec<T>> for Vec<M>
325where
326 M: IntoEure<T>,
327{
328 type Error = M::Error;
329
330 fn write(value: Vec<T>, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
331 c.bind_empty_array().map_err(WriteError::from)?;
332 for item in value {
333 let scope = c.begin_scope();
334 c.navigate(PathSegment::ArrayIndex(ArrayIndexKind::Push))
335 .map_err(WriteError::from)?;
336 M::write(item, c)?;
337 c.end_scope(scope).map_err(WriteError::from)?;
338 }
339 Ok(())
340 }
341}
342
343impl<M, T, const N: usize> IntoEure<[T; N]> for [M; N]
344where
345 M: IntoEure<T>,
346{
347 type Error = M::Error;
348
349 fn write(value: [T; N], c: &mut DocumentConstructor) -> Result<(), Self::Error> {
350 c.bind_empty_array().map_err(WriteError::from)?;
351 for item in value {
352 let scope = c.begin_scope();
353 c.navigate(PathSegment::ArrayIndex(ArrayIndexKind::Push))
354 .map_err(WriteError::from)?;
355 M::write(item, c)?;
356 c.end_scope(scope).map_err(WriteError::from)?;
357 }
358 Ok(())
359 }
360}
361
362impl<M, K, V> IntoEure<Map<K, V>> for Map<K, M>
363where
364 M: IntoEure<V>,
365 K: Into<ObjectKey>,
366{
367 type Error = M::Error;
368
369 fn write(value: Map<K, V>, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
370 c.bind_empty_map().map_err(WriteError::from)?;
371 for (key, v) in value {
372 let scope = c.begin_scope();
373 c.navigate(PathSegment::Value(key.into()))
374 .map_err(WriteError::from)?;
375 M::write(v, c)?;
376 c.end_scope(scope).map_err(WriteError::from)?;
377 }
378 Ok(())
379 }
380
381 fn write_flatten(value: Map<K, V>, rec: &mut RecordWriter<'_>) -> Result<(), Self::Error> {
382 for (key, v) in value {
383 let key = match key.into() {
384 ObjectKey::String(name) => name,
385 _ => {
386 return Err(WriteError::FlattenTargetNotRecordLike {
387 type_name: type_name::<Map<K, V>>(),
388 }
389 .into());
390 }
391 };
392 rec.field_via::<M, _>(&key, v)?;
393 }
394 Ok(())
395 }
396}
397
398impl<M, K, V> IntoEure<IndexMap<K, V>> for IndexMap<K, M>
399where
400 M: IntoEure<V>,
401 K: Into<ObjectKey> + Eq + std::hash::Hash,
402{
403 type Error = M::Error;
404
405 fn write(value: IndexMap<K, V>, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
406 c.bind_empty_map().map_err(WriteError::from)?;
407 for (key, v) in value {
408 let scope = c.begin_scope();
409 c.navigate(PathSegment::Value(key.into()))
410 .map_err(WriteError::from)?;
411 M::write(v, c)?;
412 c.end_scope(scope).map_err(WriteError::from)?;
413 }
414 Ok(())
415 }
416
417 fn write_flatten(value: IndexMap<K, V>, rec: &mut RecordWriter<'_>) -> Result<(), Self::Error> {
418 for (key, v) in value {
419 let key = match key.into() {
420 ObjectKey::String(name) => name,
421 _ => {
422 return Err(WriteError::FlattenTargetNotRecordLike {
423 type_name: type_name::<IndexMap<K, V>>(),
424 }
425 .into());
426 }
427 };
428 rec.field_via::<M, _>(&key, v)?;
429 }
430 Ok(())
431 }
432}
433
434impl<M, T> IntoEure<Option<T>> for Option<M>
435where
436 M: IntoEure<T>,
437{
438 type Error = M::Error;
439
440 fn write(value: Option<T>, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
441 match value {
442 Some(v) => M::write(v, c),
443 None => {
444 c.bind_primitive(PrimitiveValue::Null)
445 .map_err(WriteError::from)?;
446 Ok(())
447 }
448 }
449 }
450}
451
452macro_rules! impl_into_document_tuple {
457 ($n:expr, $($idx:tt: $marker:ident : $ty:ident),+) => {
458 impl<$($marker, $ty),+, __E> IntoEure<($($ty,)+)> for ($($marker,)+)
459 where
460 $($marker: IntoEure<$ty, Error = __E>,)+
461 __E: From<WriteError>,
462 {
463 type Error = __E;
464
465 fn write(value: ($($ty,)+), c: &mut DocumentConstructor) -> Result<(), Self::Error> {
466 c.bind_empty_tuple().map_err(WriteError::from)?;
467 $(
468 let scope = c.begin_scope();
469 c.navigate(PathSegment::TupleIndex($idx)).map_err(WriteError::from)?;
470 $marker::write(value.$idx, c)?;
471 c.end_scope(scope).map_err(WriteError::from)?;
472 )+
473 Ok(())
474 }
475 }
476 };
477}
478
479impl_into_document_tuple!(1, 0: MA: A);
480impl_into_document_tuple!(2, 0: MA: A, 1: MB: B);
481impl_into_document_tuple!(3, 0: MA: A, 1: MB: B, 2: MC: C);
482impl_into_document_tuple!(4, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D);
483impl_into_document_tuple!(5, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E);
484impl_into_document_tuple!(6, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F);
485impl_into_document_tuple!(7, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G);
486impl_into_document_tuple!(8, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H);
487impl_into_document_tuple!(9, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I);
488impl_into_document_tuple!(10, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I, 9: MJ: J);
489impl_into_document_tuple!(11, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I, 9: MJ: J, 10: MK: K);
490impl_into_document_tuple!(12, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I, 9: MJ: J, 10: MK: K, 11: ML: L);
491impl_into_document_tuple!(13, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I, 9: MJ: J, 10: MK: K, 11: ML: L, 12: MM: M);
492impl_into_document_tuple!(14, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I, 9: MJ: J, 10: MK: K, 11: ML: L, 12: MM: M, 13: MN: N);
493impl_into_document_tuple!(15, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I, 9: MJ: J, 10: MK: K, 11: ML: L, 12: MM: M, 13: MN: N, 14: MO: O);
494impl_into_document_tuple!(16, 0: MA: A, 1: MB: B, 2: MC: C, 3: MD: D, 4: ME: E, 5: MF: F, 6: MG: G, 7: MH: H, 8: MI: I, 9: MJ: J, 10: MK: K, 11: ML: L, 12: MM: M, 13: MN: N, 14: MO: O, 15: MP: P);
495
496impl DocumentConstructor {
501 pub fn record<F, T, E>(&mut self, f: F) -> Result<T, E>
513 where
514 F: FnOnce(&mut RecordWriter<'_>) -> Result<T, E>,
515 E: From<WriteError>,
516 {
517 self.bind_empty_map().map_err(WriteError::from)?;
518 let mut writer = RecordWriter::new(self);
519 f(&mut writer)
520 }
521
522 pub fn tuple<F, T, E>(&mut self, f: F) -> Result<T, E>
535 where
536 F: FnOnce(&mut TupleWriter<'_>) -> Result<T, E>,
537 E: From<WriteError>,
538 {
539 self.bind_empty_tuple().map_err(WriteError::from)?;
540 let mut writer = TupleWriter::new(self);
541 f(&mut writer)
542 }
543
544 pub fn set_extension<T: IntoEure>(&mut self, name: &str, value: T) -> Result<(), T::Error> {
552 let ident: Identifier = name
553 .parse()
554 .map_err(|_| WriteError::InvalidIdentifier(name.into()))?;
555 let scope = self.begin_scope();
556 self.navigate(PathSegment::Extension(ident))
557 .map_err(WriteError::from)?;
558 T::write(value, self)?;
559 self.end_scope(scope).map_err(WriteError::from)?;
560 Ok(())
561 }
562
563 pub fn set_extension_optional<T: IntoEure>(
572 &mut self,
573 name: &str,
574 value: Option<T>,
575 ) -> Result<(), T::Error> {
576 if let Some(v) = value {
577 self.set_extension(name, v)?;
578 }
579 Ok(())
580 }
581
582 pub fn set_variant(&mut self, variant: &str) -> Result<(), WriteError> {
598 VariantPath::parse(variant)
599 .map_err(|err| WriteError::InvalidVariantPath { source: err })?;
600 let current_id = self.current_node_id();
601 if let Some(variant_node_id) = self
602 .document()
603 .node(current_id)
604 .get_extension(&Identifier::VARIANT)
605 {
606 let node = self.document().node(variant_node_id);
607 let existing = match node.as_primitive().and_then(|value| value.as_str()) {
608 Some(existing) => existing,
609 None => {
610 let actual = node.content.value_kind();
611 return Err(WriteError::InvalidVariantExtensionType { actual });
612 }
613 };
614 VariantPath::parse(existing)
615 .map_err(|err| WriteError::InvalidVariantPath { source: err })?;
616 let mut combined = String::with_capacity(existing.len() + 1 + variant.len());
617 combined.push_str(existing);
618 combined.push('.');
619 combined.push_str(variant);
620 self.document_mut().node_mut(variant_node_id).content =
621 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext(combined)));
622 Ok(())
623 } else {
624 self.set_extension("variant", variant)
625 }
626 }
627
628 pub fn write_subtree(&mut self, src: &EureDocument, node_id: NodeId) -> Result<(), WriteError> {
633 write_subtree_node(src, node_id, self)
634 }
635
636 pub fn write<T: IntoEure>(&mut self, value: T) -> Result<(), T::Error> {
644 T::write(value, self)
645 }
646
647 pub fn write_via<M, T>(&mut self, value: T) -> Result<(), M::Error>
659 where
660 M: IntoEure<T>,
661 {
662 M::write(value, self)
663 }
664}
665
666#[cfg(test)]
667mod tests {
668 use super::*;
669
670 #[test]
671 fn test_primitive_bool() {
672 let mut c = DocumentConstructor::new();
673 c.write(true).unwrap();
674 let doc = c.finish();
675 assert_eq!(
676 doc.root().content,
677 NodeValue::Primitive(PrimitiveValue::Bool(true))
678 );
679 }
680
681 #[test]
682 fn test_primitive_string() {
683 let mut c = DocumentConstructor::new();
684 c.write("hello").unwrap();
685 let doc = c.finish();
686 assert_eq!(
687 doc.root().content,
688 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("hello")))
689 );
690 }
691
692 #[test]
693 fn test_vec() {
694 let mut c = DocumentConstructor::new();
695 c.write(vec![1i32, 2, 3]).unwrap();
696 let doc = c.finish();
697 let arr = doc.root().as_array().unwrap();
698 assert_eq!(arr.len(), 3);
699 }
700
701 #[test]
702 fn test_tuple() {
703 let mut c = DocumentConstructor::new();
704 c.write((1i32, "two", true)).unwrap();
705 let doc = c.finish();
706 let tuple = doc.root().as_tuple().unwrap();
707 assert_eq!(tuple.len(), 3);
708 }
709
710 #[test]
711 fn test_tuple_roundtrip() {
712 let original = (42i32, "hello".to_string(), true);
713
714 let mut c = DocumentConstructor::new();
716 c.write(original.clone()).unwrap();
717 let doc = c.finish();
718
719 assert_eq!(eure!({=(42i32, "hello", true)}), doc);
720
721 let root_id = doc.get_root_id();
723 let parsed: (i32, String, bool) = doc.parse(root_id).unwrap();
724
725 assert_eq!(parsed, original);
726 }
727
728 #[test]
729 fn test_record() {
730 let mut c = DocumentConstructor::new();
731 c.record(|rec| {
732 rec.field("name", "Alice")?;
733 rec.field("age", 30i32)?;
734 Ok::<(), WriteError>(())
735 })
736 .unwrap();
737 let doc = c.finish();
738 let map = doc.root().as_map().unwrap();
739 assert_eq!(map.len(), 2);
740 }
741
742 #[test]
743 fn test_set_extension() {
744 let mut c = DocumentConstructor::new();
745 c.record(|rec| {
746 rec.field("type", "string")?;
747 Ok::<(), WriteError>(())
748 })
749 .unwrap();
750 c.set_extension("optional", true).unwrap();
751 let doc = c.finish();
752
753 let root = doc.root();
754 assert!(
755 root.extensions
756 .contains_key(&"optional".parse::<Identifier>().unwrap())
757 );
758 }
759
760 #[test]
761 fn test_set_variant() {
762 let mut c = DocumentConstructor::new();
763 c.set_variant("foo").unwrap();
764 c.record(|rec| {
765 rec.field("value", 42i32)?;
766 Ok::<(), WriteError>(())
767 })
768 .unwrap();
769 let doc = c.finish();
770
771 let root = doc.root();
772 assert!(
773 root.extensions
774 .contains_key(&"variant".parse::<Identifier>().unwrap())
775 );
776 }
777
778 #[test]
779 fn test_set_variant_invalid_extension_type() {
780 let mut c = DocumentConstructor::new();
781 c.set_extension("variant", 1i32).unwrap();
782 let err = c.set_variant("foo").unwrap_err();
783 assert!(matches!(
784 err,
785 WriteError::InvalidVariantExtensionType {
786 actual: ValueKind::Integer
787 }
788 ));
789 }
790
791 #[test]
792 fn test_nested_record() {
793 let mut c = DocumentConstructor::new();
794 c.record(|rec| {
795 rec.field("name", "Alice")?;
796 rec.field_with("address", |c| {
797 c.record(|rec| {
798 rec.field("city", "Tokyo")?;
799 rec.field("zip", "100-0001")?;
800 Ok::<(), WriteError>(())
801 })
802 })?;
803 Ok::<(), WriteError>(())
804 })
805 .unwrap();
806 let doc = c.finish();
807 let map = doc.root().as_map().unwrap();
808 assert_eq!(map.len(), 2);
809 }
810
811 #[test]
812 fn test_write_via() {
813 struct DurationMarker;
815 struct DurationLike {
816 secs: u64,
817 nanos: u32,
818 }
819
820 impl IntoEure<DurationLike> for DurationMarker {
821 type Error = WriteError;
822
823 fn write(value: DurationLike, c: &mut DocumentConstructor) -> Result<(), Self::Error> {
824 c.record(|rec| {
825 rec.field("secs", value.secs)?;
826 rec.field("nanos", value.nanos)?;
827 Ok::<(), WriteError>(())
828 })
829 }
830 }
831
832 let mut c = DocumentConstructor::new();
833 c.write_via::<DurationMarker, _>(DurationLike {
834 secs: 60,
835 nanos: 123,
836 })
837 .unwrap();
838 let doc = c.finish();
839 let map = doc.root().as_map().unwrap();
840 assert_eq!(map.len(), 2);
841 }
842
843 #[test]
844 fn test_array_write() {
845 let mut c = DocumentConstructor::new();
846 c.write([1i32, 2, 3]).unwrap();
847 let doc = c.finish();
848 let arr = doc.root().as_array().unwrap();
849 assert_eq!(arr.len(), 3);
850 }
851
852 #[test]
853 fn test_array_empty_write() {
854 let mut c = DocumentConstructor::new();
855 let empty: [i32; 0] = [];
856 c.write(empty).unwrap();
857 let doc = c.finish();
858 let arr = doc.root().as_array().unwrap();
859 assert_eq!(arr.len(), 0);
860 }
861
862 #[test]
863 fn test_array_roundtrip() {
864 let original: [i32; 3] = [10, 20, 30];
865
866 let mut c = DocumentConstructor::new();
868 c.write(original).unwrap();
869 let doc = c.finish();
870
871 let root_id = doc.get_root_id();
873 let parsed: [i32; 3] = doc.parse(root_id).unwrap();
874
875 assert_eq!(parsed, original);
876 }
877
878 #[test]
883 fn test_regex_roundtrip() {
884 let original = regex::Regex::new(r"^[a-z]+\d{2,4}$").unwrap();
885
886 let mut c = DocumentConstructor::new();
888 c.write(original.clone()).unwrap();
889 let doc = c.finish();
890
891 let root_id = doc.get_root_id();
893 let parsed: regex::Regex = doc.parse(root_id).unwrap();
894
895 assert_eq!(parsed.as_str(), original.as_str());
896 }
897
898 #[test]
903 fn test_cow_borrowed_str() {
904 let mut c = DocumentConstructor::new();
905 let value: Cow<'_, str> = Cow::Borrowed("hello");
906 c.write(value).unwrap();
907 let doc = c.finish();
908 assert_eq!(
909 doc.root().content,
910 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("hello")))
911 );
912 }
913
914 #[test]
915 fn test_cow_owned_str() {
916 let mut c = DocumentConstructor::new();
917 let value: Cow<'static, str> = Cow::Owned("hello".to_string());
918 c.write(value).unwrap();
919 let doc = c.finish();
920 assert_eq!(
921 doc.root().content,
922 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("hello")))
923 );
924 }
925
926 #[test]
931 fn test_document_write_primitive() {
932 let src = eure!({ = "hello" });
933 let mut c = DocumentConstructor::new();
934 c.write(src.clone()).unwrap();
935 let result = c.finish();
936 assert_eq!(result, src);
937 }
938
939 #[test]
940 fn test_document_write_map() {
941 let src = eure!({
942 name = "Alice"
943 age = 30
944 });
945 let mut c = DocumentConstructor::new();
946 c.write(src.clone()).unwrap();
947 let result = c.finish();
948 assert_eq!(result, src);
949 }
950
951 #[test]
952 fn test_document_write_array() {
953 let src = eure!({ = [1, 2, 3] });
954 let mut c = DocumentConstructor::new();
955 c.write(src.clone()).unwrap();
956 let result = c.finish();
957 assert_eq!(result, src);
958 }
959
960 #[test]
961 fn test_document_write_nested() {
962 let src = eure!({
963 name = "Alice"
964 address {
965 city = "Tokyo"
966 zip = "100-0001"
967 }
968 tags = ["a", "b"]
969 });
970 let mut c = DocumentConstructor::new();
971 c.write(src.clone()).unwrap();
972 let result = c.finish();
973 assert_eq!(result, src);
974 }
975
976 #[test]
977 fn test_document_write_as_field() {
978 let inner = eure!({ city = "Tokyo" });
979 let mut c = DocumentConstructor::new();
980 c.record(|rec| {
981 rec.field("name", "Alice")?;
982 rec.field("address", inner)?;
983 Ok::<(), WriteError>(())
984 })
985 .unwrap();
986 let result = c.finish();
987 let expected = eure!({
988 name = "Alice"
989 address { city = "Tokyo" }
990 });
991 assert_eq!(result, expected);
992 }
993
994 #[test]
995 fn test_document_write_subtree() {
996 let src = eure!({
997 name = "Alice"
998 active = true
999 });
1000 let mut c = DocumentConstructor::new();
1001 c.write_subtree(&src, src.get_root_id()).unwrap();
1002 let result = c.finish();
1003 assert_eq!(result, src);
1004 }
1005}