use std::{
hash::{Hash, Hasher},
iter::FusedIterator,
slice,
};
use fxhash::FxHasher32;
use crate::{
green::{GreenElement, GreenElementRef, PackedGreenElement, SyntaxKind},
TextSize,
};
use triomphe::{Arc, HeaderWithLength, ThinArc};
#[repr(align(2))] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(super) struct GreenNodeHead {
kind: SyntaxKind,
text_len: TextSize,
child_hash: u32,
}
impl GreenNodeHead {
#[inline]
pub(super) fn from_child_iter<I>(kind: SyntaxKind, children: I) -> Self
where
I: Iterator<Item = GreenElement>,
{
let mut hasher = FxHasher32::default();
let mut text_len: TextSize = 0.into();
for child in children {
text_len += child.text_len();
child.hash(&mut hasher);
}
Self {
kind,
text_len,
child_hash: hasher.finish() as u32,
}
}
}
#[derive(Clone)]
pub struct GreenNode {
pub(super) data: ThinArc<GreenNodeHead, PackedGreenElement>,
}
impl std::fmt::Debug for GreenNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.data.with_arc(|data| data.fmt(f))
}
}
impl GreenNode {
#[inline]
pub fn new<I>(kind: SyntaxKind, children: I) -> GreenNode
where
I: IntoIterator<Item = GreenElement>,
I::IntoIter: ExactSizeIterator,
{
let mut hasher = FxHasher32::default();
let mut text_len: TextSize = 0.into();
let children = children
.into_iter()
.inspect(|it| {
text_len += it.text_len();
it.hash(&mut hasher);
})
.map(PackedGreenElement::from);
let header = HeaderWithLength::new(
GreenNodeHead {
kind,
text_len: 0.into(),
child_hash: 0,
},
children.len(),
);
let mut data = Arc::from_header_and_iter(header, children);
let header = &mut Arc::get_mut(&mut data).unwrap().header.header;
header.text_len = text_len;
header.child_hash = hasher.finish() as u32;
GreenNode {
data: Arc::into_thin(data),
}
}
#[inline]
pub(super) fn from_head_and_children<I>(header: GreenNodeHead, children: I) -> GreenNode
where
I: IntoIterator<Item = GreenElement>,
I::IntoIter: ExactSizeIterator,
{
let children = children.into_iter().map(PackedGreenElement::from);
let header = HeaderWithLength::new(header, children.len());
GreenNode {
data: Arc::into_thin(Arc::from_header_and_iter(header, children)),
}
}
#[inline]
pub fn kind(&self) -> SyntaxKind {
self.data.header.header.kind
}
#[inline]
pub fn text_len(&self) -> TextSize {
self.data.header.header.text_len
}
#[inline]
pub(crate) fn iter(&self) -> slice::Iter<'_, PackedGreenElement> {
self.data.slice.iter()
}
#[inline]
pub fn children(&self) -> Children<'_> {
Children {
inner: self.data.slice.iter(),
}
}
}
impl Hash for GreenNode {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.data.header.header.hash(state);
}
}
impl PartialEq for GreenNode {
fn eq(&self, other: &Self) -> bool {
self.data == other.data
}
}
impl Eq for GreenNode {}
#[derive(Debug, Clone)]
pub struct Children<'a> {
inner: slice::Iter<'a, PackedGreenElement>,
}
impl ExactSizeIterator for Children<'_> {
#[inline(always)]
fn len(&self) -> usize {
self.inner.len()
}
}
impl<'a> Iterator for Children<'a> {
type Item = GreenElementRef<'a>;
#[inline]
fn next(&mut self) -> Option<GreenElementRef<'a>> {
self.inner.next().map(PackedGreenElement::as_ref)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline]
fn count(self) -> usize
where
Self: Sized,
{
self.inner.count()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.inner.nth(n).map(PackedGreenElement::as_ref)
}
#[inline]
fn last(mut self) -> Option<Self::Item>
where
Self: Sized,
{
self.next_back()
}
#[inline]
fn fold<Acc, Fold>(self, init: Acc, mut f: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
let mut accum = init;
for x in self {
accum = f(accum, x);
}
accum
}
}
impl<'a> DoubleEndedIterator for Children<'a> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(PackedGreenElement::as_ref)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.inner.nth_back(n).map(PackedGreenElement::as_ref)
}
#[inline]
fn rfold<Acc, Fold>(mut self, init: Acc, mut f: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
let mut accum = init;
while let Some(x) = self.next_back() {
accum = f(accum, x);
}
accum
}
}
impl FusedIterator for Children<'_> {}