use std::any::{type_name, Any, TypeId};
use std::ffi::c_void;
use std::fmt::{Binary, Debug, Formatter, Octal, UpperHex};
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use parking_lot::lock_api::{MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLockReadGuard};
use parking_lot::{RawRwLock, RwLock, RwLockWriteGuard};
use crate::{AnyValue, PhlowExtension, PhlowView, PhlowViewMethod, PrintExtensions};
pub type PhlowObjectId = i64;
#[derive(Clone)]
pub struct PhlowObject(Arc<PhlowObjectData>);
struct PhlowObjectData {
parent: Option<PhlowObject>,
value: RwLock<AnyValue>,
phlow_type: PhlowType,
generic_types: Vec<PhlowType>,
#[cfg(feature = "object-id")]
id: PhlowObjectId,
}
impl PhlowObject {
pub fn object<T: Any>(
object: T,
phlow_extensions_fn: impl Fn(&T) -> Vec<PhlowExtension> + 'static,
) -> Self {
let phlow_type = PhlowType::new::<T>(|| phlow_extensions_fn(&object));
Self::new(AnyValue::object(object), phlow_type, vec![], None)
}
pub fn object_with_generics<T: 'static>(
object: T,
phlow_extensions_fn: impl Fn(&T) -> Vec<PhlowExtension> + 'static,
generic_types: Vec<PhlowType>,
) -> Self {
let phlow_type = PhlowType::new::<T>(|| phlow_extensions_fn(&object));
Self::new(AnyValue::object(object), phlow_type, generic_types, None)
}
pub fn reference<T: 'static>(
object: &T,
parent: &PhlowObject,
phlow_extensions_fn: impl Fn(&T) -> Vec<PhlowExtension> + 'static,
) -> Self {
let phlow_type = PhlowType::new::<T>(|| phlow_extensions_fn(object));
Self::new(
AnyValue::reference(object),
phlow_type,
vec![],
Some(parent.clone()),
)
}
pub fn construct_reference<T: 'static>(
reference: &T,
phlow_type: PhlowType,
parent: Option<PhlowObject>,
) -> Self {
Self::new(AnyValue::reference(reference), phlow_type, vec![], parent)
}
pub fn new(
value: AnyValue,
phlow_type: PhlowType,
generic_types: Vec<PhlowType>,
parent: Option<PhlowObject>,
) -> Self {
Self(Arc::new(PhlowObjectData {
parent,
value: RwLock::new(value),
phlow_type,
generic_types,
#[cfg(feature = "object-id")]
id: unique_id::Generator::<i64>::next_id(
&unique_id::sequence::SequenceGenerator::default(),
),
}))
}
pub fn phlow_type(&self) -> &PhlowType {
&self.0.phlow_type
}
pub fn generic_phlow_type(&self, index: usize) -> Option<PhlowType> {
self.0.generic_types.get(index).cloned()
}
pub fn generic_phlow_types(&self) -> &[PhlowType] {
self.0.generic_types.as_slice()
}
pub fn to_string(&self) -> String {
self.with_value(|value| self.0.phlow_type.value_to_string(value))
}
#[cfg(feature = "object-id")]
pub fn object_id(&self) -> PhlowObjectId {
self.0.id
}
pub fn has_value(&self) -> bool {
self.0.value.read().has_value()
}
pub fn take_value<T: Any>(&self) -> Option<T> {
let mut writer = self.0.value.write();
let previous = std::mem::replace(&mut *writer, AnyValue::None);
previous.take_value()
}
pub fn replace_value<T: Any>(&self, object: T) -> Option<T> {
let mut writer = self.0.value.write();
let previous = std::mem::replace(&mut *writer, AnyValue::object(object));
previous.take_value()
}
pub fn clone_value<T: Any + Clone>(&self) -> Option<T> {
self.0.value.read().clone_value()
}
pub fn with_value<R>(&self, op: impl FnOnce(&AnyValue) -> R) -> R {
op(&self.0.value.read())
}
pub fn value(&self) -> RwLockReadGuard<'_, RawRwLock, AnyValue> {
self.0.value.read()
}
pub fn value_mut<T: Any>(&self) -> Option<MappedRwLockWriteGuard<'_, RawRwLock, T>> {
RwLockWriteGuard::try_map(self.0.value.write(), |value| value.as_mut_safe())
.map(|reference| Some(reference))
.unwrap_or(None)
}
pub fn value_ref<T: Any>(&self) -> Option<MappedRwLockReadGuard<'_, RawRwLock, T>> {
RwLockReadGuard::try_map(self.0.value.read(), |value| value.as_ref_safe())
.map(|reference| Some(reference))
.unwrap_or(None)
}
pub fn value_ptr(&self) -> *const c_void {
self.value().as_ptr()
}
pub fn value_type_name(&self) -> &str {
self.0.phlow_type.type_name()
}
pub fn parent(&self) -> Option<&PhlowObject> {
self.0.parent.as_ref()
}
pub fn phlow_view_methods(&self) -> Vec<PhlowViewMethod> {
self.0
.phlow_type
.phlow_extensions
.iter()
.map(|extension| extension.view_methods())
.flatten()
.collect()
}
pub fn phlow_view_named(&self, name: impl AsRef<str>) -> Option<Box<dyn PhlowView>> {
let target_name: &str = name.as_ref();
self.phlow_view_methods()
.into_iter()
.find(|each_method| each_method.method_name.as_str() == target_name)
.and_then(|each_method| each_method.as_view(&self))
}
pub fn phlow_views(&self) -> Vec<Box<dyn PhlowView>> {
self.phlow_view_methods()
.into_iter()
.map(|each_method| each_method.as_view(&self))
.filter(|each_view| each_view.is_some())
.map(|each_view| each_view.unwrap())
.collect()
}
}
impl Debug for PhlowObject {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct(type_name::<Self>())
.field("extensions", &self.phlow_view_methods())
.finish()
}
}
pub trait AsPhlowObject {
fn is_phlow_object(&self) -> bool;
fn try_into_phlow_object(&self) -> Option<PhlowObject>;
}
impl<T> AsPhlowObject for T {
default fn is_phlow_object(&self) -> bool {
false
}
default fn try_into_phlow_object(&self) -> Option<PhlowObject> {
None
}
}
impl AsPhlowObject for PhlowObject {
fn is_phlow_object(&self) -> bool {
true
}
fn try_into_phlow_object(&self) -> Option<PhlowObject> {
Some(self.clone())
}
}
impl AsPhlowObject for &PhlowObject {
fn is_phlow_object(&self) -> bool {
true
}
fn try_into_phlow_object(&self) -> Option<PhlowObject> {
(*self).try_into_phlow_object()
}
}
pub struct TypedPhlowObject<'value, T: 'static> {
object: &'value PhlowObject,
reference: &'value T,
}
impl<'value, T: 'static> TypedPhlowObject<'value, T> {
pub fn new(object: &'value PhlowObject, reference: &'value T) -> Self {
Self { reference, object }
}
pub fn phlow_object(&self) -> &PhlowObject {
&self.object
}
}
impl<'value, T: 'static> AsRef<T> for TypedPhlowObject<'value, T> {
fn as_ref(&self) -> &'value T {
self.reference
}
}
impl<'value, T: 'static> Deref for TypedPhlowObject<'value, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.reference
}
}
impl<'value, T: 'static> ToString for TypedPhlowObject<'value, T> {
fn to_string(&self) -> String {
self.object.to_string()
}
}
impl<'value, T: Debug + 'static> Debug for TypedPhlowObject<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.reference, f)
}
}
impl<'value, T: UpperHex + 'static> UpperHex for TypedPhlowObject<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
UpperHex::fmt(self.reference, f)
}
}
impl<'value, T: Octal + 'static> Octal for TypedPhlowObject<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Octal::fmt(self.reference, f)
}
}
impl<'value, T: Binary + 'static> Binary for TypedPhlowObject<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Binary::fmt(self.reference, f)
}
}
pub struct TypedPhlowObjectMut<'value, T: 'static> {
object: &'value PhlowObject,
reference: &'value mut T,
}
impl<'value, T: 'static> TypedPhlowObjectMut<'value, T> {
pub fn new(object: &'value PhlowObject, reference: &'value mut T) -> Self {
Self { reference, object }
}
pub fn phlow_object(&self) -> &PhlowObject {
&self.object
}
}
impl<'value, T: 'static> AsRef<T> for TypedPhlowObjectMut<'value, T> {
fn as_ref(&self) -> &T {
self.reference
}
}
impl<'value, T: 'static> AsMut<T> for TypedPhlowObjectMut<'value, T> {
fn as_mut(&mut self) -> &mut T {
self.reference
}
}
impl<'value, T: 'static> Deref for TypedPhlowObjectMut<'value, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.reference
}
}
impl<'value, T: 'static> DerefMut for TypedPhlowObjectMut<'value, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.reference
}
}
impl<'value, T: 'static> ToString for TypedPhlowObjectMut<'value, T> {
fn to_string(&self) -> String {
self.object.to_string()
}
}
impl<'value, T: Debug + 'static> Debug for TypedPhlowObjectMut<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.reference, f)
}
}
impl<'value, T: UpperHex + 'static> UpperHex for TypedPhlowObjectMut<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
UpperHex::fmt(self.reference, f)
}
}
impl<'value, T: Octal + 'static> Octal for TypedPhlowObjectMut<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Octal::fmt(self.reference, f)
}
}
impl<'value, T: Binary + 'static> Binary for TypedPhlowObjectMut<'value, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Binary::fmt(self.reference, f)
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct PhlowType {
type_name: &'static str,
type_id: TypeId,
phlow_extensions: Vec<PhlowExtension>,
print_extensions: PrintExtensions,
}
impl PhlowType {
pub fn of<T: 'static>(
value: &T,
phlow_extensions_fn: impl Fn(&T) -> Vec<PhlowExtension> + 'static,
) -> Self {
Self::new::<T>(|| phlow_extensions_fn(value))
}
pub fn new<T: 'static>(phlow_extensions_fn: impl Fn() -> Vec<PhlowExtension>) -> Self {
let phlow_extensions = phlow_extensions_fn();
let print_extensions = PrintExtensions::new::<T>();
Self {
type_name: type_name::<T>(),
type_id: TypeId::of::<T>(),
phlow_extensions,
print_extensions,
}
}
pub fn type_name(&self) -> &str {
self.type_name
}
pub fn value_to_string(&self, value: &AnyValue) -> String {
self.print_extensions.to_string(value)
}
}