2020-06-07 13:25:27 -04:00
|
|
|
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
2020-05-30 17:50:27 -04:00
|
|
|
use crate::renderer::context_element::IntoContextElement;
|
2020-05-09 15:15:43 -04:00
|
|
|
use crate::renderer::WalkError;
|
2020-05-24 14:56:09 -04:00
|
|
|
use std::borrow::Borrow;
|
2020-05-09 15:15:43 -04:00
|
|
|
|
|
|
|
enum WalkResult<'a> {
|
|
|
|
NoWalk,
|
|
|
|
PartialWalk,
|
2020-05-30 17:50:27 -04:00
|
|
|
FullyWalked(&'a dyn IntoContextElement),
|
2020-05-09 15:15:43 -04:00
|
|
|
}
|
|
|
|
|
2020-06-07 13:25:27 -04:00
|
|
|
fn walk_path_from_single_level<'a, P>(
|
|
|
|
context: &'a dyn IntoContextElement,
|
|
|
|
path: &[P],
|
|
|
|
) -> WalkResult<'a>
|
2020-05-24 14:56:09 -04:00
|
|
|
where
|
|
|
|
P: Borrow<str>,
|
|
|
|
{
|
|
|
|
if path.is_empty() {
|
2020-06-07 13:25:27 -04:00
|
|
|
return WalkResult::FullyWalked(context);
|
2020-05-24 14:56:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut walk_failure = WalkResult::NoWalk;
|
2020-06-07 13:25:27 -04:00
|
|
|
let mut output = context;
|
2020-05-24 14:56:09 -04:00
|
|
|
for elem in path.iter() {
|
2020-06-07 13:25:27 -04:00
|
|
|
match output.walk(elem.borrow()) {
|
2020-05-24 14:56:09 -04:00
|
|
|
Err(WalkError::CantWalk { .. }) => {
|
|
|
|
return walk_failure;
|
|
|
|
}
|
|
|
|
Ok(new_val) => {
|
|
|
|
walk_failure = WalkResult::PartialWalk;
|
|
|
|
output = new_val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WalkResult::FullyWalked(output)
|
|
|
|
}
|
|
|
|
|
2020-06-07 13:25:27 -04:00
|
|
|
fn get_first_non_pseudo_element<'a>(
|
|
|
|
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
|
|
|
) -> Option<&'a BreadcrumbTreeElement<'a>> {
|
2020-05-30 11:50:55 -04:00
|
|
|
breadcrumbs
|
|
|
|
.iter()
|
|
|
|
.rev()
|
2020-06-07 13:25:27 -04:00
|
|
|
.filter(|b| {
|
|
|
|
!std::borrow::Borrow::<dyn IntoContextElement + 'a>::borrow(*b).is_pseudo_element()
|
|
|
|
})
|
2020-05-30 11:50:55 -04:00
|
|
|
.next()
|
|
|
|
}
|
|
|
|
|
2020-06-07 13:25:27 -04:00
|
|
|
pub fn walk_path<'a, P>(
|
|
|
|
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
2020-05-24 14:56:09 -04:00
|
|
|
path: &Vec<P>,
|
2020-05-30 17:50:27 -04:00
|
|
|
) -> Result<&'a dyn IntoContextElement, WalkError>
|
2020-05-24 14:56:09 -04:00
|
|
|
where
|
|
|
|
P: Borrow<str>,
|
|
|
|
{
|
2020-06-07 13:25:27 -04:00
|
|
|
match (breadcrumbs.last(), path.first()) {
|
|
|
|
(None, _) => return Err(WalkError::CantWalk),
|
|
|
|
(Some(last_elem), None) => return Ok(last_elem.borrow()),
|
|
|
|
(Some(_), Some(path_first)) if path_first.borrow() == "." => {
|
|
|
|
let first_non_pseudo_element = get_first_non_pseudo_element(breadcrumbs);
|
|
|
|
return match first_non_pseudo_element {
|
|
|
|
None => Err(WalkError::CantWalk),
|
|
|
|
Some(current_context) => {
|
|
|
|
match walk_path_from_single_level(current_context.borrow(), &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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
(Some(_), Some(_path_first)) => {
|
|
|
|
for context in breadcrumbs.iter().rev() {
|
|
|
|
match walk_path_from_single_level(context.borrow(), 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),
|
2020-05-30 11:50:55 -04:00
|
|
|
}
|
|
|
|
}
|
2020-05-24 14:56:09 -04:00
|
|
|
}
|
|
|
|
}
|
2020-06-07 13:25:27 -04:00
|
|
|
|
2020-05-24 14:56:09 -04:00
|
|
|
Err(WalkError::CantWalk)
|
|
|
|
}
|