// path_from_the_root: src/orchestrator/router.rs extern crate alloc; use alloc::string::String; use alloc::vec::Vec; #[cfg(feature = "alloc")] use hashbrown::HashMap; use crate::component::Component; use crate::focus::{FocusError, FocusManager}; #[derive(Debug, Clone)] pub enum RouterEvent { Navigated { from: Option, to: String }, Back { to: String }, Forward { to: String }, } pub struct Router { #[cfg(feature = "alloc")] pages: HashMap, #[cfg(not(feature = "alloc"))] pages: Vec<(String, C)>, current: Option, history: Vec, future: Vec, focus: FocusManager, } impl Default for Router { fn default() -> Self { Self::new() } } impl Router { pub fn new() -> Self { Self { #[cfg(feature = "alloc")] pages: HashMap::new(), #[cfg(not(feature = "alloc"))] pages: Vec::new(), current: None, history: Vec::new(), future: Vec::new(), focus: FocusManager::new(), } } pub fn register(&mut self, id: String, mut page: C) { #[cfg(feature = "alloc")] { if self.current.as_ref() == Some(&id) { let _ = page.on_enter(); let targets = page.targets(); self.focus.set_targets(targets.to_vec()); } self.pages.insert(id, page); } #[cfg(not(feature = "alloc"))] { if self.current.as_ref() == Some(&id) { let _ = page.on_enter(); let targets = page.targets(); self.focus.set_targets(targets.to_vec()); } self.pages.push((id, page)); } } fn get_page_mut(&mut self, id: &str) -> Option<&mut C> { #[cfg(feature = "alloc")] { self.pages.get_mut(id) } #[cfg(not(feature = "alloc"))] { self.pages .iter_mut() .find(|(page_id, _)| page_id == id) .map(|(_, page)| page) } } fn get_page(&self, id: &str) -> Option<&C> { #[cfg(feature = "alloc")] { self.pages.get(id) } #[cfg(not(feature = "alloc"))] { self.pages .iter() .find(|(page_id, _)| page_id == id) .map(|(_, page)| page) } } pub fn navigate(&mut self, id: String) -> Result, FocusError> { let result = if let Some(current_id) = self.current.take() { if let Some(current_page) = self.get_page_mut(¤t_id) { let _ = current_page.on_exit(); } self.history.push(current_id.clone()); self.future.clear(); Some(RouterEvent::Navigated { from: Some(current_id), to: id.clone(), }) } else { Some(RouterEvent::Navigated { from: None, to: id.clone(), }) }; let targets = if let Some(page) = self.get_page_mut(&id) { let _ = page.on_enter(); Some(page.targets().to_vec()) } else { None }; if let Some(targets) = targets { self.focus.set_targets(targets); } self.current = Some(id); Ok(result) } pub fn back(&mut self) -> Result, FocusError> { if let Some(current) = self.current.take() { if let Some(from) = self.history.pop() { self.future.push(current.clone()); let to = from.clone(); if let Some(current_page) = self.get_page_mut(¤t) { let _ = current_page.on_exit(); } self.current = Some(to.clone()); let targets = if let Some(page) = self.get_page_mut(&to) { let _ = page.on_enter(); Some(page.targets().to_vec()) } else { None }; if let Some(targets) = targets { self.focus.set_targets(targets); } Ok(Some(RouterEvent::Back { to })) } else { self.current = Some(current); Ok(None) } } else { Ok(None) } } pub fn forward(&mut self) -> Result, FocusError> { if let Some(current) = self.current.take() { if let Some(from) = self.future.pop() { self.history.push(current.clone()); let to = from.clone(); if let Some(current_page) = self.get_page_mut(¤t) { let _ = current_page.on_exit(); } self.current = Some(to.clone()); let targets = if let Some(page) = self.get_page_mut(&to) { let _ = page.on_enter(); Some(page.targets().to_vec()) } else { None }; if let Some(targets) = targets { self.focus.set_targets(targets); } Ok(Some(RouterEvent::Forward { to })) } else { self.current = Some(current); Ok(None) } } else { Ok(None) } } pub fn current(&self) -> Option<&C> { self.current.as_ref().and_then(|id| self.get_page(id)) } pub fn current_mut(&mut self) -> Option<&mut C> { if let Some(id) = self.current.clone() { self.get_page_mut(&id) } else { None } } pub fn current_id(&self) -> Option<&String> { self.current.as_ref() } pub fn focus_manager(&self) -> &FocusManager { &self.focus } pub fn focus_manager_mut(&mut self) -> &mut FocusManager { &mut self.focus } pub fn history(&self) -> &[String] { &self.history } pub fn future(&self) -> &[String] { &self.future } pub fn page_count(&self) -> usize { #[cfg(feature = "alloc")] { self.pages.len() } #[cfg(not(feature = "alloc"))] { self.pages.len() } } pub fn has_page(&self, id: &str) -> bool { #[cfg(feature = "alloc")] { self.pages.contains_key(id) } #[cfg(not(feature = "alloc"))] { self.pages.iter().any(|(page_id, _)| page_id == id) } } }