use std::fmt::*;
#[derive(Clone, Default, Deserialize, Serialize)]
pub struct Path<I, F>
where
I: Debug,
F: Debug,
{
interface: Option<I>,
items: Vec<PathItem<I, F>>,
}
impl<I, F> From<Vec<PathItem<I, F>>> for Path<I, F>
where
I: Debug,
F: Debug,
{
fn from(items: Vec<PathItem<I, F>>) -> Self {
Path {
interface: None,
items,
}
}
}
impl<I, F> std::hash::Hash for Path<I, F>
where
I: Debug + std::hash::Hash,
F: Debug + std::hash::Hash,
{
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
self.items.as_slice().hash(hasher)
}
}
impl<I, F> std::cmp::PartialEq for Path<I, F>
where
I: Debug + PartialEq,
F: Debug + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.items == other.items
}
}
impl<I, F> std::cmp::Eq for Path<I, F>
where
I: Debug + Eq,
F: Debug + Eq,
{
}
impl<I, F> std::fmt::Display for Path<I, F>
where
I: Debug + Display,
F: Debug + Display,
{
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result {
self.items.fmt(formatter)
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub struct PathItem<I, F>
where
I: Debug,
F: Debug,
{
pub interface: I,
pub field: F,
}
impl<I, F> PathItem<I, F>
where
I: Debug,
F: Debug,
{
pub fn interface(&self) -> &I {
&self.interface
}
pub fn field(&self) -> &F {
&self.field
}
}
impl<I, F> Debug for Path<I, F>
where
I: Debug,
F: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result {
use itertools::Itertools;
write!(
f,
"[{items}{more}]",
items = self
.items
.iter()
.map(|item| format!("{:?}.{:?}", item.interface, item.field))
.format(" > "),
more = if let Some(ref interface) = self.interface {
format!(" > {:?}", interface)
} else {
"".to_string()
}
)
}
}
impl<I, F> Path<I, F>
where
I: Debug + PartialEq,
F: Debug + PartialEq,
{
pub fn new() -> Self {
Self {
interface: None,
items: vec![],
}
}
pub fn extend_from_slice(&mut self, slice: &[PathItem<I, F>])
where
I: Clone,
F: Clone,
{
self.items.extend_from_slice(slice)
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
interface: None,
items: Vec::with_capacity(capacity),
}
}
pub fn enter_interface(&mut self, node: I) {
debug!(target: "path", "enter_interface: {:?}", node);
debug_assert!(
self.interface.is_none(),
"We shouldn't have a pending interface, got {:?}",
self.interface
);
self.interface = Some(node);
}
pub fn exit_interface(&mut self, node: I) {
debug!(target: "path", "exit_interface: {:?}", node);
let interface = self
.interface
.take()
.expect("Could not exit_interface if we're not in an interface");
debug_assert!(node == interface);
}
pub fn enter_field(&mut self, field: F) {
debug!(target: "path", "enter_field: {:?} at {:?}", field, self.interface);
let interface = self.interface.take().unwrap();
self.items.push(PathItem { interface, field });
}
pub fn exit_field(&mut self, field: F) {
debug!(target: "path", "exit_field: {:?}", field);
debug_assert!(
self.interface.is_none(),
"We shouldn't have a pending interface, got {:?}",
self.interface
);
let PathItem {
interface,
field: prev,
} = self
.items
.pop()
.expect("Could not exit_field from an empty ASTath");
debug_assert!(prev == field);
self.interface = Some(interface);
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn get(&self, index: usize) -> Option<&PathItem<I, F>> {
if index >= self.len() {
return None;
}
Some(&self.items[self.len() - index - 1])
}
pub fn tail(&self, len: usize) -> &[PathItem<I, F>] {
if len < self.len() {
&self.items[self.len() - len..]
} else {
&self.items
}
}
pub fn iter(&self) -> impl Iterator<Item = &PathItem<I, F>> {
self.items.iter()
}
}
impl<I, F> std::borrow::Borrow<[PathItem<I, F>]> for Path<I, F>
where
I: Debug + PartialEq,
F: Debug + PartialEq,
{
fn borrow(&self) -> &[PathItem<I, F>] {
&self.items
}
}
pub trait Node: downcast_rs::Downcast {
fn name(&self) -> &'static str;
fn scoped_dictionary(&self) -> Option<&::SharedString> {
None
}
}
impl_downcast!(Node);