From c35e88c3da3204ab9377c454942fcfcfb057e12e Mon Sep 17 00:00:00 2001 From: RGBCube Date: Tue, 29 Jul 2025 18:59:54 +0300 Subject: [PATCH 01/10] text: add SyntaxText::rfind_char --- cstree/src/syntax/text.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cstree/src/syntax/text.rs b/cstree/src/syntax/text.rs index 5525e4e..be08600 100644 --- a/cstree/src/syntax/text.rs +++ b/cstree/src/syntax/text.rs @@ -91,6 +91,18 @@ impl<'n, 'i, I: Resolver + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I, found(res) } + /// If `self.contains_char(c)`, returns `Some(pos)`, where `pos` is the byte position of the + /// last appearance of `c`. Otherwise, returns `None`. + pub fn rfind_char(&self, c: char) -> Option { + let mut acc: TextSize = 0.into(); + let mut res = None; + self.for_each_chunk(|chunk| { + res = chunk.rfind(c).map(|pos| acc + TextSize::from(pos as u32)).or(res); + acc += TextSize::of(chunk); + }); + res + } + /// If `offset < self.len()`, returns `Some(c)`, where `c` is the first `char` at or after /// `offset` (in bytes). Otherwise, returns `None`. pub fn char_at(&self, offset: TextSize) -> Option { From 35c2799059bb98fcef4e89f1c9fa381e73439b00 Mon Sep 17 00:00:00 2001 From: RGBCube Date: Tue, 29 Jul 2025 19:26:22 +0300 Subject: [PATCH 02/10] treewide: specify lifetimes correctly don't overrestrict lifetimes, prefer `use<...>` to prevent `impl Trait` from capturing too much --- cstree/src/syntax/element.rs | 2 +- cstree/src/syntax/resolved.rs | 2 +- cstree/src/syntax/text.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cstree/src/syntax/element.rs b/cstree/src/syntax/element.rs index bef407a..27fbdc4 100644 --- a/cstree/src/syntax/element.rs +++ b/cstree/src/syntax/element.rs @@ -292,7 +292,7 @@ impl<'a, S: Syntax, D> SyntaxElementRef<'a, S, D> { /// Returns an iterator along the chain of parents of this node. #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> + use<'a, S, D> { match self { NodeOrToken::Node(it) => it.ancestors(), NodeOrToken::Token(it) => it.parent().ancestors(), diff --git a/cstree/src/syntax/resolved.rs b/cstree/src/syntax/resolved.rs index 500d611..4c97301 100644 --- a/cstree/src/syntax/resolved.rs +++ b/cstree/src/syntax/resolved.rs @@ -713,7 +713,7 @@ impl<'a, S: Syntax, D> ResolvedElementRef<'a, S, D> { /// Returns an iterator along the chain of parents of this node. #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> + use<'a, S, D> { match self { NodeOrToken::Node(it) => it.ancestors(), NodeOrToken::Token(it) => it.parent().ancestors(), diff --git a/cstree/src/syntax/text.rs b/cstree/src/syntax/text.rs index 5525e4e..67bb909 100644 --- a/cstree/src/syntax/text.rs +++ b/cstree/src/syntax/text.rs @@ -150,7 +150,7 @@ impl<'n, 'i, I: Resolver + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I, /// See also [`fold_chunks`](SyntaxText::fold_chunks) for folds that always succeed. pub fn try_fold_chunks(&self, init: T, mut f: F) -> Result where - F: FnMut(T, &str) -> Result, + F: FnMut(T, &'i str) -> Result, { self.tokens_with_ranges().try_fold(init, move |acc, (token, range)| { f(acc, &token.resolve_text(self.resolver)[range]) @@ -195,7 +195,7 @@ impl<'n, 'i, I: Resolver + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I, self.fold_chunks((), |(), chunk| f(chunk)) } - fn tokens_with_ranges(&self) -> impl Iterator, TextRange)> { + fn tokens_with_ranges(&self) -> impl Iterator, TextRange)> + use<'i, 'n, I, S, D> { let text_range = self.range; self.node .descendants_with_tokens() From d006fcbcfe1b8b97cb07b639a25a047ff66aaee1 Mon Sep 17 00:00:00 2001 From: RGBCube Date: Tue, 29 Jul 2025 16:54:24 +0000 Subject: [PATCH 03/10] treewide: specify lifetimes correctly (#77) don't overrestrict lifetimes, prefer `use<...>` to prevent `impl Trait` from capturing too much --- cstree/src/syntax/element.rs | 2 +- cstree/src/syntax/resolved.rs | 2 +- cstree/src/syntax/text.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cstree/src/syntax/element.rs b/cstree/src/syntax/element.rs index bef407a..27fbdc4 100644 --- a/cstree/src/syntax/element.rs +++ b/cstree/src/syntax/element.rs @@ -292,7 +292,7 @@ impl<'a, S: Syntax, D> SyntaxElementRef<'a, S, D> { /// Returns an iterator along the chain of parents of this node. #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> + use<'a, S, D> { match self { NodeOrToken::Node(it) => it.ancestors(), NodeOrToken::Token(it) => it.parent().ancestors(), diff --git a/cstree/src/syntax/resolved.rs b/cstree/src/syntax/resolved.rs index 500d611..4c97301 100644 --- a/cstree/src/syntax/resolved.rs +++ b/cstree/src/syntax/resolved.rs @@ -713,7 +713,7 @@ impl<'a, S: Syntax, D> ResolvedElementRef<'a, S, D> { /// Returns an iterator along the chain of parents of this node. #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> + use<'a, S, D> { match self { NodeOrToken::Node(it) => it.ancestors(), NodeOrToken::Token(it) => it.parent().ancestors(), diff --git a/cstree/src/syntax/text.rs b/cstree/src/syntax/text.rs index 5525e4e..67bb909 100644 --- a/cstree/src/syntax/text.rs +++ b/cstree/src/syntax/text.rs @@ -150,7 +150,7 @@ impl<'n, 'i, I: Resolver + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I, /// See also [`fold_chunks`](SyntaxText::fold_chunks) for folds that always succeed. pub fn try_fold_chunks(&self, init: T, mut f: F) -> Result where - F: FnMut(T, &str) -> Result, + F: FnMut(T, &'i str) -> Result, { self.tokens_with_ranges().try_fold(init, move |acc, (token, range)| { f(acc, &token.resolve_text(self.resolver)[range]) @@ -195,7 +195,7 @@ impl<'n, 'i, I: Resolver + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I, self.fold_chunks((), |(), chunk| f(chunk)) } - fn tokens_with_ranges(&self) -> impl Iterator, TextRange)> { + fn tokens_with_ranges(&self) -> impl Iterator, TextRange)> + use<'i, 'n, I, S, D> { let text_range = self.range; self.node .descendants_with_tokens() From de990819b1446b9f4bd643aea8ac381b48e469e0 Mon Sep 17 00:00:00 2001 From: Domenic Quirl Date: Tue, 29 Jul 2025 20:44:15 +0200 Subject: [PATCH 04/10] bump MSRV to Rust 1.85 to support Edition 2024 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ad01ed8..a65b868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ authors = [ license = "MIT OR Apache-2.0" repository = "https://github.com/domenicquirl/cstree" readme = "README.md" -rust-version = "1.84" +rust-version = "1.85" [profile.release] debug = true From 8708fda02f14ec748f4978497abd29818054e27b Mon Sep 17 00:00:00 2001 From: Domenic Quirl Date: Tue, 29 Jul 2025 21:00:18 +0200 Subject: [PATCH 05/10] update to Rust edition 2024 --- Cargo.toml | 2 +- cstree-derive/src/lib.rs | 2 +- cstree-derive/src/parsing.rs | 2 +- cstree/benches/main.rs | 7 ++++--- cstree/examples/math.rs | 4 ++-- cstree/examples/readme.rs | 2 +- cstree/examples/s_expressions.rs | 4 ++-- cstree/src/green/builder.rs | 5 +++-- cstree/src/green/element.rs | 2 +- cstree/src/green/iter.rs | 2 +- cstree/src/green/node.rs | 4 ++-- cstree/src/green/token.rs | 2 +- cstree/src/interning/lasso_compat/traits.rs | 2 +- cstree/src/lib.rs | 3 ++- cstree/src/serde_impls.rs | 6 ++++-- cstree/src/syntax/element.rs | 3 ++- cstree/src/syntax/iter.rs | 2 +- cstree/src/syntax/node.rs | 5 +++-- cstree/src/syntax/resolved.rs | 15 +++++++++------ cstree/src/syntax/text.rs | 6 +++--- cstree/src/syntax/token.rs | 5 +++-- cstree/tests/it/basic.rs | 8 ++++---- cstree/tests/it/main.rs | 3 ++- cstree/tests/it/sendsync.rs | 4 ++-- cstree/tests/it/serde.rs | 2 +- rustfmt.toml | 3 ++- 26 files changed, 59 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a65b868..b89949a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "2" [workspace.package] -edition = "2021" +edition = "2024" version = "0.12.2" # when updating, also update `#![doc(html_root_url)]` and any inter-crate dependencies (such as `cstree`'s dependency on `cstree-derive`) authors = [ "Domenic Quirl ", diff --git a/cstree-derive/src/lib.rs b/cstree-derive/src/lib.rs index ebe0c9e..84ade41 100644 --- a/cstree-derive/src/lib.rs +++ b/cstree-derive/src/lib.rs @@ -17,7 +17,7 @@ use errors::ErrorContext; use parsing::SyntaxKindEnum; use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; -use syn::{parse_macro_input, spanned::Spanned, DeriveInput}; +use syn::{DeriveInput, parse_macro_input, spanned::Spanned}; mod errors; mod parsing; diff --git a/cstree-derive/src/parsing.rs b/cstree-derive/src/parsing.rs index cc53439..202cf7e 100644 --- a/cstree-derive/src/parsing.rs +++ b/cstree-derive/src/parsing.rs @@ -1,6 +1,6 @@ mod attributes; -use syn::{punctuated::Punctuated, Token}; +use syn::{Token, punctuated::Punctuated}; use crate::{errors::ErrorContext, symbols::*}; diff --git a/cstree/benches/main.rs b/cstree/benches/main.rs index 924036f..8738cb1 100644 --- a/cstree/benches/main.rs +++ b/cstree/benches/main.rs @@ -1,9 +1,10 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; +use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main}; use cstree::{ + RawSyntaxKind, + Syntax, build::*, green::GreenNode, - interning::{new_interner, Interner}, - RawSyntaxKind, Syntax, + interning::{Interner, new_interner}, }; #[derive(Debug)] diff --git a/cstree/examples/math.rs b/cstree/examples/math.rs index a98f6a2..56fb3eb 100644 --- a/cstree/examples/math.rs +++ b/cstree/examples/math.rs @@ -13,7 +13,7 @@ //! - "+" Token(Add) //! - "4" Token(Number) -use cstree::{build::GreenNodeBuilder, interning::Resolver, util::NodeOrToken, Syntax}; +use cstree::{Syntax, build::GreenNodeBuilder, interning::Resolver, util::NodeOrToken}; use std::iter::Peekable; #[derive(Debug, Clone, Copy, PartialEq, Eq, Syntax)] @@ -99,7 +99,7 @@ impl<'input, I: Iterator> Parser<'input, I> { self.handle_operation(&[Add, Sub], Self::parse_mul) } - fn parse(mut self) -> (SyntaxNode, impl Resolver) { + fn parse(mut self) -> (SyntaxNode, impl Resolver + use) { self.builder.start_node(Root); self.parse_add(); self.builder.finish_node(); diff --git a/cstree/examples/readme.rs b/cstree/examples/readme.rs index a61bf73..b8888ee 100644 --- a/cstree/examples/readme.rs +++ b/cstree/examples/readme.rs @@ -208,7 +208,7 @@ impl<'input> Parser<'input> { Ok(()) } - pub fn finish(mut self) -> (GreenNode, impl Interner) { + pub fn finish(mut self) -> (GreenNode, impl Interner + use<>) { assert!(self.lexer.next().map(|t| t == Token::EoF).unwrap_or(true)); let (tree, cache) = self.builder.finish(); (tree, cache.unwrap().into_interner().unwrap()) diff --git a/cstree/examples/s_expressions.rs b/cstree/examples/s_expressions.rs index f37b3fb..6bd94c1 100644 --- a/cstree/examples/s_expressions.rs +++ b/cstree/examples/s_expressions.rs @@ -62,7 +62,7 @@ struct Parse { /// Now, let's write a parser. /// Note that `parse` does not return a `Result`: /// By design, syntax trees can be built even for completely invalid source code. -fn parse(text: &str) -> Parse { +fn parse(text: &str) -> Parse> { struct Parser<'input> { /// input tokens, including whitespace. tokens: VecDeque<(SyntaxKind, &'input str)>, @@ -83,7 +83,7 @@ fn parse(text: &str) -> Parse { } impl Parser<'_> { - fn parse(mut self) -> Parse { + fn parse(mut self) -> Parse> { // Make sure that the root node covers all source self.builder.start_node(Root); // Parse zero or more S-expressions diff --git a/cstree/src/green/builder.rs b/cstree/src/green/builder.rs index b08b2c2..f10f80c 100644 --- a/cstree/src/green/builder.rs +++ b/cstree/src/green/builder.rs @@ -4,11 +4,12 @@ use rustc_hash::{FxHashMap, FxHasher}; use text_size::TextSize; use crate::{ + RawSyntaxKind, + Syntax, green::{GreenElement, GreenNode, GreenToken}, - interning::{new_interner, Interner, TokenInterner, TokenKey}, + interning::{Interner, TokenInterner, TokenKey, new_interner}, util::NodeOrToken, utility_types::MaybeOwned, - RawSyntaxKind, Syntax, }; use super::{node::GreenNodeHead, token::GreenTokenData}; diff --git a/cstree/src/green/element.rs b/cstree/src/green/element.rs index 00344b3..0613f70 100644 --- a/cstree/src/green/element.rs +++ b/cstree/src/green/element.rs @@ -5,10 +5,10 @@ use std::{fmt, hash, mem}; type ErasedPtr = *const u8; use crate::{ + RawSyntaxKind, green::{GreenNode, GreenToken}, text::TextSize, util::NodeOrToken, - RawSyntaxKind, }; pub(super) type GreenElement = NodeOrToken; diff --git a/cstree/src/green/iter.rs b/cstree/src/green/iter.rs index da4acad..091c2fa 100644 --- a/cstree/src/green/iter.rs +++ b/cstree/src/green/iter.rs @@ -2,7 +2,7 @@ use std::{iter::FusedIterator, slice}; -use super::{element::PackedGreenElement, GreenElementRef}; +use super::{GreenElementRef, element::PackedGreenElement}; /// An iterator over a [`GreenNode`](crate::green::GreenNode)'s children. #[derive(Debug, Clone)] diff --git a/cstree/src/green/node.rs b/cstree/src/green/node.rs index 95433be..4977e33 100644 --- a/cstree/src/green/node.rs +++ b/cstree/src/green/node.rs @@ -6,9 +6,9 @@ use std::{ use rustc_hash::FxHasher; use crate::{ - green::{iter::GreenNodeChildren, GreenElement, PackedGreenElement}, - text::TextSize, RawSyntaxKind, + green::{GreenElement, PackedGreenElement, iter::GreenNodeChildren}, + text::TextSize, }; use triomphe::{Arc, HeaderWithLength, ThinArc}; diff --git a/cstree/src/green/token.rs b/cstree/src/green/token.rs index bd7a9cf..e8013e4 100644 --- a/cstree/src/green/token.rs +++ b/cstree/src/green/token.rs @@ -1,9 +1,9 @@ use std::{fmt, hash, mem::ManuallyDrop, ptr::NonNull}; use crate::{ + RawSyntaxKind, interning::{Resolver, TokenKey}, text::TextSize, - RawSyntaxKind, }; use triomphe::Arc; diff --git a/cstree/src/interning/lasso_compat/traits.rs b/cstree/src/interning/lasso_compat/traits.rs index 9217e75..e1abb68 100644 --- a/cstree/src/interning/lasso_compat/traits.rs +++ b/cstree/src/interning/lasso_compat/traits.rs @@ -4,8 +4,8 @@ use core::fmt; use std::hash::{BuildHasher, Hash}; use crate::interning::{ - traits::{InternKey, Interner, Resolver}, TokenKey, + traits::{InternKey, Interner, Resolver}, }; // Safety: `InternKey` has the same invariant as `lasso::Key` diff --git a/cstree/src/lib.rs b/cstree/src/lib.rs index c79e70f..376dfce 100644 --- a/cstree/src/lib.rs +++ b/cstree/src/lib.rs @@ -135,10 +135,11 @@ pub mod build { /// A convenient collection of the most used parts of `cstree`. pub mod prelude { pub use crate::{ + RawSyntaxKind, + Syntax, build::GreenNodeBuilder, green::{GreenNode, GreenToken}, syntax::{SyntaxElement, SyntaxNode, SyntaxToken}, - RawSyntaxKind, Syntax, }; } diff --git a/cstree/src/serde_impls.rs b/cstree/src/serde_impls.rs index 436ac11..ae4a3bf 100644 --- a/cstree/src/serde_impls.rs +++ b/cstree/src/serde_impls.rs @@ -1,17 +1,19 @@ //! Serialization and Deserialization for syntax trees. use crate::{ + RawSyntaxKind, + Syntax, build::GreenNodeBuilder, interning::{Resolver, TokenKey}, syntax::{ResolvedNode, SyntaxNode}, traversal::WalkEvent, util::NodeOrToken, - RawSyntaxKind, Syntax, }; use serde::{ + Deserialize, + Serialize, de::{Error, SeqAccess, Visitor}, ser::SerializeTuple, - Deserialize, Serialize, }; use std::{collections::VecDeque, fmt, marker::PhantomData}; diff --git a/cstree/src/syntax/element.rs b/cstree/src/syntax/element.rs index 27fbdc4..85ab499 100644 --- a/cstree/src/syntax/element.rs +++ b/cstree/src/syntax/element.rs @@ -4,10 +4,11 @@ use text_size::{TextRange, TextSize}; use super::*; use crate::{ + RawSyntaxKind, + Syntax, green::GreenElementRef, interning::{Resolver, TokenKey}, util::{NodeOrToken, TokenAtOffset}, - RawSyntaxKind, Syntax, }; /// An element of the tree, can be either a node or a token. diff --git a/cstree/src/syntax/iter.rs b/cstree/src/syntax/iter.rs index fdc0ae1..b6c676c 100644 --- a/cstree/src/syntax/iter.rs +++ b/cstree/src/syntax/iter.rs @@ -5,9 +5,9 @@ use std::iter::FusedIterator; use text_size::TextSize; use crate::{ + Syntax, green::{GreenElementRef, GreenNodeChildren}, syntax::{SyntaxElementRef, SyntaxNode}, - Syntax, }; #[derive(Clone, Debug)] diff --git a/cstree/src/syntax/node.rs b/cstree/src/syntax/node.rs index 356e0f6..7fb6afb 100644 --- a/cstree/src/syntax/node.rs +++ b/cstree/src/syntax/node.rs @@ -2,12 +2,13 @@ use super::*; #[cfg(feature = "serialize")] use crate::serde_impls::{SerializeWithData, SerializeWithResolver}; use crate::{ + RawSyntaxKind, + Syntax, green::{GreenElementRef, GreenNode}, interning::{Resolver, TokenKey}, text::*, traversal::*, util::*, - RawSyntaxKind, Syntax, }; use parking_lot::RwLock; use std::{ @@ -17,8 +18,8 @@ use std::{ iter, ptr::{self, NonNull}, sync::{ - atomic::{AtomicU32, Ordering}, Arc as StdArc, + atomic::{AtomicU32, Ordering}, }, }; use triomphe::Arc; diff --git a/cstree/src/syntax/resolved.rs b/cstree/src/syntax/resolved.rs index 4c97301..32362b9 100644 --- a/cstree/src/syntax/resolved.rs +++ b/cstree/src/syntax/resolved.rs @@ -13,12 +13,13 @@ use std::{ use text_size::{TextRange, TextSize}; use crate::{ + RawSyntaxKind, + Syntax, green::GreenNode, interning::{Resolver, TokenKey}, syntax::*, traversal::*, util::*, - RawSyntaxKind, Syntax, }; /// Syntax tree node that is guaranteed to belong to a tree that contains an associated @@ -35,7 +36,7 @@ impl ResolvedNode { /// # Safety: /// `syntax` must belong to a tree that contains an associated inline resolver. pub(super) unsafe fn coerce_ref(syntax: &SyntaxNode) -> &Self { - &*(syntax as *const _ as *const Self) + unsafe { &*(syntax as *const _ as *const Self) } } /// Returns this node as a [`SyntaxNode`]. @@ -91,7 +92,7 @@ impl ResolvedToken { /// # Safety: /// `syntax` must belong to a tree that contains an associated inline resolver. pub(super) unsafe fn coerce_ref(syntax: &SyntaxToken) -> &Self { - &*(syntax as *const _ as *const Self) + unsafe { &*(syntax as *const _ as *const Self) } } /// Returns this token as a [`SyntaxToken`]. @@ -172,9 +173,11 @@ impl<'a, S: Syntax, D> ResolvedElementRef<'a, S, D> { /// # Safety: /// `syntax` must belong to a tree that contains an associated inline resolver. pub(super) unsafe fn coerce_ref(syntax: SyntaxElementRef<'a, S, D>) -> Self { - match syntax { - NodeOrToken::Node(node) => Self::Node(ResolvedNode::coerce_ref(node)), - NodeOrToken::Token(token) => Self::Token(ResolvedToken::coerce_ref(token)), + unsafe { + match syntax { + NodeOrToken::Node(node) => Self::Node(ResolvedNode::coerce_ref(node)), + NodeOrToken::Token(token) => Self::Token(ResolvedToken::coerce_ref(token)), + } } } } diff --git a/cstree/src/syntax/text.rs b/cstree/src/syntax/text.rs index 67bb909..1ec10e8 100644 --- a/cstree/src/syntax/text.rs +++ b/cstree/src/syntax/text.rs @@ -3,10 +3,10 @@ use std::fmt; use crate::{ + Syntax, interning::{Resolver, TokenKey}, syntax::{SyntaxNode, SyntaxToken}, text::{TextRange, TextSize}, - Syntax, }; /// An efficient representation of the text that is covered by a [`SyntaxNode`], i.e. the combined @@ -383,7 +383,7 @@ mod private { #[cfg(test)] mod tests { - use crate::{build::GreenNodeBuilder, interning::TokenInterner, RawSyntaxKind}; + use crate::{RawSyntaxKind, build::GreenNodeBuilder, interning::TokenInterner}; use super::*; @@ -409,7 +409,7 @@ mod tests { } } - fn build_tree(chunks: &[&str]) -> (SyntaxNode, impl Resolver) { + fn build_tree(chunks: &[&str]) -> (SyntaxNode, impl Resolver + use<>) { let mut builder: GreenNodeBuilder = GreenNodeBuilder::new(); builder.start_node(SyntaxKind(62)); for &chunk in chunks.iter() { diff --git a/cstree/src/syntax/token.rs b/cstree/src/syntax/token.rs index 65dd902..18bcf1d 100644 --- a/cstree/src/syntax/token.rs +++ b/cstree/src/syntax/token.rs @@ -9,10 +9,11 @@ use text_size::{TextRange, TextSize}; use super::*; use crate::{ + RawSyntaxKind, + Syntax, green::{GreenNode, GreenToken}, interning::{Resolver, TokenKey}, traversal::Direction, - RawSyntaxKind, Syntax, }; /// Syntax tree token. @@ -284,7 +285,7 @@ impl SyntaxToken { /// implementation by re-using the interner in both. /// ``` /// # use cstree::testing::*; - /// use cstree::interning::{new_interner, TokenInterner, TokenKey}; + /// use cstree::interning::{TokenInterner, TokenKey, new_interner}; /// struct TypeTable { /// // ... /// } diff --git a/cstree/tests/it/basic.rs b/cstree/tests/it/basic.rs index 207bdab..5fba9b0 100644 --- a/cstree/tests/it/basic.rs +++ b/cstree/tests/it/basic.rs @@ -1,12 +1,12 @@ use super::*; use cstree::{ - build::{GreenNodeBuilder, NodeCache}, - interning::{new_interner, Resolver}, - text::TextRange, RawSyntaxKind, + build::{GreenNodeBuilder, NodeCache}, + interning::{Resolver, new_interner}, + text::TextRange, }; -fn build_tree(root: &Element<'_>) -> (SyntaxNode, impl Resolver) { +fn build_tree(root: &Element<'_>) -> (SyntaxNode, impl Resolver + use) { let mut builder: GreenNodeBuilder = GreenNodeBuilder::new(); build_recursive(root, &mut builder, 0); let (node, cache) = builder.finish(); diff --git a/cstree/tests/it/main.rs b/cstree/tests/it/main.rs index 024bc73..cda904f 100644 --- a/cstree/tests/it/main.rs +++ b/cstree/tests/it/main.rs @@ -6,11 +6,12 @@ mod sendsync; mod serde; use cstree::{ + RawSyntaxKind, + Syntax, build::{GreenNodeBuilder, NodeCache}, green::GreenNode, interning::{Interner, Resolver}, util::NodeOrToken, - RawSyntaxKind, Syntax, }; pub type SyntaxNode = cstree::syntax::SyntaxNode; diff --git a/cstree/tests/it/sendsync.rs b/cstree/tests/it/sendsync.rs index 8bf42cf..102dcc2 100644 --- a/cstree/tests/it/sendsync.rs +++ b/cstree/tests/it/sendsync.rs @@ -3,13 +3,13 @@ use crossbeam_utils::thread::scope; use std::{thread, time::Duration}; -use super::{build_recursive, Element, ResolvedNode, SyntaxKind, SyntaxNode}; +use super::{Element, ResolvedNode, SyntaxKind, SyntaxNode, build_recursive}; use cstree::build::GreenNodeBuilder; // Excercise the multi-threaded interner when the corresponding feature is enabled. #[cfg(feature = "multi_threaded_interning")] -use cstree::interning::{new_threaded_interner, MultiThreadedTokenInterner}; +use cstree::interning::{MultiThreadedTokenInterner, new_threaded_interner}; #[cfg(not(feature = "multi_threaded_interning"))] fn get_builder() -> GreenNodeBuilder<'static, 'static, SyntaxKind> { diff --git a/cstree/tests/it/serde.rs b/cstree/tests/it/serde.rs index 6acbe57..650c85e 100644 --- a/cstree/tests/it/serde.rs +++ b/cstree/tests/it/serde.rs @@ -1,4 +1,4 @@ -use crate::{build_recursive, build_tree_with_cache, ResolvedNode}; +use crate::{ResolvedNode, build_recursive, build_tree_with_cache}; use super::{Element, SyntaxKind, SyntaxNode}; use cstree::{ diff --git a/rustfmt.toml b/rustfmt.toml index e193002..24499b2 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,6 +1,6 @@ unstable_features = true -edition = "2021" +edition = "2024" max_width = 120 comment_width = 120 @@ -10,6 +10,7 @@ format_code_in_doc_comments = true format_macro_matchers = true imports_granularity = "Crate" +imports_layout = "HorizontalVertical" reorder_impl_items = true From f531eeed290e79dd533ee2a7dfd7347f66afafca Mon Sep 17 00:00:00 2001 From: Domenic Quirl Date: Tue, 29 Jul 2025 21:04:59 +0200 Subject: [PATCH 06/10] chore: bump dependency minor versions --- cstree-derive/Cargo.toml | 6 +++--- cstree/Cargo.toml | 12 ++++++------ test_suite/Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cstree-derive/Cargo.toml b/cstree-derive/Cargo.toml index 25238a2..292ffe1 100644 --- a/cstree-derive/Cargo.toml +++ b/cstree-derive/Cargo.toml @@ -15,9 +15,9 @@ name = "cstree_derive" proc-macro = true [dependencies] -proc-macro2 = "1.0.56" -quote = "1.0.26" -syn = { version = "2.0.14" } +proc-macro2 = "1.0.95" +quote = "1.0.40" +syn = { version = "2.0.104" } [dev-dependencies] cstree = { path = "../cstree" } diff --git a/cstree/Cargo.toml b/cstree/Cargo.toml index ea48ef2..6cb21ca 100644 --- a/cstree/Cargo.toml +++ b/cstree/Cargo.toml @@ -12,15 +12,15 @@ readme.workspace = true rust-version.workspace = true [dependencies] -text-size = "1.1.0" +text-size = "1.1.1" rustc-hash = "2.1.1" -parking_lot = "0.12.1" +parking_lot = "0.12.4" # Arc -triomphe = { version = "0.1.8", default-features = false, features = ["stable_deref_trait", "std"] } +triomphe = { version = "0.1.14", default-features = false, features = ["stable_deref_trait", "std"] } # Default Interner -indexmap = "2.4.0" +indexmap = "2.10.0" [dependencies.cstree_derive] path = "../cstree-derive" @@ -28,7 +28,7 @@ version = "0.12.2" # must match the `cstree` version in the virtual w optional = true [dependencies.lasso] -version = "0.7" +version = "0.7.3" features = ["inline-more"] optional = true @@ -48,7 +48,7 @@ features = ["derive", "std"] m_lexer = "0.0.4" serde_json = "1.0" serde_test = "1.0" -crossbeam-utils = "0.8" +crossbeam-utils = "0.8.21" criterion = { version = "0.5.1", features = ["html_reports"] } [[bench]] diff --git a/test_suite/Cargo.toml b/test_suite/Cargo.toml index 4df41c1..fd665c7 100644 --- a/test_suite/Cargo.toml +++ b/test_suite/Cargo.toml @@ -13,4 +13,4 @@ rust-version.workspace = true cstree = { path = "../cstree", features = ["derive"] } [dev-dependencies] -trybuild = { version = "1.0.80", features = ["diff"] } +trybuild = { version = "1.0.106", features = ["diff"] } From e7fddb3e3d0a26790379fdde3e314e09e230a352 Mon Sep 17 00:00:00 2001 From: Domenic Quirl Date: Tue, 29 Jul 2025 21:09:40 +0200 Subject: [PATCH 07/10] chore: bump the version of `criterion` used for benchmarking --- cstree/Cargo.toml | 2 +- cstree/benches/main.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cstree/Cargo.toml b/cstree/Cargo.toml index 6cb21ca..4606b84 100644 --- a/cstree/Cargo.toml +++ b/cstree/Cargo.toml @@ -49,7 +49,7 @@ m_lexer = "0.0.4" serde_json = "1.0" serde_test = "1.0" crossbeam-utils = "0.8.21" -criterion = { version = "0.5.1", features = ["html_reports"] } +criterion = { version = "0.7.0", features = ["html_reports"] } [[bench]] name = "main" diff --git a/cstree/benches/main.rs b/cstree/benches/main.rs index 8738cb1..8baa90f 100644 --- a/cstree/benches/main.rs +++ b/cstree/benches/main.rs @@ -1,4 +1,6 @@ -use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main}; +use core::hint::black_box; + +use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use cstree::{ RawSyntaxKind, Syntax, From 9c64a715cb8fe63b62c5122d0751150f70f4be07 Mon Sep 17 00:00:00 2001 From: Domenic Quirl Date: Tue, 29 Jul 2025 21:11:35 +0200 Subject: [PATCH 08/10] bump (unreleased) crate version to 0.13.0 --- Cargo.toml | 2 +- cstree/Cargo.toml | 2 +- cstree/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b89949a..b007a5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" [workspace.package] edition = "2024" -version = "0.12.2" # when updating, also update `#![doc(html_root_url)]` and any inter-crate dependencies (such as `cstree`'s dependency on `cstree-derive`) +version = "0.13.0" # when updating, also update `#![doc(html_root_url)]` and any inter-crate dependencies (such as `cstree`'s dependency on `cstree-derive`) authors = [ "Domenic Quirl ", "Aleksey Kladov ", diff --git a/cstree/Cargo.toml b/cstree/Cargo.toml index 4606b84..393f414 100644 --- a/cstree/Cargo.toml +++ b/cstree/Cargo.toml @@ -24,7 +24,7 @@ indexmap = "2.10.0" [dependencies.cstree_derive] path = "../cstree-derive" -version = "0.12.2" # must match the `cstree` version in the virtual workspace manifest +version = "0.13.0" # must match the `cstree` version in the virtual workspace manifest optional = true [dependencies.lasso] diff --git a/cstree/src/lib.rs b/cstree/src/lib.rs index 376dfce..53f9b57 100644 --- a/cstree/src/lib.rs +++ b/cstree/src/lib.rs @@ -93,7 +93,7 @@ )] #![warn(missing_docs)] // Docs.rs -#![doc(html_root_url = "https://docs.rs/cstree/0.12.2")] +#![doc(html_root_url = "https://docs.rs/cstree/0.13.0")] #![cfg_attr(doc_cfg, feature(doc_cfg))] pub mod getting_started; From a85ed0848581d7d3703a7e479aa6c88579c1f1f2 Mon Sep 17 00:00:00 2001 From: Domenic Quirl Date: Tue, 29 Jul 2025 21:11:48 +0200 Subject: [PATCH 09/10] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f3a6f5..b24497f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * `&I` and `&mut I` will now implement `Resolver` if `I` implements `Resolver`. * `&mut I` will now implement `Interner` if `I` implements `Interner`. * Added an implementation for `Arc` to implement `Resolver` and `Interner` so an `Arc` may be used alternatively to a reference to share access to the interner. + * `SyntaxText` and the `SyntaxNodeChildren` iterator now correctly implement `Clone` independently of the generic syntax node data type `D`. + * The iterators returned by the `ancestors` methods on `SyntaxElementRef` / `ResolvedElementRef` no longer incorrectly capture the lifetime of the original syntax node (`self`). + * `cstree` was migrated to Rust edition 2024. This increases MSRV to Rust 1.85. ## `v0.12.2` From e66a5fc77563a77f0b35f69a8c3bbaddb7929302 Mon Sep 17 00:00:00 2001 From: RGBCube Date: Tue, 29 Jul 2025 18:59:54 +0300 Subject: [PATCH 10/10] text: add SyntaxText::rfind_char --- cstree/src/syntax/text.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cstree/src/syntax/text.rs b/cstree/src/syntax/text.rs index 1ec10e8..f9d9787 100644 --- a/cstree/src/syntax/text.rs +++ b/cstree/src/syntax/text.rs @@ -91,6 +91,18 @@ impl<'n, 'i, I: Resolver + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I, found(res) } + /// If `self.contains_char(c)`, returns `Some(pos)`, where `pos` is the byte position of the + /// last appearance of `c`. Otherwise, returns `None`. + pub fn rfind_char(&self, c: char) -> Option { + let mut acc: TextSize = 0.into(); + let mut res = None; + self.for_each_chunk(|chunk| { + res = chunk.rfind(c).map(|pos| acc + TextSize::from(pos as u32)).or(res); + acc += TextSize::of(chunk); + }); + res + } + /// If `offset < self.len()`, returns `Some(c)`, where `c` is the first `char` at or after /// `offset` (in bytes). Otherwise, returns `None`. pub fn char_at(&self, offset: TextSize) -> Option {