eure_document/write/
record.rs1extern crate alloc;
4
5use alloc::string::ToString;
6
7use crate::document::constructor::DocumentConstructor;
8use crate::path::PathSegment;
9use crate::value::ObjectKey;
10
11use super::{IntoDocument, WriteError};
12
13pub struct RecordWriter<'a> {
27 constructor: &'a mut DocumentConstructor,
28}
29
30impl<'a> RecordWriter<'a> {
31 pub(crate) fn new(constructor: &'a mut DocumentConstructor) -> Self {
33 Self { constructor }
34 }
35
36 pub fn field<T: IntoDocument>(&mut self, name: &str, value: T) -> Result<(), WriteError> {
44 let scope = self.constructor.begin_scope();
45 self.constructor
46 .navigate(PathSegment::Value(ObjectKey::String(name.to_string())))?;
47 value.write_to(self.constructor)?;
48 self.constructor.end_scope(scope)?;
49 Ok(())
50 }
51
52 pub fn field_optional<T: IntoDocument>(
61 &mut self,
62 name: &str,
63 value: Option<T>,
64 ) -> Result<(), WriteError> {
65 if let Some(v) = value {
66 self.field(name, v)?;
67 }
68 Ok(())
69 }
70
71 pub fn field_with<F, T>(&mut self, name: &str, f: F) -> Result<T, WriteError>
86 where
87 F: FnOnce(&mut DocumentConstructor) -> Result<T, WriteError>,
88 {
89 let scope = self.constructor.begin_scope();
90 self.constructor
91 .navigate(PathSegment::Value(ObjectKey::String(name.to_string())))?;
92 let result = f(self.constructor)?;
93 self.constructor.end_scope(scope)?;
94 Ok(result)
95 }
96
97 pub fn field_with_optional<T, F, R>(
108 &mut self,
109 name: &str,
110 value: Option<T>,
111 f: F,
112 ) -> Result<Option<R>, WriteError>
113 where
114 F: FnOnce(&mut DocumentConstructor, T) -> Result<R, WriteError>,
115 {
116 if let Some(v) = value {
117 let result = self.field_with(name, |c| f(c, v))?;
118 Ok(Some(result))
119 } else {
120 Ok(None)
121 }
122 }
123
124 pub fn constructor(&mut self) -> &mut DocumentConstructor {
128 self.constructor
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use crate::document::node::NodeValue;
136 use crate::text::Text;
137 use crate::value::PrimitiveValue;
138
139 #[test]
140 fn test_field() {
141 let mut c = DocumentConstructor::new();
142 c.record(|rec| {
143 rec.field("name", "Alice")?;
144 Ok(())
145 })
146 .unwrap();
147 let doc = c.finish();
148 let map = doc.root().as_map().unwrap();
149 let name_id = map.get(&ObjectKey::String("name".to_string())).unwrap();
150 let node = doc.node(*name_id);
151 assert_eq!(
152 node.content,
153 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("Alice")))
154 );
155 }
156
157 #[test]
158 fn test_field_optional_some() {
159 let mut c = DocumentConstructor::new();
160 c.record(|rec| {
161 rec.field_optional("age", Some(30i32))?;
162 Ok(())
163 })
164 .unwrap();
165 let doc = c.finish();
166 let map = doc.root().as_map().unwrap();
167 assert!(map.get(&ObjectKey::String("age".to_string())).is_some());
168 }
169
170 #[test]
171 fn test_field_optional_none() {
172 let mut c = DocumentConstructor::new();
173 c.record(|rec| {
174 rec.field_optional::<i32>("age", None)?;
175 Ok(())
176 })
177 .unwrap();
178 let doc = c.finish();
179 let map = doc.root().as_map().unwrap();
180 assert!(map.get(&ObjectKey::String("age".to_string())).is_none());
181 }
182
183 #[test]
184 fn test_field_with() {
185 let mut c = DocumentConstructor::new();
186 c.record(|rec| {
187 rec.field_with("nested", |c| {
188 c.record(|rec| {
189 rec.field("inner", "value")?;
190 Ok(())
191 })
192 })?;
193 Ok(())
194 })
195 .unwrap();
196 let doc = c.finish();
197 let map = doc.root().as_map().unwrap();
198 let nested_id = map.get(&ObjectKey::String("nested".to_string())).unwrap();
199 let nested = doc.node(*nested_id).as_map().unwrap();
200 assert!(
201 nested
202 .get(&ObjectKey::String("inner".to_string()))
203 .is_some()
204 );
205 }
206
207 #[test]
208 fn test_multiple_fields() {
209 let mut c = DocumentConstructor::new();
210 c.record(|rec| {
211 rec.field("name", "Bob")?;
212 rec.field("age", 25i32)?;
213 rec.field("active", true)?;
214 Ok(())
215 })
216 .unwrap();
217 let doc = c.finish();
218 let map = doc.root().as_map().unwrap();
219 assert_eq!(map.len(), 3);
220 }
221}