1extern crate alloc;
4
5pub mod record;
6pub mod tuple;
7
8pub use record::RecordWriter;
9pub use tuple::TupleWriter;
10
11use alloc::string::String;
12use num_bigint::BigInt;
13
14use crate::document::InsertError;
15use crate::document::constructor::{DocumentConstructor, ScopeError};
16use crate::path::PathSegment;
17use crate::prelude_internal::*;
18use crate::text::Text;
19
20#[derive(Debug, thiserror::Error, Clone)]
22pub enum WriteError {
23 #[error("insert error: {0}")]
25 Insert(#[from] InsertError),
26
27 #[error("scope error: {0}")]
29 Scope(#[from] ScopeError),
30
31 #[error("invalid identifier: {0}")]
33 InvalidIdentifier(String),
34}
35
36pub trait IntoDocument {
55 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError>;
57}
58
59impl IntoDocument for bool {
64 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
65 c.bind_primitive(PrimitiveValue::Bool(self))?;
66 Ok(())
67 }
68}
69
70impl IntoDocument for i32 {
71 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
72 c.bind_primitive(PrimitiveValue::Integer(BigInt::from(self)))?;
73 Ok(())
74 }
75}
76
77impl IntoDocument for i64 {
78 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
79 c.bind_primitive(PrimitiveValue::Integer(BigInt::from(self)))?;
80 Ok(())
81 }
82}
83
84impl IntoDocument for u32 {
85 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
86 c.bind_primitive(PrimitiveValue::Integer(BigInt::from(self)))?;
87 Ok(())
88 }
89}
90
91impl IntoDocument for u64 {
92 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
93 c.bind_primitive(PrimitiveValue::Integer(BigInt::from(self)))?;
94 Ok(())
95 }
96}
97
98impl IntoDocument for usize {
99 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
100 c.bind_primitive(PrimitiveValue::Integer(BigInt::from(self)))?;
101 Ok(())
102 }
103}
104
105impl IntoDocument for f32 {
106 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
107 c.bind_primitive(PrimitiveValue::F32(self))?;
108 Ok(())
109 }
110}
111
112impl IntoDocument for f64 {
113 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
114 c.bind_primitive(PrimitiveValue::F64(self))?;
115 Ok(())
116 }
117}
118
119impl IntoDocument for BigInt {
120 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
121 c.bind_primitive(PrimitiveValue::Integer(self))?;
122 Ok(())
123 }
124}
125
126impl IntoDocument for String {
127 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
128 c.bind_primitive(PrimitiveValue::Text(Text::plaintext(self)))?;
129 Ok(())
130 }
131}
132
133impl IntoDocument for &str {
134 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
135 c.bind_primitive(PrimitiveValue::Text(Text::plaintext(self)))?;
136 Ok(())
137 }
138}
139
140impl IntoDocument for Text {
141 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
142 c.bind_primitive(PrimitiveValue::Text(self))?;
143 Ok(())
144 }
145}
146
147impl IntoDocument for PrimitiveValue {
148 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
149 c.bind_primitive(self)?;
150 Ok(())
151 }
152}
153
154impl IntoDocument for Identifier {
155 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
156 c.bind_primitive(PrimitiveValue::Text(Text::plaintext(self.into_string())))?;
157 Ok(())
158 }
159}
160
161impl<T: IntoDocument> IntoDocument for Vec<T> {
166 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
167 c.bind_empty_array()?;
168 for item in self {
169 let scope = c.begin_scope();
170 c.navigate(PathSegment::ArrayIndex(None))?;
171 item.write_to(c)?;
172 c.end_scope(scope)?;
173 }
174 Ok(())
175 }
176}
177
178impl<K, V> IntoDocument for Map<K, V>
179where
180 K: Into<ObjectKey>,
181 V: IntoDocument,
182{
183 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
184 c.bind_empty_map()?;
185 for (key, value) in self {
186 let scope = c.begin_scope();
187 c.navigate(PathSegment::Value(key.into()))?;
188 value.write_to(c)?;
189 c.end_scope(scope)?;
190 }
191 Ok(())
192 }
193}
194
195impl<T: IntoDocument> IntoDocument for Option<T> {
196 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
197 match self {
198 Some(value) => value.write_to(c),
199 None => {
200 c.bind_primitive(PrimitiveValue::Null)?;
201 Ok(())
202 }
203 }
204 }
205}
206
207macro_rules! impl_into_document_tuple {
212 ($n:expr, $($idx:tt: $var:ident),+) => {
213 impl<$($var: IntoDocument),+> IntoDocument for ($($var,)+) {
214 fn write_to(self, c: &mut DocumentConstructor) -> Result<(), WriteError> {
215 c.bind_empty_tuple()?;
216 $(
217 let scope = c.begin_scope();
218 c.navigate(PathSegment::TupleIndex($idx))?;
219 self.$idx.write_to(c)?;
220 c.end_scope(scope)?;
221 )+
222 Ok(())
223 }
224 }
225 };
226}
227
228impl_into_document_tuple!(1, 0: A);
229impl_into_document_tuple!(2, 0: A, 1: B);
230impl_into_document_tuple!(3, 0: A, 1: B, 2: C);
231impl_into_document_tuple!(4, 0: A, 1: B, 2: C, 3: D);
232impl_into_document_tuple!(5, 0: A, 1: B, 2: C, 3: D, 4: E);
233impl_into_document_tuple!(6, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
234impl_into_document_tuple!(7, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G);
235impl_into_document_tuple!(8, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H);
236impl_into_document_tuple!(9, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I);
237impl_into_document_tuple!(10, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J);
238impl_into_document_tuple!(11, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K);
239impl_into_document_tuple!(12, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L);
240impl_into_document_tuple!(13, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L, 12: M);
241impl_into_document_tuple!(14, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L, 12: M, 13: N);
242impl_into_document_tuple!(15, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L, 12: M, 13: N, 14: O);
243impl_into_document_tuple!(16, 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L, 12: M, 13: N, 14: O, 15: P);
244
245impl DocumentConstructor {
250 pub fn record<F, T>(&mut self, f: F) -> Result<T, WriteError>
262 where
263 F: FnOnce(&mut RecordWriter<'_>) -> Result<T, WriteError>,
264 {
265 self.bind_empty_map()?;
266 let mut writer = RecordWriter::new(self);
267 f(&mut writer)
268 }
269
270 pub fn tuple<F, T>(&mut self, f: F) -> Result<T, WriteError>
283 where
284 F: FnOnce(&mut TupleWriter<'_>) -> Result<T, WriteError>,
285 {
286 self.bind_empty_tuple()?;
287 let mut writer = TupleWriter::new(self);
288 f(&mut writer)
289 }
290
291 pub fn set_extension<T: IntoDocument>(
299 &mut self,
300 name: &str,
301 value: T,
302 ) -> Result<(), WriteError> {
303 let ident: Identifier = name
304 .parse()
305 .map_err(|_| WriteError::InvalidIdentifier(name.into()))?;
306 let scope = self.begin_scope();
307 self.navigate(PathSegment::Extension(ident))?;
308 value.write_to(self)?;
309 self.end_scope(scope)?;
310 Ok(())
311 }
312
313 pub fn set_extension_optional<T: IntoDocument>(
322 &mut self,
323 name: &str,
324 value: Option<T>,
325 ) -> Result<(), WriteError> {
326 if let Some(v) = value {
327 self.set_extension(name, v)?;
328 }
329 Ok(())
330 }
331
332 pub fn set_variant(&mut self, variant: &str) -> Result<(), WriteError> {
345 self.set_extension("variant", variant)
346 }
347
348 pub fn write<T: IntoDocument>(&mut self, value: T) -> Result<(), WriteError> {
356 value.write_to(self)
357 }
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363
364 #[test]
365 fn test_primitive_bool() {
366 let mut c = DocumentConstructor::new();
367 true.write_to(&mut c).unwrap();
368 let doc = c.finish();
369 assert_eq!(
370 doc.root().content,
371 NodeValue::Primitive(PrimitiveValue::Bool(true))
372 );
373 }
374
375 #[test]
376 fn test_primitive_string() {
377 let mut c = DocumentConstructor::new();
378 "hello".write_to(&mut c).unwrap();
379 let doc = c.finish();
380 assert_eq!(
381 doc.root().content,
382 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("hello")))
383 );
384 }
385
386 #[test]
387 fn test_vec() {
388 let mut c = DocumentConstructor::new();
389 vec![1i32, 2, 3].write_to(&mut c).unwrap();
390 let doc = c.finish();
391 let arr = doc.root().as_array().unwrap();
392 assert_eq!(arr.len(), 3);
393 }
394
395 #[test]
396 fn test_tuple() {
397 let mut c = DocumentConstructor::new();
398 (1i32, "two", true).write_to(&mut c).unwrap();
399 let doc = c.finish();
400 let tuple = doc.root().as_tuple().unwrap();
401 assert_eq!(tuple.len(), 3);
402 }
403
404 #[test]
405 fn test_record() {
406 let mut c = DocumentConstructor::new();
407 c.record(|rec| {
408 rec.field("name", "Alice")?;
409 rec.field("age", 30i32)?;
410 Ok(())
411 })
412 .unwrap();
413 let doc = c.finish();
414 let map = doc.root().as_map().unwrap();
415 assert_eq!(map.len(), 2);
416 }
417
418 #[test]
419 fn test_set_extension() {
420 let mut c = DocumentConstructor::new();
421 c.record(|rec| {
422 rec.field("type", "string")?;
423 Ok(())
424 })
425 .unwrap();
426 c.set_extension("optional", true).unwrap();
427 let doc = c.finish();
428
429 let root = doc.root();
430 assert!(
431 root.extensions
432 .contains_key(&"optional".parse::<Identifier>().unwrap())
433 );
434 }
435
436 #[test]
437 fn test_set_variant() {
438 let mut c = DocumentConstructor::new();
439 c.set_variant("foo").unwrap();
440 c.record(|rec| {
441 rec.field("value", 42i32)?;
442 Ok(())
443 })
444 .unwrap();
445 let doc = c.finish();
446
447 let root = doc.root();
448 assert!(
449 root.extensions
450 .contains_key(&"variant".parse::<Identifier>().unwrap())
451 );
452 }
453
454 #[test]
455 fn test_nested_record() {
456 let mut c = DocumentConstructor::new();
457 c.record(|rec| {
458 rec.field("name", "Alice")?;
459 rec.field_with("address", |c| {
460 c.record(|rec| {
461 rec.field("city", "Tokyo")?;
462 rec.field("zip", "100-0001")?;
463 Ok(())
464 })
465 })?;
466 Ok(())
467 })
468 .unwrap();
469 let doc = c.finish();
470 let map = doc.root().as_map().unwrap();
471 assert_eq!(map.len(), 2);
472 }
473}