#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
use std::collections::HashMap;
use std::num::NonZeroU16;
pub mod colors;
pub mod grammar;
mod interner;
mod invariants;
pub mod utils;
#[cfg(test)]
mod interner_tests;
#[cfg(test)]
mod lib_tests;
#[cfg(test)]
mod utils_tests;
pub use colors::Colors;
pub use interner::{Interner, Symbol};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RawNode {
#[serde(rename = "type")]
pub type_name: String,
pub named: bool,
#[serde(default)]
pub root: bool,
#[serde(default)]
pub extra: bool,
#[serde(default)]
pub fields: HashMap<String, RawCardinality>,
pub children: Option<RawCardinality>,
pub subtypes: Option<Vec<RawTypeRef>>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RawCardinality {
pub multiple: bool,
pub required: bool,
pub types: Vec<RawTypeRef>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RawTypeRef {
#[serde(rename = "type")]
pub type_name: String,
pub named: bool,
}
pub fn parse_node_types(json: &str) -> Result<Vec<RawNode>, serde_json::Error> {
serde_json::from_str(json)
}
pub type NodeTypeId = NonZeroU16;
pub type NodeFieldId = NonZeroU16;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Cardinality {
pub multiple: bool,
pub required: bool,
}
pub trait NodeTypes {
fn root(&self) -> Option<NodeTypeId>;
fn is_extra(&self, node_type_id: NodeTypeId) -> bool;
fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool;
fn field_cardinality(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> Option<Cardinality>;
fn valid_field_types(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> &[NodeTypeId];
fn is_valid_field_type(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
child: NodeTypeId,
) -> bool;
fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality>;
fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId];
fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool;
}
impl<T: NodeTypes + ?Sized> NodeTypes for &T {
fn root(&self) -> Option<NodeTypeId> {
(*self).root()
}
fn is_extra(&self, node_type_id: NodeTypeId) -> bool {
(*self).is_extra(node_type_id)
}
fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool {
(*self).has_field(node_type_id, node_field_id)
}
fn field_cardinality(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> Option<Cardinality> {
(*self).field_cardinality(node_type_id, node_field_id)
}
fn valid_field_types(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> &[NodeTypeId] {
(*self).valid_field_types(node_type_id, node_field_id)
}
fn is_valid_field_type(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
child: NodeTypeId,
) -> bool {
(*self).is_valid_field_type(node_type_id, node_field_id, child)
}
fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality> {
(*self).children_cardinality(node_type_id)
}
fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId] {
(*self).valid_child_types(node_type_id)
}
fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool {
(*self).is_valid_child_type(node_type_id, child)
}
}
#[derive(Debug, Clone, Copy)]
pub struct StaticFieldInfo {
pub cardinality: Cardinality,
pub valid_types: &'static [NodeTypeId],
}
#[derive(Debug, Clone, Copy)]
pub struct StaticChildrenInfo {
pub cardinality: Cardinality,
pub valid_types: &'static [NodeTypeId],
}
#[derive(Debug, Clone, Copy)]
pub struct StaticNodeTypeInfo {
pub name: &'static str,
pub named: bool,
pub fields: &'static [(NodeFieldId, StaticFieldInfo)],
pub children: Option<StaticChildrenInfo>,
}
#[derive(Debug, Clone, Copy)]
pub struct StaticNodeTypes {
nodes: &'static [(NodeTypeId, StaticNodeTypeInfo)],
extras: &'static [NodeTypeId],
root: Option<NodeTypeId>,
}
impl StaticNodeTypes {
pub const fn new(
nodes: &'static [(NodeTypeId, StaticNodeTypeInfo)],
extras: &'static [NodeTypeId],
root: Option<NodeTypeId>,
) -> Self {
Self {
nodes,
extras,
root,
}
}
pub fn get(&self, node_type_id: NodeTypeId) -> Option<&'static StaticNodeTypeInfo> {
self.nodes
.binary_search_by_key(&node_type_id, |(node_id, _)| *node_id)
.ok()
.map(|idx| &self.nodes[idx].1)
}
pub fn contains(&self, node_type_id: NodeTypeId) -> bool {
self.nodes
.binary_search_by_key(&node_type_id, |(node_id, _)| *node_id)
.is_ok()
}
pub fn field(
&self,
node_type_id: NodeTypeId,
field_id: NodeFieldId,
) -> Option<&'static StaticFieldInfo> {
let info = self.ensure_node(node_type_id);
info.fields
.binary_search_by_key(&field_id, |(fid, _)| *fid)
.ok()
.map(|idx| &info.fields[idx].1)
}
pub fn children(&self, node_type_id: NodeTypeId) -> Option<StaticChildrenInfo> {
self.ensure_node(node_type_id).children
}
pub fn extras(&self) -> &'static [NodeTypeId] {
self.extras
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (NodeTypeId, &'static StaticNodeTypeInfo)> {
self.nodes.iter().map(|(id, info)| (*id, info))
}
}
impl NodeTypes for StaticNodeTypes {
fn root(&self) -> Option<NodeTypeId> {
self.root
}
fn is_extra(&self, node_type_id: NodeTypeId) -> bool {
self.extras.contains(&node_type_id)
}
fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool {
self.get(node_type_id).is_some_and(|info| {
info.fields
.binary_search_by_key(&node_field_id, |(fid, _)| *fid)
.is_ok()
})
}
fn field_cardinality(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> Option<Cardinality> {
self.field(node_type_id, node_field_id)
.map(|f| f.cardinality)
}
fn valid_field_types(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> &[NodeTypeId] {
self.field(node_type_id, node_field_id)
.map(|f| f.valid_types)
.unwrap_or(&[])
}
fn is_valid_field_type(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
child: NodeTypeId,
) -> bool {
self.valid_field_types(node_type_id, node_field_id)
.contains(&child)
}
fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality> {
self.children(node_type_id).map(|c| c.cardinality)
}
fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId] {
self.children(node_type_id)
.map(|c| c.valid_types)
.unwrap_or(&[])
}
fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool {
self.valid_child_types(node_type_id).contains(&child)
}
}
#[derive(Debug, Clone)]
pub struct FieldInfo {
pub cardinality: Cardinality,
pub valid_types: Vec<NodeTypeId>,
}
#[derive(Debug, Clone)]
pub struct ChildrenInfo {
pub cardinality: Cardinality,
pub valid_types: Vec<NodeTypeId>,
}
#[derive(Debug, Clone)]
pub struct NodeTypeInfo {
pub name: String,
pub named: bool,
pub fields: HashMap<NodeFieldId, FieldInfo>,
pub children: Option<ChildrenInfo>,
}
#[derive(Debug, Clone)]
pub struct DynamicNodeTypes {
nodes: HashMap<NodeTypeId, NodeTypeInfo>,
extras: Vec<NodeTypeId>,
root: Option<NodeTypeId>,
}
impl DynamicNodeTypes {
pub fn from_raw(
nodes: HashMap<NodeTypeId, NodeTypeInfo>,
extras: Vec<NodeTypeId>,
root: Option<NodeTypeId>,
) -> Self {
Self {
nodes,
extras,
root,
}
}
pub fn build<F, G>(raw_nodes: &[RawNode], node_id_for_name: F, field_id_for_name: G) -> Self
where
F: Fn(&str, bool) -> Option<NodeTypeId>,
G: Fn(&str) -> Option<NodeFieldId>,
{
let mut nodes = HashMap::new();
let mut extras = Vec::new();
let mut root = None;
for raw in raw_nodes {
let Some(node_id) = node_id_for_name(&raw.type_name, raw.named) else {
continue;
};
if raw.root {
root = Some(node_id);
}
if raw.extra {
extras.push(node_id);
}
let mut fields = HashMap::new();
for (field_name, raw_card) in &raw.fields {
let Some(field_id) = field_id_for_name(field_name) else {
continue;
};
let valid_types = raw_card
.types
.iter()
.filter_map(|t| node_id_for_name(&t.type_name, t.named))
.collect();
fields.insert(
field_id,
FieldInfo {
cardinality: Cardinality {
multiple: raw_card.multiple,
required: raw_card.required,
},
valid_types,
},
);
}
let children = raw.children.as_ref().map(|raw_card| {
let valid_types = raw_card
.types
.iter()
.filter_map(|t| node_id_for_name(&t.type_name, t.named))
.collect();
ChildrenInfo {
cardinality: Cardinality {
multiple: raw_card.multiple,
required: raw_card.required,
},
valid_types,
}
});
nodes.insert(
node_id,
NodeTypeInfo {
name: raw.type_name.clone(),
named: raw.named,
fields,
children,
},
);
}
Self {
nodes,
extras,
root,
}
}
pub fn get(&self, node_type_id: NodeTypeId) -> Option<&NodeTypeInfo> {
self.nodes.get(&node_type_id)
}
pub fn contains(&self, node_type_id: NodeTypeId) -> bool {
self.nodes.contains_key(&node_type_id)
}
pub fn field(&self, node_type_id: NodeTypeId, field_id: NodeFieldId) -> Option<&FieldInfo> {
self.ensure_node(node_type_id).fields.get(&field_id)
}
pub fn children(&self, node_type_id: NodeTypeId) -> Option<&ChildrenInfo> {
self.ensure_node(node_type_id).children.as_ref()
}
pub fn extras(&self) -> &[NodeTypeId] {
&self.extras
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (NodeTypeId, &NodeTypeInfo)> {
self.nodes.iter().map(|(&id, info)| (id, info))
}
pub fn sorted_node_ids(&self) -> Vec<NodeTypeId> {
let mut ids: Vec<_> = self.nodes.keys().copied().collect();
ids.sort_unstable();
ids
}
pub fn sorted_extras(&self) -> Vec<NodeTypeId> {
let mut ids = self.extras.clone();
ids.sort_unstable();
ids
}
}
impl NodeTypes for DynamicNodeTypes {
fn root(&self) -> Option<NodeTypeId> {
self.root
}
fn is_extra(&self, node_type_id: NodeTypeId) -> bool {
self.extras.contains(&node_type_id)
}
fn has_field(&self, node_type_id: NodeTypeId, node_field_id: NodeFieldId) -> bool {
self.nodes
.get(&node_type_id)
.is_some_and(|n| n.fields.contains_key(&node_field_id))
}
fn field_cardinality(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> Option<Cardinality> {
self.field(node_type_id, node_field_id)
.map(|f| f.cardinality)
}
fn valid_field_types(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
) -> &[NodeTypeId] {
self.field(node_type_id, node_field_id)
.map(|f| f.valid_types.as_slice())
.unwrap_or(&[])
}
fn is_valid_field_type(
&self,
node_type_id: NodeTypeId,
node_field_id: NodeFieldId,
child: NodeTypeId,
) -> bool {
self.valid_field_types(node_type_id, node_field_id)
.contains(&child)
}
fn children_cardinality(&self, node_type_id: NodeTypeId) -> Option<Cardinality> {
self.children(node_type_id).map(|c| c.cardinality)
}
fn valid_child_types(&self, node_type_id: NodeTypeId) -> &[NodeTypeId] {
self.children(node_type_id)
.map(|c| c.valid_types.as_slice())
.unwrap_or(&[])
}
fn is_valid_child_type(&self, node_type_id: NodeTypeId, child: NodeTypeId) -> bool {
self.valid_child_types(node_type_id).contains(&child)
}
}