eure_document/write/
tuple.rs1extern crate alloc;
4
5use crate::document::constructor::DocumentConstructor;
6use crate::path::PathSegment;
7
8use super::{IntoEure, WriteError};
9
10pub struct TupleWriter<'a> {
26 constructor: &'a mut DocumentConstructor,
27 position: u8,
28}
29
30impl<'a> TupleWriter<'a> {
31 pub(crate) fn new(constructor: &'a mut DocumentConstructor) -> Self {
33 Self {
34 constructor,
35 position: 0,
36 }
37 }
38
39 pub fn next<T: IntoEure>(&mut self, value: T) -> Result<(), T::Error> {
48 let scope = self.constructor.begin_scope();
49 self.constructor
50 .navigate(PathSegment::TupleIndex(self.position))
51 .map_err(WriteError::from)?;
52 T::write(value, self.constructor)?;
53 self.constructor
54 .end_scope(scope)
55 .map_err(WriteError::from)?;
56 self.position += 1;
57 Ok(())
58 }
59
60 pub fn next_via<M, T>(&mut self, value: T) -> Result<(), M::Error>
72 where
73 M: IntoEure<T>,
74 {
75 let scope = self.constructor.begin_scope();
76 self.constructor
77 .navigate(PathSegment::TupleIndex(self.position))
78 .map_err(WriteError::from)?;
79 M::write(value, self.constructor)?;
80 self.constructor
81 .end_scope(scope)
82 .map_err(WriteError::from)?;
83 self.position += 1;
84 Ok(())
85 }
86
87 pub fn next_with<F, R>(&mut self, f: F) -> Result<R, WriteError>
102 where
103 F: FnOnce(&mut DocumentConstructor) -> Result<R, WriteError>,
104 {
105 let scope = self.constructor.begin_scope();
106 self.constructor
107 .navigate(PathSegment::TupleIndex(self.position))
108 .map_err(WriteError::from)?;
109 let result = f(self.constructor)?;
110 self.constructor
111 .end_scope(scope)
112 .map_err(WriteError::from)?;
113 self.position += 1;
114 Ok(result)
115 }
116
117 pub fn position(&self) -> u8 {
119 self.position
120 }
121
122 pub fn constructor(&mut self) -> &mut DocumentConstructor {
126 self.constructor
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use alloc::string::ToString;
133
134 use super::*;
135 use crate::document::node::NodeValue;
136 use crate::text::Text;
137 use crate::value::{ObjectKey, PrimitiveValue};
138
139 #[test]
140 fn test_next_sequential() {
141 let mut c = DocumentConstructor::new();
142 c.tuple(|t| {
143 t.next(1i32)?;
144 t.next("two")?;
145 t.next(true)
146 })
147 .unwrap();
148 let doc = c.finish();
149 let tuple = doc.root().as_tuple().unwrap();
150 assert_eq!(tuple.len(), 3);
151 }
152
153 #[test]
154 fn test_next_with_nested() {
155 let mut c = DocumentConstructor::new();
156 c.tuple(|t| {
157 t.next("first")?;
158 t.next_with(|c| {
159 c.record(|rec| {
160 rec.field("inner", "value")?;
161 Ok::<(), WriteError>(())
162 })
163 })
164 })
165 .unwrap();
166 let doc = c.finish();
167 let tuple = doc.root().as_tuple().unwrap();
168 assert_eq!(tuple.len(), 2);
169
170 let nested_id = tuple.get(1).unwrap();
172 let nested = doc.node(nested_id).as_map().unwrap();
173 assert!(
174 nested
175 .get(&ObjectKey::String("inner".to_string()))
176 .is_some()
177 );
178 }
179
180 #[test]
181 fn test_position_tracking() {
182 let mut c = DocumentConstructor::new();
183 c.tuple(|t| {
184 assert_eq!(t.position(), 0);
185 t.next(1i32)?;
186 assert_eq!(t.position(), 1);
187 t.next(2i32)?;
188 assert_eq!(t.position(), 2);
189 Ok::<(), WriteError>(())
190 })
191 .unwrap();
192 }
193
194 #[test]
195 fn test_empty_tuple() {
196 let mut c = DocumentConstructor::new();
197 c.tuple(|_t| Ok::<(), WriteError>(())).unwrap();
198 let doc = c.finish();
199 let tuple = doc.root().as_tuple().unwrap();
200 assert!(tuple.is_empty());
201 }
202
203 #[test]
204 fn test_values_written_correctly() {
205 let mut c = DocumentConstructor::new();
206 c.tuple(|t| {
207 t.next(42i32)?;
208 t.next("hello")?;
209 Ok::<(), WriteError>(())
210 })
211 .unwrap();
212 let doc = c.finish();
213 let tuple = doc.root().as_tuple().unwrap();
214
215 let first_id = tuple.get(0).unwrap();
217 assert_eq!(
218 doc.node(first_id).content,
219 NodeValue::Primitive(PrimitiveValue::Integer(42.into()))
220 );
221
222 let second_id = tuple.get(1).unwrap();
224 assert_eq!(
225 doc.node(second_id).content,
226 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("hello")))
227 );
228 }
229}