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,