From 1df2e6f998111b72d764a5c119dd704a8049f6e8 Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Sun, 4 Feb 2024 11:04:25 +0100 Subject: [PATCH] Move yaml_emitter_dump to Document --- src/document.rs | 193 +++++++++++++++++++++++++++++++++++- src/dumper.rs | 255 ------------------------------------------------ src/emitter.rs | 52 ++++++++++ src/lib.rs | 2 - 4 files changed, 242 insertions(+), 260 deletions(-) delete mode 100644 src/dumper.rs diff --git a/src/document.rs b/src/document.rs index 21ff056..787cef1 100644 --- a/src/document.rs +++ b/src/document.rs @@ -1,7 +1,7 @@ use crate::{ - AliasData, ComposerError, Event, EventData, MappingStyle, Mark, Parser, ScalarStyle, - SequenceStyle, TagDirective, VersionDirective, DEFAULT_MAPPING_TAG, DEFAULT_SCALAR_TAG, - DEFAULT_SEQUENCE_TAG, + AliasData, Anchors, ComposerError, Emitter, EmitterError, Event, EventData, MappingStyle, Mark, + Parser, ScalarStyle, SequenceStyle, TagDirective, VersionDirective, DEFAULT_MAPPING_TAG, + DEFAULT_SCALAR_TAG, DEFAULT_SEQUENCE_TAG, }; /// The document structure. @@ -606,4 +606,191 @@ impl Document { _ = ctx.pop(); Ok(()) } + + /// Emit a YAML document. + /// + /// The document object may be generated using the + /// [`yaml_parser_load()`](crate::yaml_parser_load) function or the + /// [`Document::new()`] function. + pub fn dump(mut self, emitter: &mut Emitter) -> Result<(), EmitterError> { + if !emitter.opened { + if let Err(err) = emitter.open() { + emitter.reset_anchors(); + return Err(err); + } + } + if self.nodes.is_empty() { + // TODO: Do we really want to close the emitter just because the + // document contains no nodes? Isn't it OK to emit multiple documents in + // the same stream? + emitter.close()?; + } else { + assert!(emitter.opened); + emitter.anchors = vec![Anchors::default(); self.nodes.len()]; + let event = Event { + data: EventData::DocumentStart { + version_directive: self.version_directive, + tag_directives: core::mem::take(&mut self.tag_directives), + implicit: self.start_implicit, + }, + ..Default::default() + }; + emitter.emit(event)?; + self.anchor_node(emitter, 1); + self.dump_node(emitter, 1)?; + let event = Event { + data: EventData::DocumentEnd { + implicit: self.end_implicit, + }, + ..Default::default() + }; + emitter.emit(event)?; + } + + emitter.reset_anchors(); + Ok(()) + } + + fn anchor_node(&self, emitter: &mut Emitter, index: i32) { + let node = &self.nodes[index as usize - 1]; + emitter.anchors[index as usize - 1].references += 1; + if emitter.anchors[index as usize - 1].references == 1 { + match &node.data { + NodeData::Sequence { items, .. } => { + for item in items { + emitter.anchor_node_sub(*item); + } + } + NodeData::Mapping { pairs, .. } => { + for pair in pairs { + emitter.anchor_node_sub(pair.key); + emitter.anchor_node_sub(pair.value); + } + } + _ => {} + } + } else if emitter.anchors[index as usize - 1].references == 2 { + emitter.last_anchor_id += 1; + emitter.anchors[index as usize - 1].anchor = emitter.last_anchor_id; + } + } + + fn dump_node(&mut self, emitter: &mut Emitter, index: i32) -> Result<(), EmitterError> { + let node = &mut self.nodes[index as usize - 1]; + let anchor_id: i32 = emitter.anchors[index as usize - 1].anchor; + let mut anchor: Option = None; + if anchor_id != 0 { + anchor = Some(Emitter::generate_anchor(anchor_id)); + } + if emitter.anchors[index as usize - 1].serialized { + return Self::dump_alias(emitter, anchor.unwrap()); + } + emitter.anchors[index as usize - 1].serialized = true; + + let node = core::mem::take(node); + match node.data { + NodeData::Scalar { .. } => Self::dump_scalar(emitter, node, anchor), + NodeData::Sequence { .. } => self.dump_sequence(emitter, node, anchor), + NodeData::Mapping { .. } => self.dump_mapping(emitter, node, anchor), + _ => unreachable!("document node is neither a scalar, sequence, or a mapping"), + } + } + + fn dump_alias(emitter: &mut Emitter, anchor: String) -> Result<(), EmitterError> { + let event = Event { + data: EventData::Alias { anchor }, + ..Default::default() + }; + emitter.emit(event) + } + + fn dump_scalar( + emitter: &mut Emitter, + node: Node, + anchor: Option, + ) -> Result<(), EmitterError> { + let plain_implicit = node.tag.as_deref() == Some(DEFAULT_SCALAR_TAG); + let quoted_implicit = node.tag.as_deref() == Some(DEFAULT_SCALAR_TAG); // TODO: Why compare twice?! (even the C code does this) + + let NodeData::Scalar { value, style } = node.data else { + unreachable!() + }; + let event = Event { + data: EventData::Scalar { + anchor, + tag: node.tag, + value, + plain_implicit, + quoted_implicit, + style, + }, + ..Default::default() + }; + emitter.emit(event) + } + + fn dump_sequence( + &mut self, + emitter: &mut Emitter, + node: Node, + anchor: Option, + ) -> Result<(), EmitterError> { + let implicit = node.tag.as_deref() == Some(DEFAULT_SEQUENCE_TAG); + + let NodeData::Sequence { items, style } = node.data else { + unreachable!() + }; + let event = Event { + data: EventData::SequenceStart { + anchor, + tag: node.tag, + implicit, + style, + }, + ..Default::default() + }; + + emitter.emit(event)?; + for item in items { + self.dump_node(emitter, item)?; + } + let event = Event { + data: EventData::SequenceEnd, + ..Default::default() + }; + emitter.emit(event) + } + + fn dump_mapping( + &mut self, + emitter: &mut Emitter, + node: Node, + anchor: Option, + ) -> Result<(), EmitterError> { + let implicit = node.tag.as_deref() == Some(DEFAULT_MAPPING_TAG); + + let NodeData::Mapping { pairs, style } = node.data else { + unreachable!() + }; + let event = Event { + data: EventData::MappingStart { + anchor, + tag: node.tag, + implicit, + style, + }, + ..Default::default() + }; + + emitter.emit(event)?; + for pair in pairs { + self.dump_node(emitter, pair.key)?; + self.dump_node(emitter, pair.value)?; + } + let event = Event { + data: EventData::MappingEnd, + ..Default::default() + }; + emitter.emit(event) + } } diff --git a/src/dumper.rs b/src/dumper.rs deleted file mode 100644 index b6359d9..0000000 --- a/src/dumper.rs +++ /dev/null @@ -1,255 +0,0 @@ -use std::mem::take; - -use alloc::string::String; -use alloc::vec; - -use crate::{Anchors, Document, Emitter, Event, EventData, Node, NodeData}; -use crate::{ - EmitterError, Encoding, DEFAULT_MAPPING_TAG, DEFAULT_SCALAR_TAG, DEFAULT_SEQUENCE_TAG, -}; - -/// Start a YAML stream. -/// -/// This function should be used before -/// [`yaml_emitter_dump()`](crate::yaml_emitter_dump) is called. -pub fn yaml_emitter_open(emitter: &mut Emitter) -> Result<(), EmitterError> { - assert!(!emitter.opened); - let event = Event { - data: EventData::StreamStart { - encoding: Encoding::Any, - }, - ..Default::default() - }; - emitter.emit(event)?; - emitter.opened = true; - Ok(()) -} - -/// Finish a YAML stream. -/// -/// This function should be used after -/// [`yaml_emitter_dump()`](crate::yaml_emitter_dump) is called. -pub fn yaml_emitter_close(emitter: &mut Emitter) -> Result<(), EmitterError> { - assert!(emitter.opened); - if emitter.closed { - return Ok(()); - } - let event = Event { - data: EventData::StreamEnd, - ..Default::default() - }; - emitter.emit(event)?; - emitter.closed = true; - Ok(()) -} - -/// Emit a YAML document. -/// -/// The document object may be generated using the -/// [`yaml_parser_load()`](crate::yaml_parser_load) function or the -/// [`Document::new()`] function. -pub fn yaml_emitter_dump( - emitter: &mut Emitter, - mut document: Document, -) -> Result<(), EmitterError> { - if !emitter.opened { - if let Err(err) = yaml_emitter_open(emitter) { - yaml_emitter_reset_anchors(emitter); - return Err(err); - } - } - if document.nodes.is_empty() { - // TODO: Do we really want to close the emitter just because the - // document contains no nodes? Isn't it OK to emit multiple documents in - // the same stream? - yaml_emitter_close(emitter)?; - } else { - assert!(emitter.opened); - emitter.anchors = vec![Anchors::default(); document.nodes.len()]; - let event = Event { - data: EventData::DocumentStart { - version_directive: document.version_directive, - tag_directives: take(&mut document.tag_directives), - implicit: document.start_implicit, - }, - ..Default::default() - }; - emitter.emit(event)?; - yaml_emitter_anchor_node(emitter, &document, 1); - yaml_emitter_dump_node(emitter, &mut document, 1)?; - let event = Event { - data: EventData::DocumentEnd { - implicit: document.end_implicit, - }, - ..Default::default() - }; - emitter.emit(event)?; - } - - yaml_emitter_reset_anchors(emitter); - Ok(()) -} - -fn yaml_emitter_reset_anchors(emitter: &mut Emitter) { - emitter.anchors.clear(); - emitter.last_anchor_id = 0; -} - -fn yaml_emitter_anchor_node_sub(emitter: &mut Emitter, index: i32) { - emitter.anchors[index as usize - 1].references += 1; - if emitter.anchors[index as usize - 1].references == 2 { - emitter.last_anchor_id += 1; - emitter.anchors[index as usize - 1].anchor = emitter.last_anchor_id; - } -} - -fn yaml_emitter_anchor_node(emitter: &mut Emitter, document: &Document, index: i32) { - let node = &document.nodes[index as usize - 1]; - emitter.anchors[index as usize - 1].references += 1; - if emitter.anchors[index as usize - 1].references == 1 { - match &node.data { - NodeData::Sequence { items, .. } => { - for item in items { - yaml_emitter_anchor_node_sub(emitter, *item); - } - } - NodeData::Mapping { pairs, .. } => { - for pair in pairs { - yaml_emitter_anchor_node_sub(emitter, pair.key); - yaml_emitter_anchor_node_sub(emitter, pair.value); - } - } - _ => {} - } - } else if emitter.anchors[index as usize - 1].references == 2 { - emitter.last_anchor_id += 1; - emitter.anchors[index as usize - 1].anchor = emitter.last_anchor_id; - } -} - -fn yaml_emitter_generate_anchor(_emitter: &mut Emitter, anchor_id: i32) -> String { - alloc::format!("id{anchor_id:03}") -} - -fn yaml_emitter_dump_node( - emitter: &mut Emitter, - document: &mut Document, - index: i32, -) -> Result<(), EmitterError> { - let node = &mut document.nodes[index as usize - 1]; - let anchor_id: i32 = emitter.anchors[index as usize - 1].anchor; - let mut anchor: Option = None; - if anchor_id != 0 { - anchor = Some(yaml_emitter_generate_anchor(emitter, anchor_id)); - } - if emitter.anchors[index as usize - 1].serialized { - return yaml_emitter_dump_alias(emitter, anchor.unwrap()); - } - emitter.anchors[index as usize - 1].serialized = true; - - let node = take(node); - match node.data { - NodeData::Scalar { .. } => yaml_emitter_dump_scalar(emitter, node, anchor), - NodeData::Sequence { .. } => yaml_emitter_dump_sequence(emitter, document, node, anchor), - NodeData::Mapping { .. } => yaml_emitter_dump_mapping(emitter, document, node, anchor), - _ => unreachable!("document node is neither a scalar, sequence, or a mapping"), - } -} - -fn yaml_emitter_dump_alias(emitter: &mut Emitter, anchor: String) -> Result<(), EmitterError> { - let event = Event { - data: EventData::Alias { anchor }, - ..Default::default() - }; - emitter.emit(event) -} - -fn yaml_emitter_dump_scalar( - emitter: &mut Emitter, - node: Node, - anchor: Option, -) -> Result<(), EmitterError> { - let plain_implicit = node.tag.as_deref() == Some(DEFAULT_SCALAR_TAG); - let quoted_implicit = node.tag.as_deref() == Some(DEFAULT_SCALAR_TAG); // TODO: Why compare twice?! (even the C code does this) - - let NodeData::Scalar { value, style } = node.data else { - unreachable!() - }; - let event = Event { - data: EventData::Scalar { - anchor, - tag: node.tag, - value, - plain_implicit, - quoted_implicit, - style, - }, - ..Default::default() - }; - emitter.emit(event) -} - -fn yaml_emitter_dump_sequence( - emitter: &mut Emitter, - document: &mut Document, - node: Node, - anchor: Option, -) -> Result<(), EmitterError> { - let implicit = node.tag.as_deref() == Some(DEFAULT_SEQUENCE_TAG); - - let NodeData::Sequence { items, style } = node.data else { - unreachable!() - }; - let event = Event { - data: EventData::SequenceStart { - anchor, - tag: node.tag, - implicit, - style, - }, - ..Default::default() - }; - - emitter.emit(event)?; - for item in items { - yaml_emitter_dump_node(emitter, document, item)?; - } - let event = Event { - data: EventData::SequenceEnd, - ..Default::default() - }; - emitter.emit(event) -} - -fn yaml_emitter_dump_mapping( - emitter: &mut Emitter, - document: &mut Document, - node: Node, - anchor: Option, -) -> Result<(), EmitterError> { - let implicit = node.tag.as_deref() == Some(DEFAULT_MAPPING_TAG); - - let NodeData::Mapping { pairs, style } = node.data else { - unreachable!() - }; - let event = Event { - data: EventData::MappingStart { - anchor, - tag: node.tag, - implicit, - style, - }, - ..Default::default() - }; - - emitter.emit(event)?; - for pair in pairs { - yaml_emitter_dump_node(emitter, document, pair.key)?; - yaml_emitter_dump_node(emitter, document, pair.value)?; - } - let event = Event { - data: EventData::MappingEnd, - ..Default::default() - }; - emitter.emit(event) -} diff --git a/src/emitter.rs b/src/emitter.rs index 868a387..6518382 100644 --- a/src/emitter.rs +++ b/src/emitter.rs @@ -278,6 +278,41 @@ impl<'w> Emitter<'w> { *self = Self::new(); } + /// Start a YAML stream. + /// + /// This function should be used before + /// [`yaml_emitter_dump()`](crate::yaml_emitter_dump) is called. + pub fn open(&mut self) -> Result<(), EmitterError> { + assert!(!self.opened); + let event = Event { + data: EventData::StreamStart { + encoding: Encoding::Any, + }, + ..Default::default() + }; + self.emit(event)?; + self.opened = true; + Ok(()) + } + + /// Finish a YAML stream. + /// + /// This function should be used after + /// [`yaml_emitter_dump()`](crate::yaml_emitter_dump) is called. + pub fn close(&mut self) -> Result<(), EmitterError> { + assert!(self.opened); + if self.closed { + return Ok(()); + } + let event = Event { + data: EventData::StreamEnd, + ..Default::default() + }; + self.emit(event)?; + self.closed = true; + Ok(()) + } + /// Set a string output. /// /// The emitter will write the output characters to the `output` buffer. @@ -1758,4 +1793,21 @@ impl<'w> Emitter<'w> { } Ok(()) } + + pub(crate) fn reset_anchors(&mut self) { + self.anchors.clear(); + self.last_anchor_id = 0; + } + + pub(crate) fn anchor_node_sub(&mut self, index: i32) { + self.anchors[index as usize - 1].references += 1; + if self.anchors[index as usize - 1].references == 2 { + self.last_anchor_id += 1; + self.anchors[index as usize - 1].anchor = self.last_anchor_id; + } + } + + pub(crate) fn generate_anchor(anchor_id: i32) -> String { + alloc::format!("id{anchor_id:03}") + } } diff --git a/src/lib.rs b/src/lib.rs index 4464352..8b92d42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,6 @@ extern crate alloc; mod macros; mod document; -mod dumper; mod emitter; mod error; mod event; @@ -39,7 +38,6 @@ mod token; mod writer; pub use crate::document::*; -pub use crate::dumper::{yaml_emitter_close, yaml_emitter_dump, yaml_emitter_open}; pub use crate::emitter::*; pub use crate::error::*; pub use crate::event::*;