use crate::renderer::context_element::ContextElement; use crate::renderer::WalkError; enum WalkResult<'a> { NoWalk, PartialWalk, FullyWalked(&'a dyn ContextElement), } fn walk_path_from_single_level<'a>( context: &'a dyn ContextElement, path: &[&str], ) -> WalkResult<'a> { 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) { Err(WalkError::CantWalk { .. }) => { return walk_failure; } Ok(new_val) => { walk_failure = WalkResult::PartialWalk; output = new_val; } } } WalkResult::FullyWalked(output) } pub fn walk_path<'a>( breadcrumbs: &Vec<&'a dyn ContextElement>, path: &'a Vec<&str>, ) -> Result<&'a dyn ContextElement, WalkError> { if path.is_empty() { return Ok(*breadcrumbs .last() .expect("Breadcrumbs should never be empty")); } if *path.first().expect("Already proved path is not empty") == "." { 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) } pub fn owned_walk_path<'a>( breadcrumbs: &'a Vec>, path: &Vec, ) -> Result<&'a dyn ContextElement, WalkError> { if path.is_empty() { return Ok(breadcrumbs .last() .expect("Breadcrumbs should never be empty") .as_ref()); } let path_reference: Vec<&str> = path.iter().map(|p| &p[..]).collect(); if path.first().expect("Already proved path is not empty") == "." { return match walk_path_from_single_level( breadcrumbs .last() .expect("Breadcrumbs should never be empty") .as_ref(), &path_reference[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.as_ref(), &path_reference) { // 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) }