use super::{super::normal::*, node::*, representation::*, segment::*};
use {
depiction::*,
kutil::std::iter::*,
std::{
fmt::{self, Write},
io, ptr,
},
};
#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Path<'own, AnnotatedT> {
pub nodes: Vec<PathNode<'own, AnnotatedT>>,
}
impl<'own, AnnotatedT> Path<'own, AnnotatedT> {
pub fn find(ancestor: &'own Variant<AnnotatedT>, descendent: &'own Variant<AnnotatedT>) -> Option<Self>
where
AnnotatedT: Default,
{
if ptr::eq(descendent, ancestor) {
let mut path = Path::default();
path.push(ancestor);
return Some(path);
}
match ancestor {
Variant::List(list) => {
for (index, child) in list.inner.iter().enumerate() {
if let Some(child_route) = Self::find(child, descendent) {
let mut path = Path::default();
path.push_list_index(ancestor, index);
path.extend(child_route);
return Some(path);
}
}
}
Variant::Map(map) => {
for (key, child) in &map.inner {
if ptr::eq(descendent, key) {
let mut path = Path::default();
path.push_map_key(ancestor, key);
return Some(path);
}
if let Some(child_path) = Self::find(child, descendent) {
let mut path = Path::default();
path.push_map_key(ancestor, key);
path.extend(child_path);
return Some(path);
}
}
}
_ => {}
}
None
}
pub fn push(&mut self, variant: &'own Variant<AnnotatedT>) {
self.nodes.push(PathNode::new(variant, None))
}
pub fn push_list_index(&mut self, variant: &'own Variant<AnnotatedT>, index: usize) {
self.nodes.push(PathNode::new(variant, Some(PathSegment::ListIndex(index))))
}
pub fn push_map_key(&mut self, variant: &'own Variant<AnnotatedT>, key: &'own Variant<AnnotatedT>) {
self.nodes.push(PathNode::new(variant, Some(PathSegment::MapKey(key))))
}
pub fn extend(&mut self, other: Path<'own, AnnotatedT>) {
self.nodes.extend(other.nodes);
}
pub fn into_representation(self) -> PathRepresentation {
PathRepresentation {
segments: self
.nodes
.into_iter()
.filter_map(|node| node.segment.map(|segment| segment.to_string_keys()))
.collect(),
}
}
}
impl<'own, AnnotatedT> Depict for Path<'own, AnnotatedT> {
fn depict<WriteT>(&self, writer: &mut WriteT, context: &DepictionContext) -> io::Result<()>
where
WriteT: io::Write,
{
for (node, first) in IterateWithFirst::new(&self.nodes) {
if let Some(segment) = &node.segment {
if !first && matches!(segment, PathSegment::MapKey(_)) {
context.theme.write_delimiter(writer, '.')?;
}
segment.depict(writer, context)?;
}
}
Ok(())
}
}
impl<'own, AnnotatedT> fmt::Display for Path<'own, AnnotatedT> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
for (node, first) in IterateWithFirst::new(&self.nodes) {
if let Some(segment) = &node.segment {
if !first && matches!(segment, PathSegment::MapKey(_)) {
formatter.write_char('.')?;
}
fmt::Display::fmt(segment, formatter)?;
}
}
Ok(())
}
}