use std::collections::{BTreeMap, HashSet};
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use crate::{SData, SField, SFunc, SGraph, SNodeRef, SPrototype, SType, SVal};
use super::Expr;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomType {
pub locid: String,
pub decid: String,
pub name: String,
pub fields: Vec<CustomTypeField>,
pub attributes: BTreeMap<String, SVal>,
}
impl CustomType {
pub fn new(decid: &str, name: &str, fields: Vec<CustomTypeField>) -> Self {
Self {
name: name.to_owned(),
fields,
locid: format!("ctl{}", nanoid!(10)),
decid: decid.to_owned(),
attributes: Default::default(),
}
}
pub fn is_private(&self) -> bool {
return self.attributes.contains_key("private");
}
pub fn prototype(&self) -> SPrototype {
SPrototype::new(&self.locid)
}
pub fn fieldnames(&self) -> HashSet<String> {
let mut names = HashSet::new();
for param in &self.fields {
names.insert(param.name.clone());
}
names
}
pub fn typepath(&self, graph: &SGraph) -> String {
let typepath = SNodeRef::new(&self.decid).path(&graph).replace('/', ".");
format!("{}.{}", typepath, self.name)
}
pub fn insert(&mut self, graph: &mut SGraph, location: &str, functions: Vec<SFunc>) {
let nref = graph.ensure_nodes(location, '/', true, None);
self.locid = nref.id.clone();
for f in functions {
SData::insert_new(graph, &nref, Box::new(f));
}
if let Some(typename_field_ref) = SField::field_ref(graph, "typename", '.', Some(&nref)) {
if let Some(field) = SData::get_mut::<SField>(graph, &typename_field_ref) {
field.value = SVal::String(self.name.clone());
}
} else {
SField::new_string(graph, "typename", &self.name, &nref);
}
let typepath = SNodeRef::new(&self.decid).path(&graph).replace('/', ".");
if let Some(typepath_field_ref) = SField::field_ref(graph, "typepath", '.', Some(&nref)) {
if let Some(field) = SData::get_mut::<SField>(graph, &typepath_field_ref) {
field.value = SVal::String(format!("{}.{}", typepath, self.name));
}
} else {
SField::new_string(graph, "typepath", &format!("{}.{}", typepath, self.name), &nref);
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomTypeField {
pub name: String,
pub ptype: SType,
pub default: Option<Expr>,
pub optional: bool,
pub attributes: BTreeMap<String, SVal>,
}
impl CustomTypeField {
pub fn new(name: &str, ptype: SType, default: Option<Expr>, attrs: BTreeMap<String, SVal>, optional: bool) -> Self {
Self {
name: name.into(),
ptype,
default,
optional,
attributes: attrs,
}
}
}