use crate::de::{Event, Progress}; use crate::error::{self, Error, ErrorImpl, Result}; use crate::libyaml::error::Mark; use crate::libyaml::parser::{Event as YamlEvent, Parser}; use std::borrow::Cow; use std::collections::BTreeMap; use std::sync::Arc; pub(crate) struct Loader<'input> { parser: Option>, document_count: usize, } pub(crate) struct Document<'input> { pub events: Vec<(Event<'input>, Mark)>, pub error: Option>, /// Map from alias id to index in events. pub aliases: BTreeMap, } impl<'input> Loader<'input> { pub fn new(progress: Progress<'input>) -> Result { let input = match progress { Progress::Str(s) => Cow::Borrowed(s.as_bytes()), Progress::Slice(bytes) => Cow::Borrowed(bytes), Progress::Read(mut rdr) => { let mut buffer = Vec::new(); if let Err(io_error) = rdr.read_to_end(&mut buffer) { return Err(error::new(ErrorImpl::Io(io_error))); } Cow::Owned(buffer) } Progress::Iterable(_) | Progress::Document(_) => unreachable!(), Progress::Fail(err) => return Err(error::shared(err)), }; Ok(Loader { parser: Some(Parser::new(input)), document_count: 0, }) } pub fn next_document(&mut self) -> Option> { let parser = match &mut self.parser { Some(parser) => parser, None => return None, }; let first = self.document_count == 0; self.document_count += 1; let mut anchors = BTreeMap::new(); let mut document = Document { events: Vec::new(), error: None, aliases: BTreeMap::new(), }; loop { let (event, mark) = match parser.next() { Ok((event, mark)) => (event, mark), Err(err) => { document.error = Some(Error::from(err).shared()); return Some(document); } }; let event = match event { YamlEvent::StreamStart => continue, YamlEvent::StreamEnd => { self.parser = None; return if first { if document.events.is_empty() { document.events.push((Event::Void, mark)); } Some(document) } else { None }; } YamlEvent::DocumentStart => continue, YamlEvent::DocumentEnd => return Some(document), YamlEvent::Alias(alias) => match anchors.get(&alias) { Some(id) => Event::Alias(*id), None => { document.error = Some(error::new(ErrorImpl::UnknownAnchor(mark)).shared()); return Some(document); } }, YamlEvent::Scalar(mut scalar) => { if let Some(anchor) = scalar.anchor.take() { let id = anchors.len(); anchors.insert(anchor, id); document.aliases.insert(id, document.events.len()); } Event::Scalar(scalar) } YamlEvent::SequenceStart(mut sequence_start) => { if let Some(anchor) = sequence_start.anchor.take() { let id = anchors.len(); anchors.insert(anchor, id); document.aliases.insert(id, document.events.len()); } Event::SequenceStart(sequence_start) } YamlEvent::SequenceEnd => Event::SequenceEnd, YamlEvent::MappingStart(mut mapping_start) => { if let Some(anchor) = mapping_start.anchor.take() { let id = anchors.len(); anchors.insert(anchor, id); document.aliases.insert(id, document.events.len()); } Event::MappingStart(mapping_start) } YamlEvent::MappingEnd => Event::MappingEnd, }; document.events.push((event, mark)); } } }