use std::any::Any;
use std::fmt;
use std::ops::ControlFlow;
pub trait RouteMetadata: fmt::Debug + Clone + Send + Sync + 'static {
fn merge(&mut self, other: &Self);
}
#[derive(Debug, Default)]
pub struct RouteMetadataSet {
extensions: Vec<Box<dyn DynRouteMetadata>>,
}
impl RouteMetadataSet {
pub fn insert<T: RouteMetadata>(&mut self, value: T) {
for ext in &mut self.extensions {
if let Some(ext) = ext.as_mut_dyn().downcast_mut::<T>() {
ext.merge(&value);
return;
}
}
self.extensions.push(Box::new(value) as _);
}
pub fn merge(&mut self, other: &Self) {
for other_ext in &other.extensions {
for self_ext in &mut self.extensions {
if self_ext.merge_maybe(&**other_ext).is_break() {
break;
}
}
self.extensions.push(other_ext.clone_boxed());
}
}
pub fn get<T: RouteMetadata>(&self) -> Option<&T> {
for ext in &self.extensions {
if let Some(ext) = ext.as_dyn().downcast_ref::<T>() {
return Some(ext);
}
}
None
}
}
trait DynRouteMetadata: fmt::Debug + Send + Sync + 'static {
fn merge_maybe(&mut self, other: &dyn DynRouteMetadata) -> ControlFlow<()>;
fn clone_boxed(&self) -> Box<dyn DynRouteMetadata>;
fn as_dyn(&self) -> &(dyn Any + Send + Sync + 'static);
fn as_mut_dyn(&mut self) -> &mut (dyn Any + Send + Sync + 'static);
}
impl<T: RouteMetadata> DynRouteMetadata for T {
fn merge_maybe(&mut self, other: &dyn DynRouteMetadata) -> ControlFlow<()> {
match other.as_dyn().downcast_ref::<Self>() {
Some(other) => {
self.merge(other);
ControlFlow::Break(())
}
None => ControlFlow::Continue(()),
}
}
fn clone_boxed(&self) -> Box<dyn DynRouteMetadata> {
Box::new(self.clone()) as _
}
fn as_dyn(&self) -> &(dyn Any + Send + Sync + 'static) {
self as _
}
fn as_mut_dyn(&mut self) -> &mut (dyn Any + Send + Sync + 'static) {
self as _
}
}