use std::{any::{Any, TypeId}, fmt::Debug, mem};
use downcast_rs::{impl_downcast, Downcast};
const _: Option<Box<dyn DynObject>> = None;
pub trait DynObject: Downcast + Debug + Send + Sync + 'static {
fn dyn_clone(&self) -> Box<dyn DynObject>;
fn dyn_eq(&self, other: &dyn DynObject) -> bool;
}
impl_downcast!(DynObject);
impl Clone for Box<dyn DynObject> {
fn clone(&self) -> Self {
self.as_ref().dyn_clone()
}
}
impl PartialEq for dyn DynObject {
fn eq(&self, other: &Self) -> bool {
self.dyn_eq(other)
}
}
impl<T> DynObject for T where T: Debug + Clone + PartialEq + Send + Sync + 'static{
fn dyn_clone(&self) -> Box<dyn DynObject> {
Box::new(self.clone())
}
fn dyn_eq(&self, other: &dyn DynObject) -> bool {
match other.downcast_ref::<T>() {
Some(some) => some == self,
None => false,
}
}
}
pub trait AsObject: Sized + Debug + Clone + Send + Sync + 'static {
fn cloned(obj: &Object) -> Option<Self>;
fn get_ref(obj: &Object) -> Option<&Self>;
fn get_mut(obj: &mut Object) -> Option<&mut Self>;
fn from_object(obj: Object) -> Option<Self>;
fn into_object(self) -> Object;
fn as_dyn_inner(&self) -> Option<&dyn DynObject>;
}
impl<T> AsObject for T where T: DynObject + Clone {
fn cloned(obj: &Object) -> Option<Self> {
if TypeId::of::<T>() == TypeId::of::<Object>() {
if obj.is_none() { return None; };
Some((obj as &dyn Any).downcast_ref::<T>().unwrap().clone())
} else {
obj.0.as_ref().and_then(|x| x.downcast_ref::<T>().cloned())
}
}
fn get_ref(obj: &Object) -> Option<&Self> {
if TypeId::of::<T>() == TypeId::of::<Object>() {
if obj.is_none() { return None; };
Some((obj as &dyn Any).downcast_ref::<T>().unwrap())
} else {
obj.0.as_ref().and_then(|x| x.downcast_ref())
}
}
fn get_mut(obj: &mut Object) -> Option<&mut Self> {
if TypeId::of::<T>() == TypeId::of::<Object>() {
if obj.is_none() { return None; };
Some((obj as &mut dyn Any).downcast_mut::<T>().unwrap())
} else {
obj.0.as_mut().and_then(|x| x.downcast_mut())
}
}
fn from_object(obj: Object) -> Option<Self> {
if TypeId::of::<T>() == TypeId::of::<Object>() {
if obj.is_none() { return None; };
Some(*(Box::new(obj) as Box<dyn Any>).downcast::<T>().unwrap())
} else {
obj.0.and_then(|x| x.downcast().map(|x| *x).ok())
}
}
fn into_object(self) -> Object {
if TypeId::of::<T>() == TypeId::of::<Object>() {
*(Box::new(self) as Box<dyn Any>).downcast::<Object>().unwrap()
} else {
Object(Some(Box::new(self)))
}
}
fn as_dyn_inner(&self) -> Option<&dyn DynObject> {
if TypeId::of::<T>() == TypeId::of::<Object>() {
(self as &dyn Any)
.downcast_ref::<Object>()
.unwrap()
.0
.as_ref()
.map(|x| x.as_ref())
} else {
Some(self)
}
}
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Object(Option<Box<dyn DynObject>>);
impl Object {
pub const NONE: Self = Self(None);
pub fn unnameable() -> Self {
#[derive(Debug, Clone)]
struct UnnameableUnequal;
impl PartialEq for UnnameableUnequal{
fn eq(&self, _: &Self) -> bool {
false
}
}
Self(Some(Box::new(UnnameableUnequal)))
}
pub fn new<T: AsObject>(v: T) -> Self {
AsObject::into_object(v)
}
pub fn is_some(&self) -> bool {
self.0.is_some()
}
pub fn is_none(&self) -> bool {
self.0.is_none()
}
pub fn cloned<T: AsObject>(&self) -> Option<T> {
AsObject::cloned(self)
}
pub fn get_ref<T: AsObject>(&self) -> Option<&T> {
AsObject::get_ref(self)
}
pub fn get_mut<T: AsObject>(&mut self) -> Option<&mut T> {
AsObject::get_mut(self)
}
pub fn clear(&mut self) {
self.0.take();
}
pub fn take<T: AsObject>(&mut self) -> Option<T> {
AsObject::from_object(mem::take(self))
}
pub fn set<T: AsObject>(&mut self, v: T) {
*self = AsObject::into_object(v)
}
pub fn replace<A: AsObject, B: AsObject>(&mut self, v: A) -> Option<B>{
let original = self.take();
self.set(v);
original
}
pub fn or<T: AsObject>(self, item: T) -> Object {
if self.is_none() {
Object::new(item)
} else {
self
}
}
pub fn or_else<T: AsObject>(self, item: impl Fn() -> T) -> Object {
if self.is_none() {
Object::new(item())
} else {
self
}
}
pub fn equals<T: AsObject>(&self, other: &T) -> bool {
match (&self.0, other.as_dyn_inner()) {
(None, None) => true,
(Some(a), Some(b)) => a.as_ref().dyn_eq(b),
_ => false
}
}
}