`prepare_component()` ahora devuelve `Result<Markup, ComponentError>` en lugar de `Markup`, para que los componentes señalen fallos durante el renderizado de forma explícita. `ComponentError` encapsula un mensaje de error y un marcado HTML alternativo opcional (`fallback`). Si se produce un error, el ciclo de renderizado registra la traza y muestra el `fallback` en lugar del componente fallido, sin interrumpir el resto de la página. Lo mismo aplica a los errores devueltos por la acción `PrepareRender` de los temas, que siguen el mismo mecanismo.
59 lines
1.5 KiB
Rust
59 lines
1.5 KiB
Rust
use crate::core::action::{ActionBox, ActionDispatcher};
|
|
use crate::core::AnyCast;
|
|
use crate::trace;
|
|
use crate::AutoDefault;
|
|
|
|
use parking_lot::RwLock;
|
|
|
|
#[derive(AutoDefault)]
|
|
pub struct ActionsList(RwLock<Vec<ActionBox>>);
|
|
|
|
impl ActionsList {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn add(&mut self, action: ActionBox) {
|
|
let mut list = self.0.write();
|
|
list.push(action);
|
|
list.sort_by_key(|a| a.weight());
|
|
}
|
|
|
|
pub fn iter_map<A, B, F>(&self, mut f: F)
|
|
where
|
|
Self: Sized,
|
|
A: ActionDispatcher,
|
|
F: FnMut(&A) -> B,
|
|
{
|
|
let _: Vec<_> = self
|
|
.0
|
|
.read()
|
|
.iter()
|
|
.rev()
|
|
.map(|a| {
|
|
if let Some(action) = (**a).downcast_ref::<A>() {
|
|
f(action);
|
|
} else {
|
|
trace::error!("Failed to downcast action of type {}", (**a).type_name());
|
|
}
|
|
})
|
|
.collect();
|
|
}
|
|
|
|
pub fn iter_try_map<A, F>(&self, mut f: F)
|
|
where
|
|
A: ActionDispatcher,
|
|
F: FnMut(&A) -> std::ops::ControlFlow<()>,
|
|
{
|
|
let list = self.0.read();
|
|
for a in list.iter().rev() {
|
|
if let Some(action) = (**a).downcast_ref::<A>() {
|
|
if f(action).is_break() {
|
|
break;
|
|
}
|
|
} else {
|
|
trace::error!("Failed to downcast action of type {}", (**a).type_name());
|
|
}
|
|
}
|
|
}
|
|
}
|