From f06a2c903caa270e977a73ef5b9091f99e8fbe6c Mon Sep 17 00:00:00 2001 From: Theodore Luo Wang <wangtheo662@gmail.com> Date: Sun, 3 Oct 2021 15:03:23 -0400 Subject: [PATCH 1/3] Reduce allocations when iterating over Syntax{Node,Element} children This allows users of the API to apply a filter on the SyntaxKind before materializing concrete SyntaxNode/Token objects, which require a memory allocation for the NodeData. For slint, this removes ~400k allocations when parsing a largish project, about 50% of all rowan allocations (850k down to 450k). --- src/api.rs | 93 +++++++++++++++++++++++ src/cursor.rs | 202 +++++++++++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 3 +- 3 files changed, 288 insertions(+), 10 deletions(-) diff --git a/src/api.rs b/src/api.rs index ccfb0a5..72ef0a9 100644 --- a/src/api.rs +++ b/src/api.rs @@ -148,6 +148,13 @@ impl<L: Language> SyntaxNode<L> { pub fn first_child(&self) -> Option<SyntaxNode<L>> { self.raw.first_child().map(Self::from) } + + pub fn first_child_by_kind(&self, matcher: &impl Fn(L::Kind) -> bool) -> Option<SyntaxNode<L>> { + self.raw + .first_child_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(Self::from) + } + pub fn last_child(&self) -> Option<SyntaxNode<L>> { self.raw.last_child().map(Self::from) } @@ -155,6 +162,16 @@ impl<L: Language> SyntaxNode<L> { pub fn first_child_or_token(&self) -> Option<SyntaxElement<L>> { self.raw.first_child_or_token().map(NodeOrToken::from) } + + pub fn first_child_or_token_by_kind( + &self, + matcher: &impl Fn(L::Kind) -> bool, + ) -> Option<SyntaxElement<L>> { + self.raw + .first_child_or_token_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(NodeOrToken::from) + } + pub fn last_child_or_token(&self) -> Option<SyntaxElement<L>> { self.raw.last_child_or_token().map(NodeOrToken::from) } @@ -162,6 +179,16 @@ impl<L: Language> SyntaxNode<L> { pub fn next_sibling(&self) -> Option<SyntaxNode<L>> { self.raw.next_sibling().map(Self::from) } + + pub fn next_sibling_by_kind( + &self, + matcher: &impl Fn(L::Kind) -> bool, + ) -> Option<SyntaxNode<L>> { + self.raw + .next_sibling_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(Self::from) + } + pub fn prev_sibling(&self) -> Option<SyntaxNode<L>> { self.raw.prev_sibling().map(Self::from) } @@ -169,6 +196,16 @@ impl<L: Language> SyntaxNode<L> { pub fn next_sibling_or_token(&self) -> Option<SyntaxElement<L>> { self.raw.next_sibling_or_token().map(NodeOrToken::from) } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(L::Kind) -> bool, + ) -> Option<SyntaxElement<L>> { + self.raw + .next_sibling_or_token_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(NodeOrToken::from) + } + pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement<L>> { self.raw.prev_sibling_or_token().map(NodeOrToken::from) } @@ -403,6 +440,34 @@ impl<L: Language> Iterator for SyntaxNodeChildren<L> { } } +impl<L: Language> SyntaxNodeChildren<L> { + pub fn by_kind<'a>( + self, + matcher: &'a dyn Fn(SyntaxKind) -> bool, + ) -> SyntaxNodeChildrenByKind<'a, L> { + SyntaxNodeChildrenByKind { raw: self.raw.by_kind(matcher), _p: PhantomData } + } +} + +#[derive(Clone)] +pub struct SyntaxNodeChildrenByKind<'a, L: Language> { + raw: cursor::SyntaxNodeChildrenByKind<&'a dyn Fn(SyntaxKind) -> bool>, + _p: PhantomData<L>, +} + +impl<'a, L: Language> Iterator for SyntaxNodeChildrenByKind<'a, L> { + type Item = SyntaxNode<L>; + fn next(&mut self) -> Option<Self::Item> { + self.raw.next().map(SyntaxNode::from) + } +} + +impl<'a, L: Language> fmt::Debug for SyntaxNodeChildrenByKind<'a, L> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SyntaxNodeChildrenByKind").finish() + } +} + #[derive(Debug, Clone)] pub struct SyntaxElementChildren<L: Language> { raw: cursor::SyntaxElementChildren, @@ -416,6 +481,34 @@ impl<L: Language> Iterator for SyntaxElementChildren<L> { } } +impl<L: Language> SyntaxElementChildren<L> { + pub fn by_kind<'a>( + self, + matcher: &'a dyn Fn(SyntaxKind) -> bool, + ) -> SyntaxElementChildrenByKind<'a, L> { + SyntaxElementChildrenByKind { raw: self.raw.by_kind(matcher), _p: PhantomData } + } +} + +#[derive(Clone)] +pub struct SyntaxElementChildrenByKind<'a, L: Language> { + raw: cursor::SyntaxElementChildrenByKind<&'a dyn Fn(SyntaxKind) -> bool>, + _p: PhantomData<L>, +} + +impl<'a, L: Language> Iterator for SyntaxElementChildrenByKind<'a, L> { + type Item = SyntaxElement<L>; + fn next(&mut self) -> Option<Self::Item> { + self.raw.next().map(NodeOrToken::from) + } +} + +impl<'a, L: Language> fmt::Debug for SyntaxElementChildrenByKind<'a, L> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SyntaxElementChildrenByKind").finish() + } +} + pub struct Preorder<L: Language> { raw: cursor::Preorder, _p: PhantomData<L>, diff --git a/src/cursor.rs b/src/cursor.rs index f7faf27..4681c21 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -376,11 +376,26 @@ impl NodeData { } fn next_sibling(&self) -> Option<SyntaxNode> { - let mut siblings = self.green_siblings().enumerate(); + let siblings = self.green_siblings().enumerate(); + let index = self.index() as usize; + + siblings.skip(index + 1).find_map(|(index, child)| { + child.as_ref().into_node().and_then(|green| { + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxNode::new_child(green, parent, index as u32, offset)) + }) + }) + } + + fn next_sibling_by_kind(&self, matcher: &impl Fn(SyntaxKind) -> bool) -> Option<SyntaxNode> { + let siblings = self.green_siblings().enumerate(); let index = self.index() as usize; - siblings.nth(index); - siblings.find_map(|(index, child)| { + siblings.skip(index + 1).find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } child.as_ref().into_node().and_then(|green| { let parent = self.parent_node()?; let offset = parent.offset() + child.rel_offset(); @@ -388,12 +403,12 @@ impl NodeData { }) }) } + fn prev_sibling(&self) -> Option<SyntaxNode> { - let mut rev_siblings = self.green_siblings().enumerate().rev(); - let index = rev_siblings.len().checked_sub(self.index() as usize + 1)?; + let rev_siblings = self.green_siblings().enumerate().rev(); + let index = rev_siblings.len().checked_sub(self.index() as usize)?; - rev_siblings.nth(index); - rev_siblings.find_map(|(index, child)| { + rev_siblings.skip(index + 1).find_map(|(index, child)| { child.as_ref().into_node().and_then(|green| { let parent = self.parent_node()?; let offset = parent.offset() + child.rel_offset(); @@ -412,6 +427,24 @@ impl NodeData { Some(SyntaxElement::new(child.as_ref(), parent, index as u32, offset)) }) } + + fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option<SyntaxElement> { + let siblings = self.green_siblings().enumerate(); + let index = self.index() as usize; + + siblings.skip(index + 1).find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxElement::new(child.as_ref(), parent, index as u32, offset)) + }) + } + fn prev_sibling_or_token(&self) -> Option<SyntaxElement> { let mut siblings = self.green_siblings().enumerate(); let index = self.index().checked_sub(1)? as usize; @@ -647,6 +680,23 @@ impl SyntaxNode { }) }) } + + pub fn first_child_by_kind(&self, matcher: &impl Fn(SyntaxKind) -> bool) -> Option<SyntaxNode> { + self.green_ref().children().raw.enumerate().find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } + child.as_ref().into_node().map(|green| { + SyntaxNode::new_child( + green, + self.clone(), + index as u32, + self.offset() + child.rel_offset(), + ) + }) + }) + } + pub fn last_child(&self) -> Option<SyntaxNode> { self.green_ref().children().raw.enumerate().rev().find_map(|(index, child)| { child.as_ref().into_node().map(|green| { @@ -665,6 +715,24 @@ impl SyntaxNode { SyntaxElement::new(child.as_ref(), self.clone(), 0, self.offset() + child.rel_offset()) }) } + + pub fn first_child_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option<SyntaxElement> { + self.green_ref().children().raw.enumerate().find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } + Some(SyntaxElement::new( + child.as_ref(), + self.clone(), + index as u32, + self.offset() + child.rel_offset(), + )) + }) + } + pub fn last_child_or_token(&self) -> Option<SyntaxElement> { self.green_ref().children().raw.enumerate().next_back().map(|(index, child)| { SyntaxElement::new( @@ -679,6 +747,14 @@ impl SyntaxNode { pub fn next_sibling(&self) -> Option<SyntaxNode> { self.data().next_sibling() } + + pub fn next_sibling_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option<SyntaxNode> { + self.data().next_sibling_by_kind(matcher) + } + pub fn prev_sibling(&self) -> Option<SyntaxNode> { self.data().prev_sibling() } @@ -686,6 +762,14 @@ impl SyntaxNode { pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> { self.data().next_sibling_or_token() } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option<SyntaxElement> { + self.data().next_sibling_or_token_by_kind(matcher) + } + pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> { self.data().prev_sibling_or_token() } @@ -910,6 +994,14 @@ impl SyntaxToken { pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> { self.data().next_sibling_or_token() } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option<SyntaxElement> { + self.data().next_sibling_or_token_by_kind(matcher) + } + pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> { self.data().prev_sibling_or_token() } @@ -1028,6 +1120,17 @@ impl SyntaxElement { NodeOrToken::Token(it) => it.next_sibling_or_token(), } } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option<SyntaxElement> { + match self { + NodeOrToken::Node(it) => it.next_sibling_or_token_by_kind(matcher), + NodeOrToken::Token(it) => it.next_sibling_or_token_by_kind(matcher), + } + } + pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> { match self { NodeOrToken::Node(it) => it.prev_sibling_or_token(), @@ -1133,18 +1236,41 @@ impl From<SyntaxToken> for SyntaxElement { #[derive(Clone, Debug)] pub struct SyntaxNodeChildren { + parent: SyntaxNode, next: Option<SyntaxNode>, + next_initialized: bool, } impl SyntaxNodeChildren { fn new(parent: SyntaxNode) -> SyntaxNodeChildren { - SyntaxNodeChildren { next: parent.first_child() } + SyntaxNodeChildren { parent, next: None, next_initialized: false } + } + + pub fn by_kind<F: Fn(SyntaxKind) -> bool>(self, matcher: F) -> SyntaxNodeChildrenByKind<F> { + if !self.next_initialized { + SyntaxNodeChildrenByKind { next: self.parent.first_child_by_kind(&matcher), matcher } + } else { + SyntaxNodeChildrenByKind { + next: self.next.and_then(|node| { + if matcher(node.kind()) { + Some(node) + } else { + node.next_sibling_by_kind(&matcher) + } + }), + matcher, + } + } } } impl Iterator for SyntaxNodeChildren { type Item = SyntaxNode; fn next(&mut self) -> Option<SyntaxNode> { + if !self.next_initialized { + self.next = self.parent.first_child(); + self.next_initialized = true; + } self.next.take().map(|next| { self.next = next.next_sibling(); next @@ -1152,20 +1278,62 @@ impl Iterator for SyntaxNodeChildren { } } +#[derive(Clone, Debug)] +pub struct SyntaxNodeChildrenByKind<F: Fn(SyntaxKind) -> bool> { + next: Option<SyntaxNode>, + matcher: F, +} + +impl<F: Fn(SyntaxKind) -> bool> Iterator for SyntaxNodeChildrenByKind<F> { + type Item = SyntaxNode; + fn next(&mut self) -> Option<SyntaxNode> { + self.next.take().map(|next| { + self.next = next.next_sibling_by_kind(&self.matcher); + next + }) + } +} + #[derive(Clone, Debug)] pub struct SyntaxElementChildren { + parent: SyntaxNode, next: Option<SyntaxElement>, + next_initialized: bool, } impl SyntaxElementChildren { fn new(parent: SyntaxNode) -> SyntaxElementChildren { - SyntaxElementChildren { next: parent.first_child_or_token() } + SyntaxElementChildren { parent, next: None, next_initialized: false } + } + + pub fn by_kind<F: Fn(SyntaxKind) -> bool>(self, matcher: F) -> SyntaxElementChildrenByKind<F> { + if !self.next_initialized { + SyntaxElementChildrenByKind { + next: self.parent.first_child_or_token_by_kind(&matcher), + matcher, + } + } else { + SyntaxElementChildrenByKind { + next: self.next.and_then(|node| { + if matcher(node.kind()) { + Some(node) + } else { + node.next_sibling_or_token_by_kind(&matcher) + } + }), + matcher, + } + } } } impl Iterator for SyntaxElementChildren { type Item = SyntaxElement; fn next(&mut self) -> Option<SyntaxElement> { + if !self.next_initialized { + self.next = self.parent.first_child_or_token(); + self.next_initialized = true; + } self.next.take().map(|next| { self.next = next.next_sibling_or_token(); next @@ -1173,6 +1341,22 @@ impl Iterator for SyntaxElementChildren { } } +#[derive(Clone, Debug)] +pub struct SyntaxElementChildrenByKind<F: Fn(SyntaxKind) -> bool> { + next: Option<SyntaxElement>, + matcher: F, +} + +impl<F: Fn(SyntaxKind) -> bool> Iterator for SyntaxElementChildrenByKind<F> { + type Item = SyntaxElement; + fn next(&mut self) -> Option<SyntaxElement> { + self.next.take().map(|next| { + self.next = next.next_sibling_or_token_by_kind(&self.matcher); + next + }) + } +} + pub struct Preorder { start: SyntaxNode, next: Option<WalkEvent<SyntaxNode>>, diff --git a/src/lib.rs b/src/lib.rs index bb8f30d..066d8c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,8 @@ pub use text_size::{TextLen, TextRange, TextSize}; pub use crate::{ api::{ - Language, SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken, + Language, SyntaxElement, SyntaxElementChildren, SyntaxElementChildrenByKind, SyntaxNode, + SyntaxNodeChildren, SyntaxNodeChildrenByKind, SyntaxToken, }, green::{ Checkpoint, Children, GreenNode, GreenNodeBuilder, GreenNodeData, GreenToken, From 0b1a6ec04ae9aa60413c28ddee0c344415129260 Mon Sep 17 00:00:00 2001 From: Milian Wolff <milian.wolff@kdab.com> Date: Sun, 27 Oct 2024 19:39:28 +0100 Subject: [PATCH 2/3] Optimize iteration over sibling nodes by reusing NodeData if possible When possible, reuse the allocated NodeData instead of allocating a new one for each iteration. This can be done as long as the refcount is 1 - we can then just rewire the values in NodeData to point to the new item. This removes ~220k allocations when compiling a largish slint file, about half of all rowan allocations that happen during iteration, i.e. we go from 450k down to 230k. --- src/cursor.rs | 134 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 8 deletions(-) diff --git a/src/cursor.rs b/src/cursor.rs index 4681c21..aa66be0 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -597,6 +597,20 @@ impl SyntaxNode { unsafe { self.ptr.as_ref() } } + #[inline] + fn can_take_ptr(&self) -> bool { + self.data().rc.get() == 1 && !self.data().mutable + } + + #[inline] + fn take_ptr(self) -> ptr::NonNull<NodeData> { + assert!(self.can_take_ptr()); + let ret = self.ptr; + // don't change the refcount when self gets dropped + std::mem::forget(self); + ret + } + pub fn replace_with(&self, replacement: GreenNode) -> GreenNode { assert_eq!(self.kind(), replacement.kind()); match &self.parent() { @@ -744,6 +758,43 @@ impl SyntaxNode { }) } + // if possible (i.e. unshared), consume self and advance it to point to the next sibling + // this way, we can reuse the previously allocated buffer + pub fn to_next_sibling(self) -> Option<SyntaxNode> { + if !self.can_take_ptr() { + // cannot mutate in-place + return self.next_sibling(); + } + + let mut ptr = self.take_ptr(); + let data = unsafe { ptr.as_mut() }; + assert!(data.rc.get() == 1); + + let parent = data.parent_node()?; + let parent_offset = parent.offset(); + let siblings = parent.green_ref().children().raw.enumerate(); + let index = data.index() as usize; + + siblings + .skip(index + 1) + .find_map(|(index, child)| { + child + .as_ref() + .into_node() + .and_then(|green| Some((green, index as u32, child.rel_offset()))) + }) + .and_then(|(green, index, rel_offset)| { + data.index.set(index); + data.offset = parent_offset + rel_offset; + data.green = Green::Node { ptr: Cell::new(green.into()) }; + Some(SyntaxNode { ptr }) + }) + .or_else(|| { + unsafe { free(ptr) }; + None + }) + } + pub fn next_sibling(&self) -> Option<SyntaxNode> { self.data().next_sibling() } @@ -937,6 +988,20 @@ impl SyntaxToken { unsafe { self.ptr.as_ref() } } + #[inline] + fn can_take_ptr(&self) -> bool { + self.data().rc.get() == 1 && !self.data().mutable + } + + #[inline] + fn take_ptr(self) -> ptr::NonNull<NodeData> { + assert!(self.can_take_ptr()); + let ret = self.ptr; + // don't change the refcount when self gets dropped + std::mem::forget(self); + ret + } + pub fn replace_with(&self, replacement: GreenToken) -> GreenNode { assert_eq!(self.kind(), replacement.kind()); let parent = self.parent().unwrap(); @@ -1121,6 +1186,59 @@ impl SyntaxElement { } } + fn can_take_ptr(&self) -> bool { + match self { + NodeOrToken::Node(it) => it.can_take_ptr(), + NodeOrToken::Token(it) => it.can_take_ptr(), + } + } + + fn take_ptr(self) -> ptr::NonNull<NodeData> { + match self { + NodeOrToken::Node(it) => it.take_ptr(), + NodeOrToken::Token(it) => it.take_ptr(), + } + } + + // if possible (i.e. unshared), consume self and advance it to point to the next sibling + // this way, we can reuse the previously allocated buffer + pub fn to_next_sibling_or_token(self) -> Option<SyntaxElement> { + if !self.can_take_ptr() { + // cannot mutate in-place + return self.next_sibling_or_token(); + } + + let mut ptr = self.take_ptr(); + let data = unsafe { ptr.as_mut() }; + + let parent = data.parent_node()?; + let parent_offset = parent.offset(); + let siblings = parent.green_ref().children().raw.enumerate(); + let index = data.index() as usize; + + siblings + .skip(index + 1) + .find_map(|(index, green)| { + data.index.set(index as u32); + data.offset = parent_offset + green.rel_offset(); + + match green.as_ref() { + NodeOrToken::Node(node) => { + data.green = Green::Node { ptr: Cell::new(node.into()) }; + Some(SyntaxElement::Node(SyntaxNode { ptr })) + } + NodeOrToken::Token(token) => { + data.green = Green::Token { ptr: token.into() }; + Some(SyntaxElement::Token(SyntaxToken { ptr })) + } + } + }) + .or_else(|| { + unsafe { free(ptr) }; + None + }) + } + pub fn next_sibling_or_token_by_kind( &self, matcher: &impl Fn(SyntaxKind) -> bool, @@ -1270,11 +1388,11 @@ impl Iterator for SyntaxNodeChildren { if !self.next_initialized { self.next = self.parent.first_child(); self.next_initialized = true; + } else { + self.next = self.next.take().and_then(|next| next.to_next_sibling()); } - self.next.take().map(|next| { - self.next = next.next_sibling(); - next - }) + + self.next.clone() } } @@ -1333,11 +1451,11 @@ impl Iterator for SyntaxElementChildren { if !self.next_initialized { self.next = self.parent.first_child_or_token(); self.next_initialized = true; + } else { + self.next = self.next.take().and_then(|next| next.to_next_sibling_or_token()); } - self.next.take().map(|next| { - self.next = next.next_sibling_or_token(); - next - }) + + self.next.clone() } } From ab5463e2749330be6846886c21e98c83caca8598 Mon Sep 17 00:00:00 2001 From: Milian Wolff <milian.wolff@kdab.com> Date: Sun, 27 Oct 2024 22:06:08 +0100 Subject: [PATCH 3/3] Use iterators for by_kind instead of introducing separate structs This makes this API actually useful from the outside - there is no lifetime problem with the matcher callback, and we can remap the raw Kind to the Language::Kind on the fly. --- src/api.rs | 56 +++++++++--------------------------------------------- src/lib.rs | 3 +-- 2 files changed, 10 insertions(+), 49 deletions(-) diff --git a/src/api.rs b/src/api.rs index 72ef0a9..cd86d9d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -441,30 +441,11 @@ impl<L: Language> Iterator for SyntaxNodeChildren<L> { } impl<L: Language> SyntaxNodeChildren<L> { - pub fn by_kind<'a>( - self, - matcher: &'a dyn Fn(SyntaxKind) -> bool, - ) -> SyntaxNodeChildrenByKind<'a, L> { - SyntaxNodeChildrenByKind { raw: self.raw.by_kind(matcher), _p: PhantomData } - } -} - -#[derive(Clone)] -pub struct SyntaxNodeChildrenByKind<'a, L: Language> { - raw: cursor::SyntaxNodeChildrenByKind<&'a dyn Fn(SyntaxKind) -> bool>, - _p: PhantomData<L>, -} - -impl<'a, L: Language> Iterator for SyntaxNodeChildrenByKind<'a, L> { - type Item = SyntaxNode<L>; - fn next(&mut self) -> Option<Self::Item> { - self.raw.next().map(SyntaxNode::from) - } -} - -impl<'a, L: Language> fmt::Debug for SyntaxNodeChildrenByKind<'a, L> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SyntaxNodeChildrenByKind").finish() + pub fn by_kind(self, matcher: impl Fn(L::Kind) -> bool) -> impl Iterator<Item = SyntaxNode<L>> { + self.raw + .by_kind(move |raw_kind| matcher(L::kind_from_raw(raw_kind))) + .into_iter() + .map(SyntaxNode::from) } } @@ -482,30 +463,11 @@ impl<L: Language> Iterator for SyntaxElementChildren<L> { } impl<L: Language> SyntaxElementChildren<L> { - pub fn by_kind<'a>( + pub fn by_kind( self, - matcher: &'a dyn Fn(SyntaxKind) -> bool, - ) -> SyntaxElementChildrenByKind<'a, L> { - SyntaxElementChildrenByKind { raw: self.raw.by_kind(matcher), _p: PhantomData } - } -} - -#[derive(Clone)] -pub struct SyntaxElementChildrenByKind<'a, L: Language> { - raw: cursor::SyntaxElementChildrenByKind<&'a dyn Fn(SyntaxKind) -> bool>, - _p: PhantomData<L>, -} - -impl<'a, L: Language> Iterator for SyntaxElementChildrenByKind<'a, L> { - type Item = SyntaxElement<L>; - fn next(&mut self) -> Option<Self::Item> { - self.raw.next().map(NodeOrToken::from) - } -} - -impl<'a, L: Language> fmt::Debug for SyntaxElementChildrenByKind<'a, L> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SyntaxElementChildrenByKind").finish() + matcher: impl Fn(L::Kind) -> bool, + ) -> impl Iterator<Item = SyntaxElement<L>> { + self.raw.by_kind(move |raw_kind| matcher(L::kind_from_raw(raw_kind))).map(NodeOrToken::from) } } diff --git a/src/lib.rs b/src/lib.rs index 066d8c5..bb8f30d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,8 +30,7 @@ pub use text_size::{TextLen, TextRange, TextSize}; pub use crate::{ api::{ - Language, SyntaxElement, SyntaxElementChildren, SyntaxElementChildrenByKind, SyntaxNode, - SyntaxNodeChildren, SyntaxNodeChildrenByKind, SyntaxToken, + Language, SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken, }, green::{ Checkpoint, Children, GreenNode, GreenNodeBuilder, GreenNodeData, GreenToken,