use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::{IntoNodeRef, Data, SData, SDataRef, SDoc, SGraph, SNodeRef};
use super::{lang::CustomType, SField, SVal};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SPrototype {
pub prototype: String,
}
#[typetag::serde(name = "_SProto")]
impl Data for SPrototype {}
impl IntoNodeRef for SPrototype {
fn node_ref(&self) -> SNodeRef {
SNodeRef::from(&self.prototype)
}
}
impl SPrototype {
pub fn new(node: impl IntoNodeRef) -> Self {
Self {
prototype: node.node_ref().id,
}
}
pub fn get(graph: &SGraph, node: impl IntoNodeRef) -> Option<&Self> {
if let Some(node) = node.node_ref().node(graph) {
for proto in node.data::<Self>(graph) {
return Some(proto);
}
}
None
}
pub fn get_ref(graph: &SGraph, node: impl IntoNodeRef) -> Option<SDataRef> {
if let Some(node) = node.node_ref().node(graph) {
for dref in &node.data {
if let Some(_proto) = SData::get::<SPrototype>(graph, dref) {
return Some(dref.clone());
}
}
}
None
}
pub fn get_stack(graph: &SGraph, node: impl IntoNodeRef) -> Vec<SNodeRef> {
let mut stack = Vec::new();
if let Some(node) = node.node_ref().node(graph) {
let mut current = None;
for proto in node.data::<Self>(graph) {
current = Some(proto.node_ref());
}
while let Some(proto) = current {
if let Some(node) = proto.node(graph) {
if node.name != "__stof__" && node.name != "prototypes" {
stack.push(proto);
} else {
break;
}
if let Some(parent_ref) = &node.parent {
current = Some(parent_ref.clone());
} else {
break;
}
} else {
break;
}
}
}
stack
}
pub fn typepath(&self, graph: &SGraph) -> Option<String> {
if let Some(typepath) = SField::field(graph, "typepath", '.', Some(&self.node_ref())) {
return Some(typepath.to_string());
}
None
}
pub fn typepath_stack(&self, graph: &SGraph) -> Vec<String> {
let mut type_stack = Vec::new();
let mut current = Some(self.node_ref());
while let Some(typename) = SField::field(graph, "typepath", '.', current.as_ref()) {
type_stack.push(typename.to_string());
if let Some(node) = current.unwrap().node(graph) {
if let Some(parent_ref) = &node.parent {
current = Some(parent_ref.clone());
} else {
break;
}
} else {
break;
}
}
type_stack
}
pub fn typename(&self, graph: &SGraph) -> Option<String> {
if let Some(typename) = SField::field(graph, "typename", '.', Some(&self.node_ref())) {
return Some(typename.to_string());
}
None
}
pub fn type_stack(&self, graph: &SGraph) -> Vec<String> {
let mut type_stack = Vec::new();
let mut current = Some(self.node_ref());
while let Some(typename) = SField::field(graph, "typename", '.', current.as_ref()) {
type_stack.push(typename.to_string());
if let Some(node) = current.unwrap().node(graph) {
if let Some(parent_ref) = &node.parent {
current = Some(parent_ref.clone());
} else {
break;
}
} else {
break;
}
}
type_stack
}
pub fn custom_type<'a>(&self, doc: &'a SDoc) -> Option<&'a CustomType> {
if let Some(typename) = self.typename(&doc.graph) {
if let Some(ctypes) = doc.types.types.get(&typename) {
for ctype in ctypes {
if ctype.locid == self.prototype {
return Some(ctype);
}
}
}
}
None
}
pub fn attributes(&self, doc: &SDoc) -> BTreeMap<String, SVal> {
if let Some(ctype) = self.custom_type(doc) {
return ctype.attributes.clone();
}
BTreeMap::default()
}
}