use crate::{DefiningMethod, ObjectRef, PhlowView};
use annotate::Function;
use std::any::{Any, type_name};
use std::fmt::{Debug, Formatter};
use std::ops::Deref;
use std::sync::Arc;
#[repr(transparent)]
pub struct PhlowObject<T: ?Sized = dyn Any>(Arc<T>);
impl<T: 'static> PhlowObject<T> {
pub fn as_any(&self) -> AnyObject {
AnyObject(self.0.clone())
}
}
impl PhlowObject {
pub fn from_any(object: AnyObject) -> Self {
Self(object.0)
}
}
impl<T> From<T> for PhlowObject<T> {
fn from(value: T) -> Self {
Self(Arc::new(value))
}
}
impl<T: ?Sized> From<Arc<T>> for PhlowObject<T> {
fn from(value: Arc<T>) -> Self {
Self(value)
}
}
impl<T: ?Sized> AsRef<T> for PhlowObject<T> {
fn as_ref(&self) -> &T {
self.0.as_ref()
}
}
impl<T: ?Sized> Clone for PhlowObject<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: ?Sized> Deref for PhlowObject<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: ?Sized> Debug for PhlowObject<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("PhlowObject")
}
}
#[repr(transparent)]
#[derive(Clone)]
pub struct AnyObject(Arc<dyn Any>);
impl AnyObject {
pub fn new<T: Any>(object: T) -> Self {
Self(Arc::new(object))
}
pub fn downcast<T: 'static>(self) -> PhlowObject<T> {
if self.0.is::<T>() {
let raw = Arc::into_raw(self.0) as *const T;
unsafe { Arc::from_raw(raw).into() }
} else {
panic!("Failed to downcast AnyObject to {}", type_name::<T>());
}
}
}
impl From<Arc<dyn Any>> for AnyObject {
fn from(value: Arc<dyn Any>) -> Self {
Self(value)
}
}
impl From<Box<dyn Any>> for AnyObject {
fn from(value: Box<dyn Any>) -> Self {
Self(Arc::from(value))
}
}
impl From<AnyObject> for PhlowObject {
fn from(value: AnyObject) -> Self {
Self::from_any(value)
}
}
impl Deref for AnyObject {
type Target = dyn Any;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Debug for AnyObject {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("AnyObject")
}
}
#[repr(transparent)]
pub struct AnySendObject(Box<dyn Any + Send>);
impl AnySendObject {
pub fn new<T: Send + 'static>(object: T) -> Self {
Self(Box::new(object))
}
pub fn downcast_ref<T: 'static>(&self) -> &T {
self.0
.downcast_ref()
.unwrap_or_else(|| panic!("Failed to downcast AnySendObject to {}", type_name::<T>()))
}
pub fn as_any(&self) -> &dyn Any {
self.0.as_ref()
}
}
pub struct PhlowVTable {
pub type_name_fn: Option<Function>,
pub to_string_fn: Option<Function>,
pub as_view_fn: Option<Function>,
pub defining_methods_fn: Option<Function>,
}
impl PhlowVTable {
pub fn supports_type_name(&self) -> bool {
self.type_name_fn.is_some()
}
pub fn type_name(&self) -> Option<&'static str> {
self.type_name_fn
.as_ref()
.map(|f| f.call::<fn() -> &'static str, _>(|f| f()))
}
pub fn supports_to_string(&self) -> bool {
self.to_string_fn.is_some()
}
pub fn to_string(&self, object: ObjectRef<'_>) -> Option<String> {
self.to_string_fn
.as_ref()
.map(|f| f.call::<fn(ObjectRef<'_>) -> String, _>(|f| f(object)))
}
pub fn view_defining_methods_for_type(&self) -> Vec<DefiningMethod> {
self.defining_methods_fn
.as_ref()
.map(|f| f.call::<fn() -> Vec<DefiningMethod>, _>(|f| f()))
.unwrap_or_default()
}
pub fn defining_method_as_view(
&self,
method: &DefiningMethod,
object: ObjectRef<'_>,
) -> Option<Box<dyn PhlowView>> {
self.as_view_fn.as_ref().map(|f| {
f.call::<fn(&DefiningMethod, ObjectRef<'_>) -> Box<dyn PhlowView>, _>(|f| {
f(method, object)
})
})
}
pub fn views(&self, object: ObjectRef<'_>) -> Vec<Box<dyn PhlowView>> {
self.view_defining_methods_for_type()
.iter()
.filter_map(move |method| self.defining_method_as_view(method, object))
.collect()
}
}