use std::{
any::{Any, TypeId},
fmt, ops,
sync::Arc,
};
use smallbox::*;
pub struct BoxAnyVarValue(SmallBox<dyn AnyVarValue, space::S4>);
impl ops::Deref for BoxAnyVarValue {
type Target = dyn AnyVarValue;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl ops::DerefMut for BoxAnyVarValue {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.0
}
}
impl BoxAnyVarValue {
pub fn new(value: impl AnyVarValue) -> Self {
BoxAnyVarValue(smallbox!(value))
}
pub fn downcast<T: VarValue>(self) -> Result<T, Self> {
match self.downcast_ref::<T>() {
Some(v) => Ok(v.clone()),
None => Err(self),
}
}
pub fn type_id(&self) -> TypeId {
(*self.0).type_id()
}
pub fn detailed_debug(&self) -> impl fmt::Debug {
struct DetailedDebug<'a>(&'a BoxAnyVarValue);
impl<'a> fmt::Debug for DetailedDebug<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut b = f.debug_struct("BoxAnyVarValue");
b.field("value", &*self.0.0);
#[cfg(feature = "type_names")]
b.field("type_name()", &self.0.0.type_name());
#[cfg(not(feature = "type_names"))]
b.field("type_id()", &self.0.type_id());
b.field("is_heap()", &SmallBox::is_heap(&self.0.0));
b.finish()
}
}
DetailedDebug(self)
}
}
impl Clone for BoxAnyVarValue {
fn clone(&self) -> Self {
self.0.clone_boxed()
}
}
impl fmt::Debug for BoxAnyVarValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.0, f)
}
}
pub trait AnyVarValue: fmt::Debug + Any + Send + Sync {
fn clone_boxed(&self) -> BoxAnyVarValue;
fn eq_any(&self, other: &dyn AnyVarValue) -> bool;
#[cfg(feature = "type_names")]
fn type_name(&self) -> &'static str;
fn try_swap(&mut self, other: &mut dyn AnyVarValue) -> bool;
}
impl dyn AnyVarValue {
pub fn downcast_ref<T: VarValue>(&self) -> Option<&T> {
let any: &dyn Any = self;
any.downcast_ref()
}
pub fn downcast_mut<T: VarValue>(&mut self) -> Option<&mut T> {
let any: &mut dyn Any = self;
any.downcast_mut()
}
pub fn is<T: VarValue>(&self) -> bool {
let any: &dyn Any = self;
any.is::<T>()
}
}
impl PartialEq for dyn AnyVarValue {
fn eq(&self, other: &Self) -> bool {
self.eq_any(other)
}
}
impl<T> AnyVarValue for T
where
T: fmt::Debug + PartialEq + Clone + Any + Send + Sync,
{
fn clone_boxed(&self) -> BoxAnyVarValue {
BoxAnyVarValue::new(self.clone())
}
fn eq_any(&self, other: &dyn AnyVarValue) -> bool {
match other.downcast_ref::<T>() {
Some(o) => self == o,
None => false,
}
}
#[cfg(feature = "type_names")]
fn type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
fn try_swap(&mut self, other: &mut dyn AnyVarValue) -> bool {
if let Some(other) = other.downcast_mut::<T>() {
std::mem::swap(self, other);
return true;
}
false
}
}
pub trait VarValue: AnyVarValue + Clone + PartialEq {}
impl<T: AnyVarValue + Clone + PartialEq> VarValue for T {}
pub struct ArcEq<T: fmt::Debug + Send + Sync>(pub Arc<T>);
impl<T: fmt::Debug + Send + Sync> ops::Deref for ArcEq<T> {
type Target = Arc<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: fmt::Debug + Send + Sync> ArcEq<T> {
pub fn new(value: T) -> Self {
Self(Arc::new(value))
}
}
impl<T: fmt::Debug + Send + Sync> PartialEq for ArcEq<T> {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl<T: fmt::Debug + Send + Sync> Eq for ArcEq<T> {}
impl<T: fmt::Debug + Send + Sync> Clone for ArcEq<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<T: fmt::Debug + Send + Sync> fmt::Debug for ArcEq<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.0, f)
}
}
#[derive(Clone)]
pub struct VarEq<T: VarValue>(pub crate::Var<T>);
impl<T: VarValue> ops::Deref for VarEq<T> {
type Target = crate::Var<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: VarValue> fmt::Debug for VarEq<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl<T: VarValue> PartialEq for VarEq<T> {
fn eq(&self, other: &Self) -> bool {
self.0.var_eq(&other.0)
}
}
#[diagnostic::on_unimplemented(
note = "`IntoValue<T>` is implemented for all `T: VarValue`",
note = "you can use `impl_from_and_into_var!` to implement conversions"
)]
pub trait IntoValue<T: VarValue>: Into<T> {}
impl<T: VarValue> IntoValue<T> for T {}