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, C: Borrow, { 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, path: &Vec

, ) -> Result<&'a dyn ContextElement, WalkError> where B: Borrow, P: Borrow, { 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) }