diff --git a/Cargo.lock b/Cargo.lock index 5412c0cae24335..7a69676215a8c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,6 +232,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "castaway" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.0.95" @@ -436,6 +445,20 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "serde", + "static_assertions", +] + [[package]] name = "console" version = "0.15.8" @@ -2258,6 +2281,7 @@ version = "0.0.0" dependencies = [ "aho-corasick", "bitflags 2.5.0", + "compact_str", "is-macro", "itertools 0.13.0", "once_cell", @@ -2269,7 +2293,6 @@ dependencies = [ "rustc-hash 2.0.0", "schemars", "serde", - "smol_str", ] [[package]] @@ -2355,6 +2378,7 @@ dependencies = [ "anyhow", "bitflags 2.5.0", "bstr", + "compact_str", "insta", "memchr", "ruff_python_ast", diff --git a/Cargo.toml b/Cargo.toml index 613a5fd92097f9..42c8f16000378b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ colored = { version = "2.1.0" } console_error_panic_hook = { version = "0.1.7" } console_log = { version = "1.0.0" } countme = { version = "3.0.1" } +compact_str = "0.7.1" criterion = { version = "0.5.1", default-features = false } crossbeam = { version = "0.8.4" } dashmap = { version = "5.5.3" } diff --git a/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs b/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs index aa592c828523b2..31cec1cd48be01 100644 --- a/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs +++ b/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs @@ -93,7 +93,12 @@ pub(crate) fn private_member_access(checker: &mut Checker, expr: &Expr) { return; } - if checker.settings.flake8_self.ignore_names.contains(&attr.id) { + if checker + .settings + .flake8_self + .ignore_names + .contains(attr.id()) + { return; } diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs index 811bf7c26e52f7..539e14ca85399e 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/strings.rs @@ -747,7 +747,7 @@ pub(crate) fn string_dot_format_extra_named_arguments( let missing: Vec<(usize, &Name)> = keywords .enumerate() .filter_map(|(index, keyword)| { - if summary.keywords.contains(&keyword.id) { + if summary.keywords.contains(keyword.id()) { None } else { Some((index, &keyword.id)) @@ -863,7 +863,7 @@ pub(crate) fn string_dot_format_missing_argument( .iter() .filter_map(|k| { let Keyword { arg, .. } = &k; - arg.as_ref().map(|identifier| &identifier.id) + arg.as_ref().map(|identifier| identifier.id()) }) .collect(); diff --git a/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs b/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs index e6421bd2a7d499..a1648c8438a79f 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/no_method_decorator.rs @@ -153,7 +153,7 @@ fn get_undecorated_methods(checker: &mut Checker, class_stmt: &Stmt, method_type .. }) = stmt { - let Some(decorator_call_statement) = explicit_decorator_calls.get(&name.id) else { + let Some(decorator_call_statement) = explicit_decorator_calls.get(name.id()) else { continue; }; diff --git a/crates/ruff_linter/src/rules/refurb/rules/repeated_global.rs b/crates/ruff_linter/src/rules/refurb/rules/repeated_global.rs index 2e10dc0b76adae..bf2925be935a2b 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/repeated_global.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/repeated_global.rs @@ -86,7 +86,7 @@ pub(crate) fn repeated_global(checker: &mut Checker, mut suite: &[Stmt]) { Stmt::Nonlocal(stmt) => &stmt.names, _ => unreachable!(), }) - .map(|identifier| &identifier.id) + .map(|identifier| identifier.id()) .format(", ") ), range, diff --git a/crates/ruff_python_ast/Cargo.toml b/crates/ruff_python_ast/Cargo.toml index cde90b1fbfa7ca..bd41c71b676efd 100644 --- a/crates/ruff_python_ast/Cargo.toml +++ b/crates/ruff_python_ast/Cargo.toml @@ -27,10 +27,10 @@ once_cell = { workspace = true } rustc-hash = { workspace = true } schemars = { workspace = true, optional = true } serde = { workspace = true, optional = true } -smol_str = { workspace = true } +compact_str = { workspace = true } [features] -serde = ["dep:serde", "ruff_text_size/serde", "dep:ruff_cache", "smol_str/serde", "dep:ruff_macros", "dep:schemars"] +serde = ["dep:serde", "ruff_text_size/serde", "dep:ruff_cache", "compact_str/serde", "dep:ruff_macros", "dep:schemars"] [lints] workspace = true diff --git a/crates/ruff_python_ast/src/name.rs b/crates/ruff_python_ast/src/name.rs index c72f18ec35305e..56908245fe6362 100644 --- a/crates/ruff_python_ast/src/name.rs +++ b/crates/ruff_python_ast/src/name.rs @@ -1,30 +1,32 @@ -use crate::{nodes, Expr}; -use std::borrow::Borrow; +use std::borrow::{Borrow, Cow}; use std::fmt::{Debug, Display, Formatter, Write}; use std::hash::{Hash, Hasher}; use std::ops::Deref; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +use crate::{nodes, Expr}; + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize, ruff_macros::CacheKey,) )] -pub struct Name(smol_str::SmolStr); +pub struct Name(compact_str::CompactString); impl Name { #[inline] pub fn empty() -> Self { - Self(smol_str::SmolStr::new_inline("")) + Self(compact_str::CompactString::default()) } #[inline] pub fn new(name: impl AsRef) -> Self { - Self(smol_str::SmolStr::new(name)) + Self(compact_str::CompactString::new(name)) } #[inline] pub fn new_static(name: &'static str) -> Self { - Self(smol_str::SmolStr::new_static(name)) + // TODO: Use ComactString::const_new once we upgrade to 0.8 https://github.com/ParkMyCar/compact_str/pull/336 + Self(compact_str::CompactString::from(name)) } pub fn as_str(&self) -> &str { @@ -55,12 +57,52 @@ impl Borrow for Name { } } -impl From for Name -where - T: Into, -{ - fn from(value: T) -> Self { - Self(value.into()) +impl<'a> From<&'a str> for Name { + #[inline] + fn from(s: &'a str) -> Self { + Name(s.into()) + } +} + +impl From for Name { + #[inline] + fn from(s: String) -> Self { + Name(s.into()) + } +} + +impl<'a> From<&'a String> for Name { + #[inline] + fn from(s: &'a String) -> Self { + Name(s.into()) + } +} + +impl<'a> From> for Name { + #[inline] + fn from(cow: Cow<'a, str>) -> Self { + Name(cow.into()) + } +} + +impl From> for Name { + #[inline] + fn from(b: Box) -> Self { + Name(b.into()) + } +} + +impl From for Name { + #[inline] + fn from(value: compact_str::CompactString) -> Self { + Self(value) + } +} + +impl From for compact_str::CompactString { + #[inline] + fn from(name: Name) -> Self { + name.0 } } diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index e8dbc969f17517..5e6308d0867e32 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -3777,6 +3777,10 @@ impl Identifier { } } + pub fn id(&self) -> &Name { + &self.id + } + pub fn is_valid(&self) -> bool { !self.id.is_empty() } diff --git a/crates/ruff_python_parser/Cargo.toml b/crates/ruff_python_parser/Cargo.toml index 834baac8532f86..a74a93143e28db 100644 --- a/crates/ruff_python_parser/Cargo.toml +++ b/crates/ruff_python_parser/Cargo.toml @@ -19,6 +19,7 @@ ruff_text_size = { workspace = true } bitflags = { workspace = true } bstr = { workspace = true } +compact_str = { workspace = true } memchr = { workspace = true } rustc-hash = { workspace = true } static_assertions = { workspace = true } diff --git a/crates/ruff_python_parser/src/parser/statement.rs b/crates/ruff_python_parser/src/parser/statement.rs index d09183b8eeba23..e10487e18c9c31 100644 --- a/crates/ruff_python_parser/src/parser/statement.rs +++ b/crates/ruff_python_parser/src/parser/statement.rs @@ -1,3 +1,4 @@ +use compact_str::CompactString; use std::fmt::Display; use rustc_hash::{FxBuildHasher, FxHashSet}; @@ -624,7 +625,7 @@ impl<'src> Parser<'src> { let range = self.node_range(start); return ast::Alias { name: ast::Identifier { - id: "*".into(), + id: Name::new_static("*"), range, }, asname: None, @@ -670,7 +671,7 @@ impl<'src> Parser<'src> { fn parse_dotted_name(&mut self) -> ast::Identifier { let start = self.node_start(); - let mut dotted_name = self.parse_identifier().id.to_string(); + let mut dotted_name: CompactString = self.parse_identifier().id.into(); let mut progress = ParserProgress::default(); while self.eat(TokenKind::Dot) { @@ -687,7 +688,7 @@ impl<'src> Parser<'src> { // import a.b.c // import a . b . c ast::Identifier { - id: Name::new(dotted_name), + id: Name::from(dotted_name), range: self.node_range(start), } }