| 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<Parser<'input>>, |
| document_count: usize, |
| } |
| |
| pub(crate) struct Document<'input> { |
| pub events: Vec<(Event<'input>, Mark)>, |
| pub error: Option<Arc<ErrorImpl>>, |
| /// Map from alias id to index in events. |
| pub aliases: BTreeMap<usize, usize>, |
| } |
| |
| impl<'input> Loader<'input> { |
| pub fn new(progress: Progress<'input>) -> Result<Self> { |
| 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<Document<'input>> { |
| 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)); |
| } |
| } |
| } |