use std::{any::Any, collections::HashSet};
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use super::{IntoDataRef, IntoNodeRef, SDataRef, SGraph, SNodeRef};
pub const DATA_DIRTY_VAL: &str = "value";
pub const DATA_DIRTY_NODES: &str = "nodes";
#[typetag::serde]
pub trait Data: AsDynAny + std::fmt::Debug + DataClone + Send + Sync {}
#[typetag::serde(name = "_String")]
impl Data for String {}
#[typetag::serde(name = "_None")]
impl Data for () {}
pub trait DataClone {
fn clone_data(&self) -> Box<dyn Data>;
}
impl<T: Data + Clone + 'static> DataClone for T {
fn clone_data(&self) -> Box<dyn Data> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn Data> {
fn clone(&self) -> Box<dyn Data> {
self.clone_data()
}
}
pub trait AsDynAny {
fn as_dyn_any(&self) -> &dyn Any;
fn as_mut_dyn_any(&mut self) -> &mut dyn Any;
}
impl<T: Data + Any> AsDynAny for T {
fn as_dyn_any(&self) -> &dyn Any {
self
}
fn as_mut_dyn_any(&mut self) -> &mut dyn Any {
self
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SData {
pub id: String,
pub nodes: Vec<SNodeRef>,
pub data: Box<dyn Data>,
#[serde(skip)]
pub dirty: HashSet<String>,
}
impl SData {
pub fn new_id(id: &str, data: Box<dyn Data>) -> Self {
Self {
id: id.to_owned(),
nodes: Default::default(),
dirty: Default::default(),
data,
}
}
pub fn new(data: Box<dyn Data>) -> Self {
Self {
id: format!("dta{}", nanoid!()),
nodes: Default::default(),
dirty: Default::default(),
data,
}
}
pub fn new_reference(&mut self, node: SNodeRef) {
self.nodes.push(node);
self.invalidate(DATA_DIRTY_NODES);
}
pub fn ref_removed(&mut self, node: &SNodeRef) {
self.nodes.retain(|x| x.id != node.id);
self.invalidate(DATA_DIRTY_NODES);
}
pub fn ref_count(&self) -> usize {
self.nodes.len()
}
pub fn invalidate(&mut self, symbol: &str) {
self.dirty.insert(symbol.to_owned());
}
pub fn invalidate_val(&mut self) {
self.invalidate(DATA_DIRTY_VAL);
}
pub fn validate_val(&mut self) -> bool {
self.validate(DATA_DIRTY_VAL)
}
pub fn dirty_val(&self) -> bool {
self.dirty(DATA_DIRTY_VAL)
}
pub fn dirty(&self, symbol: &str) -> bool {
self.dirty.contains(symbol)
}
pub fn validate(&mut self, symbol: &str) -> bool {
self.dirty.remove(symbol)
}
pub fn has_dirty(&self) -> bool {
self.dirty.len() > 0
}
pub fn insert_new_id(graph: &mut SGraph, node: impl IntoNodeRef, data: Box<dyn Data>, id: &str) -> Option<SDataRef> {
let dta = Self::new_id(id, data);
dta.insert(graph, node)
}
pub fn insert_new(graph: &mut SGraph, node: impl IntoNodeRef, data: Box<dyn Data>) -> Option<SDataRef> {
let dta = Self::new(data);
dta.insert(graph, node)
}
pub fn insert(self, graph: &mut SGraph, node: impl IntoNodeRef) -> Option<SDataRef> {
graph.put_data(node, self)
}
pub fn attach_existing(graph: &mut SGraph, node: impl IntoNodeRef, data: impl IntoDataRef) -> bool {
let nref = node.node_ref();
if nref.exists(graph) {
return graph.put_data_ref(node, data);
}
false
}
pub fn attach(&self, graph: &mut SGraph, node: impl IntoNodeRef) -> bool {
let nref = node.node_ref();
if nref.exists(graph) {
return graph.put_data_ref(node, &self.id);
}
false
}
pub fn is_type_of<T: Any>(&self) -> bool {
if let Some(_) = self.get_data::<T>() {
return true;
}
false
}
pub fn type_of<T: Any>(graph: &SGraph, dref: impl IntoDataRef) -> bool {
if let Some(sdata) = dref.data_ref().data(graph) {
return sdata.is_type_of::<T>();
}
false
}
pub fn set_data(&mut self, data: Box<dyn Data>) {
self.data = data;
self.invalidate_val();
}
pub fn set(graph: &mut SGraph, dref: impl IntoDataRef, data: Box<dyn Data>) -> bool {
if let Some(sdata) = dref.data_ref().data_mut(graph) {
sdata.set_data(data);
return true;
}
false
}
pub fn get_data<T: Any>(&self) -> Option<&T> {
let any = self.data.as_dyn_any();
if let Some(data) = any.downcast_ref::<T>() {
Some(data)
} else {
None
}
}
pub fn get_data_mut<T: Any>(&mut self) -> Option<&mut T> {
let any = self.data.as_mut_dyn_any();
if let Some(data) = any.downcast_mut::<T>() {
Some(data)
} else {
None
}
}
pub fn get<T: Any>(graph: &SGraph, into_ref: impl IntoDataRef) -> Option<&T> {
if let Some(data) = into_ref.data_ref().data(graph) {
return data.get_data::<T>();
}
None
}
pub fn get_mut<T: Any>(graph: &mut SGraph, into_ref: impl IntoDataRef) -> Option<&mut T> {
if let Some(data) = into_ref.data_ref().data_mut(graph) {
return data.get_data_mut::<T>();
}
None
}
}