blob: 7c7c7b655ca81fc6afe8bc970b81b1082acdeed5 [file] [log] [blame]
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));
}
}
}