use crate::components::context::Context;
use crate::components::r#type::type_system::TypeSystem;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt::Debug;
use std::ops::Add;
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound = "T: Serialize + for<'a> Deserialize<'a>")]
pub struct Graph<T: TypeSystem> {
memory: Arc<HashSet<T>>,
root: Arc<Node<T>>,
#[serde(skip)]
subtype_cache: Arc<HashMap<(T, T), bool>>,
}
impl<T: TypeSystem> Default for Graph<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: TypeSystem> Graph<T> {
pub fn new() -> Self {
Graph {
memory: Arc::new(HashSet::new()),
root: Arc::new(Node::new()),
subtype_cache: Arc::new(HashMap::new()),
}
}
pub fn check_subtype_cache(&self, t1: &T, t2: &T) -> Option<bool> {
self.subtype_cache.get(&(t1.clone(), t2.clone())).copied()
}
pub fn cache_subtype(self, t1: T, t2: T, result: bool) -> Self {
let mut subtype_cache = Arc::unwrap_or_clone(self.subtype_cache);
subtype_cache.insert((t1, t2), result);
Graph {
memory: self.memory,
root: self.root,
subtype_cache: Arc::new(subtype_cache),
}
}
pub fn add_type(self, typ: T, context: &Context) -> Self {
if self.memory.contains(&typ) {
self
} else {
let root = Arc::unwrap_or_clone(self.root);
let new_root = root.add_type(typ.clone(), context);
let mut new_memory = Arc::unwrap_or_clone(self.memory);
new_memory.insert(typ);
Graph {
memory: Arc::new(new_memory),
root: Arc::new(new_root),
subtype_cache: self.subtype_cache,
}
}
}
pub fn get_hierarchy(&self) -> String {
self.root.get_hierarchy()
}
pub fn structure_debug(&self) -> String {
format!("{:?}", self.root)
}
pub fn get_supertypes(&self, typ: &T, context: &Context) -> Vec<T> {
self.get_ordered_supertypes(typ, context)
}
pub fn get_ordered_supertypes(&self, typ: &T, context: &Context) -> Vec<T> {
let raw = self.root.get_supertypes(typ, context);
let mut seen = HashSet::new();
let mut result = Vec::new();
for item in raw {
if seen.insert(item.clone()) {
result.push(item);
}
}
result
}
pub fn add_types(self, typs: &[T], context: &Context) -> Self {
typs.iter().cloned().fold(self, |acc, x| acc.add_type(x, context))
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound = "T: Serialize + for<'a> Deserialize<'a>")]
pub struct Node<T: TypeSystem> {
value: T,
subtypes: Vec<Node<T>>,
}
impl<T: TypeSystem> From<T> for Node<T> {
fn from(val: T) -> Self {
Node {
value: val,
subtypes: vec![],
}
}
}
impl<T: TypeSystem> Default for Node<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: TypeSystem> Node<T> {
pub fn new() -> Self {
Node {
value: T::default(),
subtypes: vec![],
}
}
pub fn propagate(self, typ: T, context: &Context) -> Self {
let graph = Node {
value: self.value.clone(),
subtypes: self
.subtypes
.iter()
.cloned()
.map(|x| x.add_type(typ.clone(), context))
.collect(),
};
if graph == self {
self.add_subtype(typ)
} else {
graph
}
}
pub fn add_subtype(self, typ: T) -> Self {
Node {
value: self.value,
subtypes: self.subtypes.iter().chain([Node::from(typ)].iter()).cloned().collect(),
}
}
pub fn set_subtypes(self, subtypes: Vec<Node<T>>) -> Self {
Node {
value: self.value,
subtypes,
}
}
fn switch_if_reverse_subtype(self, typ: T, context: &Context) -> Self {
if self.value.is_subtype_raw(&typ, context) {
Node {
value: typ,
subtypes: vec![Node::from(self.value).set_subtypes(self.subtypes)],
}
} else {
self
}
}
pub fn add_type(self, typ: T, context: &Context) -> Self {
if self.value == typ {
self
} else {
match (typ.is_subtype_raw(&self.value, context), self.subtypes.len()) {
(true, 0) => self.add_subtype(typ),
(true, _) => self.propagate(typ, context),
_ => self.switch_if_reverse_subtype(typ, context),
}
}
}
pub fn get_supertypes(&self, target_type: &T, context: &Context) -> Vec<T> {
if target_type == &self.value {
vec![]
} else if target_type.is_subtype_raw(&self.value, context) {
self.subtypes
.iter()
.flat_map(|x| x.get_supertypes(target_type, context))
.chain([self.value.clone()].iter().cloned())
.collect::<Vec<T>>()
} else {
vec![]
}
}
pub fn get_hierarchy(&self) -> String {
self.get_hierarchy_helper(0)
}
fn tabulation_from_level(level: i32) -> String {
(0..level).map(|_| " ").collect::<Vec<_>>().join("")
}
pub fn get_hierarchy_helper(&self, level: i32) -> String {
let tab = Node::<T>::tabulation_from_level(level);
let children = self
.subtypes
.iter()
.map(|x| x.get_hierarchy_helper(level + 1))
.collect::<Vec<_>>()
.join("\n");
tab + &self.value.pretty() + "\n" + &children
}
}
use std::fmt;
impl<T: TypeSystem> fmt::Display for Node<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.get_hierarchy())
}
}
impl<T: TypeSystem> Add for Graph<T> {
type Output = Self;
fn add(self, other: Self) -> Self {
let context = Context::default(); let merged = other
.memory
.iter()
.cloned()
.fold(self.clone(), |acc, typ| acc.add_type(typ, &context));
let mut new_cache = Arc::unwrap_or_clone(self.subtype_cache);
new_cache.extend(other.subtype_cache.iter().map(|(k, v)| (k.clone(), *v)));
Graph {
subtype_cache: Arc::new(new_cache),
..merged
}
}
}