use crate::provider::{EntryId, Path};
use derive_more::{Deref, DerefMut};
use std::collections::HashMap;
#[derive(Debug, Deref, DerefMut)]
pub struct Pathfinder<T> {
root: Record<T>,
}
impl<T> Pathfinder<T> {
pub fn new() -> Self {
Self {
root: Record::default(),
}
}
}
impl<T> Default for Pathfinder<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct Record<T> {
subs: HashMap<EntryId, Record<T>>,
link: Option<T>,
}
impl<T> Default for Record<T> {
fn default() -> Self {
Self {
subs: HashMap::new(),
link: None,
}
}
}
pub struct Discovered<'a, T> {
pub remained_path: Path,
pub record: &'a Record<T>,
}
impl<T> Record<T> {
pub fn dig(&mut self, path: Path) -> &mut Self {
let mut record = self;
let entries: Vec<_> = path.into();
for element in entries {
record = record.subs.entry(element).or_default();
}
record
}
pub fn discover(&self, path: &Path) -> Discovered<'_, T> {
let mut record = self;
let mut iter = path.as_ref().iter();
let mut remained = Vec::new();
while let Some(element) = iter.next() {
if let Some(next_record) = record.subs.get(element) {
record = next_record;
} else {
remained.push(element.clone());
break;
}
}
remained.extend(iter.cloned());
Discovered {
remained_path: Path::from(remained),
record,
}
}
pub fn remove(&mut self, path: &Path) -> Option<Self> {
let mut record = self;
let mut iter = path.as_ref().iter();
while let Some(element) = iter.next() {
if iter.len() == 0 {
return record.subs.remove(element);
} else if let Some(next_record) = record.subs.get_mut(element) {
record = next_record;
} else {
break;
}
}
None
}
pub fn find(&self, path: &Path) -> Option<&Self> {
let mut record = self;
for element in path.as_ref() {
if let Some(next_record) = record.subs.get(element) {
record = next_record;
} else {
return None;
}
}
Some(record)
}
pub fn find_mut(&mut self, path: &Path) -> Option<&mut Self> {
let mut record = self;
for element in path.as_ref() {
if let Some(next_record) = record.subs.get_mut(element) {
record = next_record;
} else {
return None;
}
}
Some(record)
}
pub fn list(&self) -> impl Iterator<Item = (EntryId, Option<&T>)> {
self.subs.iter().map(|(id, record)| {
let id = id.to_owned();
(id, record.link.as_ref())
})
}
pub fn set_link(&mut self, link: T) -> Option<T> {
let mut cell = Some(link);
std::mem::swap(&mut self.link, &mut cell);
cell
}
pub fn take_link(&mut self) -> Option<T> {
self.link.take()
}
pub fn get_link(&self) -> Option<&T> {
self.link.as_ref()
}
pub fn get_link_mut(&mut self) -> Option<&mut T> {
self.link.as_mut()
}
}