use crate::node_types::rust_names::PrevNodeRustNames;
use crate::vec_set::VecSet;
use crate::{NodeName, NodeRustNames};
use serde::Deserialize;
use std::borrow::{Borrow, Cow};
use std::collections::{BTreeMap, BTreeSet};
use std::ops::{BitOrAssign, Index};
use std::path::{Path, PathBuf};
use super::deserialize_json_array_as_stream::iter_json_array;
#[derive(Debug)]
pub struct NodeTypeMap {
nodes: BTreeMap<NodeName, NodeType>,
prev_rust_names: PrevNodeRustNames,
}
#[derive(Clone, Debug)]
pub struct NodeType {
pub name: NodeName,
pub kind: NodeTypeKind,
pub(crate) rust_names: NodeRustNames,
}
#[derive(Clone, Debug, Deserialize)]
pub(crate) struct ContextFreeNodeType {
#[serde(flatten)]
name: NodeName,
#[serde(flatten)]
kind: NodeTypeKind,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum NodeTypeKind {
Supertype {
subtypes: BTreeSet<NodeName>,
},
Regular {
#[serde(default)]
fields: BTreeMap<String, Children>,
#[serde(default)]
children: Children,
},
}
#[derive(Clone, Debug, Deserialize)]
pub struct Children {
pub multiple: bool,
pub required: bool,
pub types: VecSet<NodeName>,
}
impl NodeTypeMap {
pub(crate) fn new(node_types: Vec<ContextFreeNodeType>) -> Self {
let mut prev_rust_names = PrevNodeRustNames::new();
let mut nodes = node_types
.into_iter()
.map(|node_type| {
(
node_type.name.clone(),
NodeType::new(node_type, &mut prev_rust_names),
)
})
.collect::<BTreeMap<_, _>>();
let child_type_names = nodes
.values()
.flat_map(|node_type| match &node_type.kind {
NodeTypeKind::Supertype { .. } => None,
NodeTypeKind::Regular { fields, children } => {
Some(fields.values().chain([children]))
}
})
.flatten()
.flat_map(|children| &children.types);
let nonexistent_alias_type_names =
child_type_names.filter(|name| !nodes.contains_key(*name));
let nonexistent_alias_type_names =
nonexistent_alias_type_names.cloned().collect::<Vec<_>>();
nodes.extend(nonexistent_alias_type_names.into_iter().map(|name| {
(
name.clone(),
NodeType::nonexistent_alias_stub(name, &mut prev_rust_names),
)
}));
Self {
nodes,
prev_rust_names,
}
}
pub fn get<Q: Ord + ?Sized>(&self, name: &Q) -> Option<&NodeType>
where
NodeName: Borrow<Q>,
{
self.nodes.get(name)
}
pub fn values(&self) -> impl Iterator<Item = &NodeType> {
self.nodes.values()
}
pub fn add_custom_supertype(
&mut self,
name: &str,
subtypes: impl IntoIterator<Item = NodeName>,
) -> Result<NodeName, NodeName> {
if !name.starts_with("_") {
panic!("Illegal supertype name '{name}'. Supertypes must start with an underscore, i.e. '_{name}'.");
}
let subtypes = BTreeSet::from_iter(subtypes);
let subtypes_vecset = VecSet::from_iter(subtypes.clone());
let name = NodeName {
sexp_name: name.to_owned(),
is_named: true,
};
let new_node = ContextFreeNodeType {
name: name.clone(),
kind: NodeTypeKind::Supertype { subtypes },
};
let new_node = NodeType::new(new_node, &mut self.prev_rust_names);
if self.nodes.contains_key(&name) {
return Err(name);
}
self.nodes.insert(name.clone(), new_node);
for node in self.nodes.values_mut() {
match &mut node.kind {
NodeTypeKind::Regular {
fields, children, ..
} => {
for children in fields.values_mut().chain(std::iter::once(children)) {
if children.types == subtypes_vecset {
children.types = VecSet::from_iter([name.clone()]);
}
}
}
NodeTypeKind::Supertype { .. } => {}
}
}
Ok(name)
}
}
impl TryFrom<&Path> for NodeTypeMap {
type Error = crate::Error;
fn try_from(path: &Path) -> Result<Self, Self::Error> {
let text = std::fs::read_to_string(path)?;
NodeTypeMap::try_from(text.as_str())
}
}
impl TryFrom<PathBuf> for NodeTypeMap {
type Error = crate::Error;
fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
Self::try_from(value.as_path())
}
}
impl TryFrom<&str> for NodeTypeMap {
type Error = crate::Error;
fn try_from(text: &str) -> Result<Self, Self::Error> {
let elems = iter_json_array::<ContextFreeNodeType, _>(text.as_bytes())
.collect::<Result<Vec<_>, _>>()?;
Ok(NodeTypeMap::new(elems))
}
}
impl<Q: Ord + ?Sized> Index<&Q> for NodeTypeMap
where
NodeName: Borrow<Q>,
{
type Output = NodeType;
fn index(&self, name: &Q) -> &Self::Output {
&self.nodes[name]
}
}
impl NodeType {
fn new(
ContextFreeNodeType { name, kind }: ContextFreeNodeType,
prev_rust_names: &mut PrevNodeRustNames,
) -> Self {
let rust_names = NodeRustNames::new(&name, prev_rust_names);
Self {
name,
rust_names,
kind,
}
}
fn nonexistent_alias_stub(name: NodeName, prev_rust_names: &mut PrevNodeRustNames) -> Self {
let rust_names = NodeRustNames::new(&name, prev_rust_names);
Self {
name,
kind: NodeTypeKind::Regular {
fields: BTreeMap::default(),
children: Children::default(),
},
rust_names,
}
}
pub fn rust_type_path(&self) -> Cow<'_, str> {
self.rust_names.type_path()
}
pub fn anon_union_type_name<'a>(
types: impl IntoIterator<Item = &'a NodeType, IntoIter: 'a>,
) -> String {
NodeRustNames::anon_union_type_name(types.into_iter().map(|t| &t.rust_names))
}
pub fn field(&self, name: &str) -> Option<&Children> {
match &self.kind {
NodeTypeKind::Supertype { .. } => None,
NodeTypeKind::Regular { fields, .. } => fields.get(name),
}
}
}
impl Index<&str> for NodeType {
type Output = Children;
fn index(&self, name: &str) -> &Self::Output {
self.field(&name)
.expect("this node doesn't have a field with the given name")
}
}
impl Children {
pub const EMPTY: Self = Self {
multiple: false,
required: false,
types: VecSet::new(),
};
pub fn is_empty(&self) -> bool {
self.types.is_empty()
}
}
impl Default for Children {
fn default() -> Self {
Self::EMPTY.clone()
}
}
impl BitOrAssign for Children {
fn bitor_assign(&mut self, other: Self) {
if other.is_empty() {
return;
} else if self.is_empty() {
*self = other;
return;
}
self.required |= other.required;
self.multiple |= other.multiple;
self.types.extend(other.types);
}
}