use crate::yaml::{Document, Mapping, Scalar, Sequence, TaggedNode, YamlFile};
pub trait YamlVisitor {
fn visit_yaml(&mut self, yaml: &YamlFile) {
for doc in yaml.documents() {
self.visit_document(&doc);
}
}
fn visit_document(&mut self, document: &Document) {
self.walk_document(document);
}
fn walk_document(&mut self, document: &Document) {
if let Some(tagged) = document.as_tagged() {
self.visit_tagged_node(&tagged);
} else if let Some(mapping) = document.as_mapping() {
self.visit_mapping(&mapping);
} else if let Some(sequence) = document.as_sequence() {
self.visit_sequence(&sequence);
} else if let Some(scalar) = document.as_scalar() {
self.visit_scalar(&scalar);
}
}
fn visit_scalar(&mut self, _scalar: &Scalar) {}
fn visit_mapping(&mut self, mapping: &Mapping) {
self.walk_mapping(mapping);
}
fn visit_sequence(&mut self, sequence: &Sequence) {
self.walk_sequence(sequence);
}
fn visit_tagged_node(&mut self, tagged: &TaggedNode) {
self.walk_tagged_node(tagged);
}
fn walk_tagged_node(&mut self, tagged: &TaggedNode) {
if let Some(mapping) = tagged.as_mapping() {
self.visit_mapping(&mapping);
} else if let Some(sequence) = tagged.as_sequence() {
self.visit_sequence(&sequence);
} else if let Some(scalar) = tagged.value() {
self.visit_scalar(&scalar);
}
}
fn walk_mapping(&mut self, mapping: &Mapping) {
for (key_node, value_node) in mapping.pairs() {
visit_node(self, &key_node);
visit_node(self, &value_node);
}
}
fn walk_sequence(&mut self, sequence: &Sequence) {
for item in sequence.items() {
visit_node(self, &item);
}
}
}
fn visit_node<V: YamlVisitor + ?Sized>(visitor: &mut V, node: &crate::yaml::SyntaxNode) {
use crate::yaml::extract;
if let Some(scalar) = extract(node) {
visitor.visit_scalar(&scalar);
} else if let Some(tagged) = extract(node) {
visitor.visit_tagged_node(&tagged);
} else if let Some(mapping) = extract(node) {
visitor.visit_mapping(&mapping);
} else if let Some(sequence) = extract(node) {
visitor.visit_sequence(&sequence);
}
}
pub trait YamlAccept {
fn accept<V: YamlVisitor>(&self, visitor: &mut V);
}
impl YamlAccept for YamlFile {
fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
visitor.visit_yaml(self);
}
}
impl YamlAccept for Document {
fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
visitor.visit_document(self);
}
}
impl YamlAccept for Scalar {
fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
visitor.visit_scalar(self);
}
}
impl YamlAccept for Mapping {
fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
visitor.visit_mapping(self);
}
}
impl YamlAccept for Sequence {
fn accept<V: YamlVisitor>(&self, visitor: &mut V) {
visitor.visit_sequence(self);
}
}
#[derive(Debug, Clone)]
pub struct ScalarCollector {
pub scalars: Vec<String>,
}
impl ScalarCollector {
pub fn new() -> Self {
Self {
scalars: Vec::new(),
}
}
}
impl Default for ScalarCollector {
fn default() -> Self {
Self::new()
}
}
impl YamlVisitor for ScalarCollector {
fn visit_scalar(&mut self, scalar: &Scalar) {
self.scalars.push(scalar.to_string());
}
}
#[derive(Debug, Clone)]
pub struct NodeCounter {
pub document_count: usize,
pub scalar_count: usize,
pub mapping_count: usize,
pub sequence_count: usize,
}
impl NodeCounter {
pub fn new() -> Self {
Self {
document_count: 0,
scalar_count: 0,
mapping_count: 0,
sequence_count: 0,
}
}
pub fn total(&self) -> usize {
self.document_count + self.scalar_count + self.mapping_count + self.sequence_count
}
}
impl Default for NodeCounter {
fn default() -> Self {
Self::new()
}
}
impl YamlVisitor for NodeCounter {
fn visit_document(&mut self, document: &Document) {
self.document_count += 1;
self.walk_document(document);
}
fn visit_scalar(&mut self, _scalar: &Scalar) {
self.scalar_count += 1;
}
fn visit_mapping(&mut self, mapping: &Mapping) {
self.mapping_count += 1;
self.walk_mapping(mapping);
}
fn visit_sequence(&mut self, sequence: &Sequence) {
self.sequence_count += 1;
self.walk_sequence(sequence);
}
}
pub struct ScalarTransformer<F>
where
F: FnMut(&str) -> String,
{
transform: F,
transformed: Vec<(String, String)>, }
impl<F> ScalarTransformer<F>
where
F: FnMut(&str) -> String,
{
pub fn new(transform: F) -> Self {
Self {
transform,
transformed: Vec::new(),
}
}
pub fn results(&self) -> &[(String, String)] {
&self.transformed
}
}
impl<F> YamlVisitor for ScalarTransformer<F>
where
F: FnMut(&str) -> String,
{
fn visit_scalar(&mut self, scalar: &Scalar) {
let original = scalar.to_string();
let transformed = (self.transform)(&original);
self.transformed.push((original, transformed));
}
}