duster/src/renderer/walking.rs

84 lines
2.4 KiB
Rust
Raw Normal View History

use crate::renderer::context_element::ContextElement;
use crate::renderer::WalkError;
use std::borrow::Borrow;
enum WalkResult<'a> {
NoWalk,
PartialWalk,
FullyWalked(&'a dyn ContextElement),
}
fn walk_path_from_single_level<'a, P, C>(context: &'a C, path: &[P]) -> WalkResult<'a>
where
P: Borrow<str>,
C: Borrow<dyn ContextElement + 'a>,
{
if path.is_empty() {
return WalkResult::FullyWalked(context.borrow());
}
let mut walk_failure = WalkResult::NoWalk;
let mut output = context.borrow();
for elem in path.iter() {
match output.borrow().walk(elem.borrow()) {
Err(WalkError::CantWalk { .. }) => {
return walk_failure;
}
Ok(new_val) => {
walk_failure = WalkResult::PartialWalk;
output = new_val;
}
}
}
WalkResult::FullyWalked(output)
}
pub fn walk_path<'a, B, P>(
breadcrumbs: &'a Vec<B>,
path: &Vec<P>,
) -> Result<&'a dyn ContextElement, WalkError>
where
B: Borrow<dyn ContextElement + 'a>,
P: Borrow<str>,
{
if path.is_empty() {
return Ok(breadcrumbs
.last()
.expect("Breadcrumbs should never be empty.")
.borrow());
}
if path
.first()
.expect("Already proved path is not empty")
.borrow()
== "."
{
return match walk_path_from_single_level(
breadcrumbs
.last()
.expect("Breadcrumbs should never be empty"),
&path[1..],
) {
// If no walking was done at all or we partially walked
// then stop trying to find anything because '.' restricts
// us to the current scope
WalkResult::NoWalk | WalkResult::PartialWalk => Err(WalkError::CantWalk),
WalkResult::FullyWalked(new_context) => Ok(new_context),
};
}
for context in breadcrumbs.iter().rev() {
match walk_path_from_single_level(context, path) {
// If no walking was done at all, keep looping
WalkResult::NoWalk => {}
// If we partially walked then stop trying to find
// anything
WalkResult::PartialWalk => {
return Err(WalkError::CantWalk);
}
WalkResult::FullyWalked(new_context) => return Ok(new_context),
}
}
Err(WalkError::CantWalk)
}