use std::any::Any;
use std::fmt::Debug;
use dyn_clone::DynClone;
trait DynCompare: Any {
fn dyn_eq(&self, other: &dyn DynCompare) -> bool;
}
impl<T> DynCompare for T
where
T: Any + PartialEq,
{
fn dyn_eq(&self, other: &dyn DynCompare) -> bool {
if let Some(other) = (other as &dyn Any).downcast_ref::<Self>() {
self == other
} else {
false
}
}
}
impl PartialEq<dyn DynCompare> for dyn DynCompare {
fn eq(&self, other: &dyn DynCompare) -> bool {
self.dyn_eq(other)
}
}
#[allow(private_bounds)]
pub trait PropBound: Any + DynClone + DynCompare + Debug + Send + Sync {
fn to_any_prop(self) -> AnyPropBox;
}
impl<T> PropBound for T
where
T: Any + DynClone + DynCompare + Debug + Sized + Send + Sync,
{
fn to_any_prop(self) -> AnyPropBox {
Box::new(self)
}
}
impl PartialEq<dyn PropBound> for dyn PropBound {
fn eq(&self, other: &dyn PropBound) -> bool {
self as &dyn DynCompare == other as &dyn DynCompare
}
}
dyn_clone::clone_trait_object!(PropBound);
pub type AnyPropBox = Box<dyn PropBound>;
impl dyn PropBound {
pub fn as_any(&self) -> &dyn Any {
self
}
pub fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use crate::props::PropBound;
#[test]
fn should_work_basic() {
let value = String::from("Some string");
let prop_boxed = value.to_any_prop();
assert_eq!(
prop_boxed.as_any().downcast_ref::<String>().unwrap(),
&String::from("Some string")
);
let mut prop_boxed = prop_boxed;
prop_boxed
.as_any_mut()
.downcast_mut::<String>()
.unwrap()
.push_str(" hello");
assert_eq!(
prop_boxed.as_any().downcast_ref::<String>().unwrap(),
&String::from("Some string hello")
);
}
}