/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::{any::Any, fmt, hash::Hash};
use anyhow::{anyhow, bail, Result}; use indexmap::{IndexMap, IndexSet};
usesuper::Value;
/// Node trait, this is implemented on all nodes in the Ir (structs, enums and their fields) /// /// Note: All node types must implement `Clone`, `Default`, and `PartialEq`, and the derive macro ensures that. /// However, these are not bounds on the node trait, since they're not `dyn-compatible`. pubtrait Node: fmt::Debug + Any { /// Call a visitor function for all child nodes /// /// Calls the visitor with a path string that represents the field name, vec index, etc. along /// with the child node. /// /// If the visitor returns an error, then the error is returned from `visit_children` without /// any more visits. fn visit_children(
&self,
_visitor: &mutdyn FnMut(&str, &dyn Node) -> Result<()>,
) -> Result<()> {
Ok(())
}
/// Like visit_children, but use &mut. /// /// Note: this will not visit `IndexMap` keys, since they can't be mutated. fn visit_children_mut(
&mutself,
_visitor: &mutdyn FnMut(&str, &mutdyn Node) -> Result<()>,
) -> Result<()> {
Ok(())
}
/// Type name for structs / enums /// /// This is used to implement the type name filter in the CLI fn type_name(&self) -> Option<&'static str> {
None
}
/// Create a value from this node's data /// /// Logically, this consumes `self`. However, it inputs `&mut self` because it works better /// with dyn traits. It leaves behind an empty node. fn take_into_value(&mutself) -> Value;
/// Convert a value into this node. fn try_from_value(value: Value) -> Result<Self, FromValueError> where Self: Sized;
/// Convert `&Node` into `&dyn Any`. /// /// This is used to implement `visit_children`. fn as_any(&self) -> &dyn Any;
/// Does this node has any descendant where the closure returns `true`? fn has_descendant<T: Node>(&self, mut matcher: impl FnMut(&T) -> bool) -> bool where Self: Sized,
{ self.try_visit(|node: &T| { if matcher(node) { // `matcher` returned true, so we want to short-circuit the `try_visit`. To do // that, return an error, then check the error after `try_visit` completes. It's // weird, but it works
bail!("");
} else {
Ok(())
}
})
.is_err()
}
/// Does this node have any descendant of a given type? fn has_descendant_with_type<T: Node>(&self) -> bool where Self: Sized,
{ self.has_descendant(|_: &T| true)
}
/// Take the current value from `self` leaving behind an empty value fn take(&mutself) -> Self where Self: Default,
{
std::mem::take(self)
}
/// Convert from one node to another fn try_from_node(mut other: impl Node) -> Result<Self> where Self: Sized,
{ Self::try_from_value(other.take_into_value()).map_err(|mut e| {
e.path.reverse(); let path = e.path.join("");
anyhow!("Node conversion error: {} (path: <root>{path})", e.message)
})
}
}
/// Error struct for `Node::try_from_value` pubstruct FromValueError { /// Field path to the node that couldn't be converted. /// /// To make the generated code simpler, this is in reverse order, the first items in the vec /// are the deepest items in the node tree.
path: Vec<String>,
message: String,
}
fn try_from_value(value: Value) -> Result<Self, FromValueError> { match value {
Value::Vec(values) => values
.into_iter()
.enumerate()
.map(|(i, v)| {
v.try_into_node()
.map_err(|e| e.add_field_to_path(format!("[{i}]")))
})
.collect(),
v => Err(FromValueError::new(format!( "Node type error (expected Vec, actual {v:?})",
))),
}
}
}
impl<T> Node for IndexSet<T> where
T: Node + Hash + Eq,
{ fn visit_children(&self, visitor: &mutdyn FnMut(&str, &dyn Node) -> Result<()>) -> Result<()> { for v inself.iter() {
visitor(&format!("{{{v:?}}}"), v)?;
}
Ok(())
}
fn visit_children_mut(
&mutself,
visitor: &mutdyn FnMut(&str, &mutdyn Node) -> Result<()>,
) -> Result<()> { // We can't directly mutate IndexSet items, since that would change their hash value. // Instead, use deconstruct the set using into_iter() and collect everything at the end.
*self = Node::take(self)
.into_iter()
.map(|mut v| {
visitor(&format!("{{{v:?}}}"), &mut v)?;
Ok(v)
})
.collect::<Result<IndexSet<_>>>()?;
Ok(())
}
fn try_from_value(value: Value) -> Result<Self, FromValueError> { match value {
Value::Map(values) => values
.into_iter()
.map(|(k, v)| { let v = v
.try_into_node()
.map_err(|e| e.add_field_to_path(format!("[{k:?}]")))?; let k = k
.try_into_node()
.map_err(|e| e.add_field_to_path("[<key>]".to_string()))?;
Ok((k, v))
})
.collect(),
v => Err(FromValueError::new(format!( "Node type error (expected Map, actual {v:?})",
))),
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.