extern crate alloc;
use alloc::format;
use crate::document::node::NodeTuple;
use crate::prelude_internal::*;
use super::{DocumentParser, FromEure, ParseContext, ParseError, ParseErrorKind};
#[derive(Debug)]
#[must_use]
pub struct TupleParser<'doc> {
doc: &'doc EureDocument,
node_id: NodeId,
tuple: &'doc NodeTuple,
position: usize,
}
impl<'doc> TupleParser<'doc> {
pub(crate) fn new(ctx: &ParseContext<'doc>) -> Result<Self, ParseError> {
Self::from_doc_and_node(ctx.doc(), ctx.node_id())
}
pub(crate) fn from_doc_and_node(
doc: &'doc EureDocument,
node_id: NodeId,
) -> Result<Self, ParseError> {
let node = doc.node(node_id);
match &node.content {
NodeValue::Tuple(tuple) => Ok(Self {
doc,
node_id,
tuple,
position: 0,
}),
NodeValue::Hole(_) => Err(ParseError {
node_id,
kind: ParseErrorKind::UnexpectedHole,
}),
_ => Err(ParseError {
node_id,
kind: ParseErrorKind::TypeMismatch {
expected: crate::value::ValueKind::Tuple,
actual: node.content.value_kind(),
},
}),
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
#[allow(clippy::should_implement_trait)]
pub fn next<T>(&mut self) -> Result<T, T::Error>
where
T: FromEure<'doc>,
T::Error: From<ParseError>,
{
self.next_with(T::parse)
}
pub fn next_with<T>(&mut self, mut parser: T) -> Result<T::Output, T::Error>
where
T: DocumentParser<'doc>,
T::Error: From<ParseError>,
{
let index = self.position;
let element_node_id = self.tuple.get(index).ok_or_else(|| ParseError {
node_id: self.node_id,
kind: ParseErrorKind::MissingField(format!("#{}", index)),
})?;
self.position += 1;
let ctx = ParseContext::new(self.doc, element_node_id);
parser.parse(&ctx)
}
pub fn next_via<M, T>(&mut self) -> Result<T, M::Error>
where
M: FromEure<'doc, T>,
M::Error: From<ParseError>,
{
self.next_with(M::parse)
}
pub fn get<T>(&self, index: usize) -> Result<T, T::Error>
where
T: FromEure<'doc>,
T::Error: From<ParseError>,
{
self.get_with(index, T::parse)
}
pub fn get_with<T>(&self, index: usize, mut parser: T) -> Result<T::Output, T::Error>
where
T: DocumentParser<'doc>,
T::Error: From<ParseError>,
{
let element_node_id = self.tuple.get(index).ok_or_else(|| ParseError {
node_id: self.node_id,
kind: ParseErrorKind::MissingField(format!("#{}", index)),
})?;
let ctx = ParseContext::new(self.doc, element_node_id);
parser.parse(&ctx)
}
pub fn get_via<M, T>(&self, index: usize) -> Result<T, M::Error>
where
M: FromEure<'doc, T>,
M::Error: From<ParseError>,
{
self.get_with(index, M::parse)
}
pub fn remaining(&self) -> usize {
self.tuple.len().saturating_sub(self.position)
}
pub fn finish(self) -> Result<(), ParseError> {
if self.position != self.tuple.len() {
return Err(ParseError {
node_id: self.node_id,
kind: ParseErrorKind::UnexpectedTupleLength {
expected: self.position,
actual: self.tuple.len(),
},
});
}
Ok(())
}
pub fn expect_len(&self, expected: usize) -> Result<(), ParseError> {
if self.tuple.len() != expected {
return Err(ParseError {
node_id: self.node_id,
kind: ParseErrorKind::UnexpectedTupleLength {
expected,
actual: self.tuple.len(),
},
});
}
Ok(())
}
pub fn len(&self) -> usize {
self.tuple.len()
}
pub fn is_empty(&self) -> bool {
self.tuple.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::document::constructor::DocumentConstructor;
use crate::path::PathSegment;
use crate::value::PrimitiveValue;
fn create_tuple_doc(elements: Vec<PrimitiveValue>) -> EureDocument {
let mut c = DocumentConstructor::new();
c.bind_empty_tuple().unwrap();
for (i, elem) in elements.into_iter().enumerate() {
let scope = c.begin_scope();
c.navigate(PathSegment::TupleIndex(i as u8)).unwrap();
c.bind_primitive(elem).unwrap();
c.end_scope(scope).unwrap();
}
c.finish()
}
#[test]
fn test_next_sequential() {
let doc = create_tuple_doc(vec![
PrimitiveValue::Integer(1.into()),
PrimitiveValue::Integer(2.into()),
PrimitiveValue::Integer(3.into()),
]);
let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
assert_eq!(tuple.next::<i32>().unwrap(), 1);
assert_eq!(tuple.next::<i32>().unwrap(), 2);
assert_eq!(tuple.next::<i32>().unwrap(), 3);
tuple.finish().unwrap();
}
#[test]
fn test_next_past_end() {
let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
tuple.next::<i32>().unwrap();
let result = tuple.next::<i32>();
assert!(matches!(
result.unwrap_err().kind,
ParseErrorKind::MissingField(_)
));
}
#[test]
fn test_get_random_access() {
let doc = create_tuple_doc(vec![
PrimitiveValue::Integer(10.into()),
PrimitiveValue::Integer(20.into()),
PrimitiveValue::Integer(30.into()),
]);
let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
assert_eq!(tuple.get::<i32>(2).unwrap(), 30);
assert_eq!(tuple.get::<i32>(0).unwrap(), 10);
assert_eq!(tuple.get::<i32>(1).unwrap(), 20);
}
#[test]
fn test_get_out_of_bounds() {
let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
let result = tuple.get::<i32>(5);
assert!(matches!(
result.unwrap_err().kind,
ParseErrorKind::MissingField(_)
));
}
#[test]
fn test_remaining() {
let doc = create_tuple_doc(vec![
PrimitiveValue::Integer(1.into()),
PrimitiveValue::Integer(2.into()),
PrimitiveValue::Integer(3.into()),
]);
let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
assert_eq!(tuple.remaining(), 3);
tuple.next::<i32>().unwrap();
assert_eq!(tuple.remaining(), 2);
tuple.next::<i32>().unwrap();
assert_eq!(tuple.remaining(), 1);
tuple.next::<i32>().unwrap();
assert_eq!(tuple.remaining(), 0);
}
#[test]
fn test_finish_with_remaining_elements() {
let doc = create_tuple_doc(vec![
PrimitiveValue::Integer(1.into()),
PrimitiveValue::Integer(2.into()),
]);
let mut tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
tuple.next::<i32>().unwrap();
let result = tuple.finish();
assert!(matches!(
result.unwrap_err().kind,
ParseErrorKind::UnexpectedTupleLength {
expected: 1,
actual: 2
}
));
}
#[test]
fn test_expect_len_correct() {
let doc = create_tuple_doc(vec![
PrimitiveValue::Integer(1.into()),
PrimitiveValue::Integer(2.into()),
]);
let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
tuple.expect_len(2).unwrap();
}
#[test]
fn test_expect_len_incorrect() {
let doc = create_tuple_doc(vec![PrimitiveValue::Integer(1.into())]);
let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
let result = tuple.expect_len(3);
assert!(matches!(
result.unwrap_err().kind,
ParseErrorKind::UnexpectedTupleLength {
expected: 3,
actual: 1
}
));
}
#[test]
fn test_empty_tuple() {
let doc = create_tuple_doc(vec![]);
let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
assert!(tuple.is_empty());
assert_eq!(tuple.len(), 0);
assert_eq!(tuple.remaining(), 0);
tuple.finish().unwrap();
}
#[test]
fn test_len_and_is_empty() {
let doc = create_tuple_doc(vec![
PrimitiveValue::Integer(1.into()),
PrimitiveValue::Integer(2.into()),
]);
let tuple = doc.parse_tuple(doc.get_root_id()).unwrap();
assert!(!tuple.is_empty());
assert_eq!(tuple.len(), 2);
}
#[test]
fn test_parse_non_tuple_fails() {
let mut c = DocumentConstructor::new();
c.bind_empty_array().unwrap();
let doc = c.finish();
let result = doc.parse_tuple(doc.get_root_id());
assert!(matches!(
result.unwrap_err().kind,
ParseErrorKind::TypeMismatch { .. }
));
}
}