extern crate alloc;
use crate::document::constructor::DocumentConstructor;
use crate::path::PathSegment;
use super::{IntoEure, WriteError};
pub struct TupleWriter<'a> {
constructor: &'a mut DocumentConstructor,
position: u8,
}
impl<'a> TupleWriter<'a> {
pub(crate) fn new(constructor: &'a mut DocumentConstructor) -> Self {
Self {
constructor,
position: 0,
}
}
pub fn next<T: IntoEure>(&mut self, value: T) -> Result<(), T::Error> {
let scope = self.constructor.begin_scope();
self.constructor
.navigate(PathSegment::TupleIndex(self.position))
.map_err(WriteError::from)?;
T::write(value, self.constructor)?;
self.constructor
.end_scope(scope)
.map_err(WriteError::from)?;
self.position += 1;
Ok(())
}
pub fn next_via<M, T>(&mut self, value: T) -> Result<(), M::Error>
where
M: IntoEure<T>,
{
let scope = self.constructor.begin_scope();
self.constructor
.navigate(PathSegment::TupleIndex(self.position))
.map_err(WriteError::from)?;
M::write(value, self.constructor)?;
self.constructor
.end_scope(scope)
.map_err(WriteError::from)?;
self.position += 1;
Ok(())
}
pub fn next_with<F, R>(&mut self, f: F) -> Result<R, WriteError>
where
F: FnOnce(&mut DocumentConstructor) -> Result<R, WriteError>,
{
let scope = self.constructor.begin_scope();
self.constructor
.navigate(PathSegment::TupleIndex(self.position))
.map_err(WriteError::from)?;
let result = f(self.constructor)?;
self.constructor
.end_scope(scope)
.map_err(WriteError::from)?;
self.position += 1;
Ok(result)
}
pub fn position(&self) -> u8 {
self.position
}
pub fn constructor(&mut self) -> &mut DocumentConstructor {
self.constructor
}
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
use super::*;
use crate::document::node::NodeValue;
use crate::text::Text;
use crate::value::{ObjectKey, PrimitiveValue};
#[test]
fn test_next_sequential() {
let mut c = DocumentConstructor::new();
c.tuple(|t| {
t.next(1i32)?;
t.next("two")?;
t.next(true)
})
.unwrap();
let doc = c.finish();
let tuple = doc.root().as_tuple().unwrap();
assert_eq!(tuple.len(), 3);
}
#[test]
fn test_next_with_nested() {
let mut c = DocumentConstructor::new();
c.tuple(|t| {
t.next("first")?;
t.next_with(|c| {
c.record(|rec| {
rec.field("inner", "value")?;
Ok::<(), WriteError>(())
})
})
})
.unwrap();
let doc = c.finish();
let tuple = doc.root().as_tuple().unwrap();
assert_eq!(tuple.len(), 2);
let nested_id = tuple.get(1).unwrap();
let nested = doc.node(nested_id).as_map().unwrap();
assert!(
nested
.get(&ObjectKey::String("inner".to_string()))
.is_some()
);
}
#[test]
fn test_position_tracking() {
let mut c = DocumentConstructor::new();
c.tuple(|t| {
assert_eq!(t.position(), 0);
t.next(1i32)?;
assert_eq!(t.position(), 1);
t.next(2i32)?;
assert_eq!(t.position(), 2);
Ok::<(), WriteError>(())
})
.unwrap();
}
#[test]
fn test_empty_tuple() {
let mut c = DocumentConstructor::new();
c.tuple(|_t| Ok::<(), WriteError>(())).unwrap();
let doc = c.finish();
let tuple = doc.root().as_tuple().unwrap();
assert!(tuple.is_empty());
}
#[test]
fn test_values_written_correctly() {
let mut c = DocumentConstructor::new();
c.tuple(|t| {
t.next(42i32)?;
t.next("hello")?;
Ok::<(), WriteError>(())
})
.unwrap();
let doc = c.finish();
let tuple = doc.root().as_tuple().unwrap();
let first_id = tuple.get(0).unwrap();
assert_eq!(
doc.node(first_id).content,
NodeValue::Primitive(PrimitiveValue::Integer(42.into()))
);
let second_id = tuple.get(1).unwrap();
assert_eq!(
doc.node(second_id).content,
NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext("hello")))
);
}
}