orchestrator
This commit is contained in:
256
src/orchestrator/router.rs
Normal file
256
src/orchestrator/router.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
// 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<String>, to: String },
|
||||
Back { to: String },
|
||||
Forward { to: String },
|
||||
}
|
||||
|
||||
pub struct Router<C: Component> {
|
||||
#[cfg(feature = "alloc")]
|
||||
pages: HashMap<String, C>,
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
pages: Vec<(String, C)>,
|
||||
current: Option<String>,
|
||||
history: Vec<String>,
|
||||
future: Vec<String>,
|
||||
focus: FocusManager<C::Focus>,
|
||||
}
|
||||
|
||||
impl<C: Component> Default for Router<C> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Component> Router<C> {
|
||||
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<Option<RouterEvent>, 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<Option<RouterEvent>, 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<Option<RouterEvent>, 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<C::Focus> {
|
||||
&self.focus
|
||||
}
|
||||
|
||||
pub fn focus_manager_mut(&mut self) -> &mut FocusManager<C::Focus> {
|
||||
&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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user