use crate::cst::syntax::SyntaxKind;
use crate::prelude::*;
#[derive(Debug, Clone)]
pub enum GreenChild {
Node(GreenNode),
Token {
kind: SyntaxKind,
len: u32,
},
}
impl GreenChild {
#[must_use]
pub fn text_len(&self) -> usize {
match self {
Self::Node(n) => n.text_len(),
Self::Token { len, .. } => *len as usize,
}
}
#[must_use]
pub fn token_text<'s>(&self, source: &'s str, offset: usize) -> Option<&'s str> {
match self {
Self::Token { len, .. } => Some(&source[offset..offset + *len as usize]),
Self::Node(_) => None,
}
}
pub(crate) fn write_text(&self, out: &mut String, source: &str, offset: usize) -> usize {
match self {
Self::Node(n) => n.write_text(out, source, offset),
Self::Token { len, .. } => {
let l = *len as usize;
out.push_str(&source[offset..offset + l]);
offset + l
}
}
}
}
#[derive(Debug, Clone)]
pub struct GreenNode {
kind: SyntaxKind,
text_len: u32,
children: Arc<[GreenChild]>,
}
impl GreenNode {
#[must_use]
pub fn new(kind: SyntaxKind, children: Vec<GreenChild>) -> Self {
Self::try_new(kind, children)
.expect("YAML document exceeds 4 GiB — parser cap should have rejected this earlier")
}
pub(crate) fn try_new(kind: SyntaxKind, children: Vec<GreenChild>) -> Option<Self> {
let mut total: usize = 0;
for child in &children {
total = total.checked_add(child.text_len())?;
}
let text_len = u32::try_from(total).ok()?;
Some(Self {
kind,
text_len,
children: Arc::from(children),
})
}
#[must_use]
pub fn kind(&self) -> SyntaxKind {
self.kind
}
#[must_use]
pub fn text_len(&self) -> usize {
self.text_len as usize
}
pub fn children(&self) -> impl Iterator<Item = &GreenChild> {
self.children.iter()
}
#[must_use]
pub fn text(&self, source: &str) -> String {
let mut out = String::with_capacity(self.text_len as usize);
let _ = self.write_text(&mut out, source, 0);
out
}
pub(crate) fn write_text(&self, out: &mut String, source: &str, offset: usize) -> usize {
let mut pos = offset;
for child in self.children.iter() {
pos = child.write_text(out, source, pos);
}
pos
}
}
impl Drop for GreenNode {
fn drop(&mut self) {
if !has_node_child(&self.children) {
return;
}
let mut pending = vec![core::mem::replace(&mut self.children, empty_children())];
while let Some(mut list) = pending.pop() {
let Some(children) = Arc::get_mut(&mut list) else {
continue;
};
for child in children.iter_mut() {
if let GreenChild::Node(node) = child {
if has_node_child(&node.children) {
pending.push(core::mem::replace(&mut node.children, empty_children()));
}
}
}
}
}
}
fn has_node_child(children: &[GreenChild]) -> bool {
children.iter().any(|c| matches!(c, GreenChild::Node(_)))
}
fn empty_children() -> Arc<[GreenChild]> {
Arc::from(Vec::new())
}