use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement; use crate::renderer::context_element::IntoContextElement; use crate::renderer::WalkError; use std::borrow::Borrow; enum WalkResult<'a> { NoWalk, PartialWalk, FullyWalked(&'a dyn IntoContextElement), } fn walk_path_from_single_level<'a, P>( context: &'a dyn IntoContextElement, path: &[P], ) -> WalkResult<'a> where P: Borrow, { if path.is_empty() { return WalkResult::FullyWalked(context); } let mut walk_failure = WalkResult::NoWalk; let mut output = context; for elem in path.iter() { match output.walk(elem.borrow()) { Err(WalkError::CantWalk { .. }) => { return walk_failure; } Ok(new_val) => { walk_failure = WalkResult::PartialWalk; output = new_val; } } } WalkResult::FullyWalked(output) } fn get_first_non_pseudo_element<'a>( breadcrumbs: &'a Vec>, ) -> Option<&'a BreadcrumbTreeElement<'a>> { breadcrumbs .iter() .rev() .filter(|b| { std::borrow::Borrow::::borrow(*b).is_pseudo_element() }) .next() } pub fn walk_path<'a, P>( breadcrumbs: &'a Vec>, path: &Vec

, ) -> Result<&'a dyn IntoContextElement, WalkError> where P: Borrow, { 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), } } } } Err(WalkError::CantWalk) }