From 33c497bf227dcd574f1f63d2063636daaaa912fb Mon Sep 17 00:00:00 2001 From: Simon Ask Ulsnes Date: Tue, 16 Dec 2025 15:31:41 +0100 Subject: [PATCH] Replace Symbol impl with stringleton --- Cargo.lock | 51 ++++++++ Cargo.toml | 1 + tests/Cargo.toml | 1 + tests/lib.rs | 2 + tests/test_expressions.rs | 2 +- tests/test_outdatedness.rs | 2 +- tests/test_path_resolution.rs | 23 ++-- werk-fs/Cargo.toml | 1 + werk-fs/sym.rs | 2 +- werk-parser/Cargo.toml | 1 + werk-parser/ast.rs | 2 +- werk-parser/ast/string.rs | 3 +- werk-parser/parser/string.rs | 3 +- werk-runner/Cargo.toml | 1 + werk-runner/cache.rs | 2 +- werk-runner/eval.rs | 3 +- werk-runner/eval/string.rs | 3 +- werk-runner/eval/used.rs | 2 +- werk-runner/ir.rs | 3 +- werk-runner/lib.rs | 2 + werk-runner/outdatedness.rs | 2 +- werk-runner/runner.rs | 7 +- werk-runner/runner/task.rs | 2 +- werk-runner/scope.rs | 64 +++------- werk-runner/workspace.rs | 3 +- werk-util/lib.rs | 2 - werk-util/symbol.rs | 221 ---------------------------------- 27 files changed, 109 insertions(+), 302 deletions(-) delete mode 100644 werk-util/symbol.rs diff --git a/Cargo.lock b/Cargo.lock index 766ccd3b..23098e5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -531,6 +531,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "ctor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e" + [[package]] name = "ctrlc" version = "3.5.1" @@ -1151,6 +1157,26 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29fc123b2f6600099ca18248f69e3ee02b09c4188c0d98e9a690d90dec3e408a" +[[package]] +name = "linkme" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3283ed2d0e50c06dd8602e0ab319bb048b6325d0bba739db64ed8205179898" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5cec0ec4228b4853bb129c84dbf093a27e6c7a20526da046defc334a1b017f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -1754,6 +1780,27 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stringleton" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f44e65a6af54fa159199b353dd00227b68f08e0113f3b5f406b6d36cdaa4ef37" +dependencies = [ + "ctor", + "linkme", + "stringleton-registry", +] + +[[package]] +name = "stringleton-registry" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3367599ca3efb8bbf1f7cda51e9dba9c7a8f020ec966737640ae453239e52ea" +dependencies = [ + "hashbrown", + "serde", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1810,6 +1857,7 @@ dependencies = [ "regex", "smol", "smol-macros", + "stringleton", "toml_edit", "tracing", "tracing-subscriber", @@ -2210,6 +2258,7 @@ name = "werk-fs" version = "0.1.0" dependencies = [ "serde", + "stringleton", "thiserror", "werk-util", "winnow", @@ -2225,6 +2274,7 @@ dependencies = [ "regex", "serde", "serde_json", + "stringleton", "thiserror", "unicode-ident", "werk-util", @@ -2251,6 +2301,7 @@ dependencies = [ "rustc-stable-hash", "serde", "smol", + "stringleton", "thiserror", "toml_edit", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 93734517..230d34e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ toml_edit = "0.23.9" futures = "0.3.31" annotate-snippets = "0.12.10" anstream = "0.6.18" +stringleton = { version = "0.2.1", features = ["serde"] } [workspace.lints.clippy] pedantic = { level = "warn", priority = -1 } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 56a4cd10..00876e43 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -25,6 +25,7 @@ werk-util.workspace = true anstream.workspace = true # Hijacking winnow for the Offset trait winnow.workspace = true +stringleton.workspace = true [dev-dependencies] criterion = "0.8.1" diff --git a/tests/lib.rs b/tests/lib.rs index bcb92e24..4f7c5c44 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,2 +1,4 @@ // This file intentionally left blank. pub mod mock_io; + +stringleton::enable!(werk_runner); diff --git a/tests/test_expressions.rs b/tests/test_expressions.rs index 090c62ba..1791a1db 100644 --- a/tests/test_expressions.rs +++ b/tests/test_expressions.rs @@ -1,7 +1,7 @@ use werk_runner::Value; +use stringleton::Symbol; use tests::mock_io::*; -use werk_util::Symbol; fn evaluate_global(source: &str, global_variable_name_to_check: &str) -> Value { let mut test = Test::new(source).unwrap(); diff --git a/tests/test_outdatedness.rs b/tests/test_outdatedness.rs index 2f72f94d..35964878 100644 --- a/tests/test_outdatedness.rs +++ b/tests/test_outdatedness.rs @@ -2,9 +2,9 @@ use macro_rules_attribute::apply; use tests::mock_io; use mock_io::*; +use stringleton::Symbol; use werk_fs::{Absolute, Path}; use werk_runner::{BuildStatus, Outdatedness, Reason, ShellCommandLine, TaskId}; -use werk_util::Symbol; static WERK: &str = r#" config profile = env "PROFILE" diff --git a/tests/test_path_resolution.rs b/tests/test_path_resolution.rs index 87599275..1ac624c2 100644 --- a/tests/test_path_resolution.rs +++ b/tests/test_path_resolution.rs @@ -1,8 +1,11 @@ use macro_rules_attribute::apply; +use stringleton::sym; use tests::mock_io::*; use werk_fs::Absolute; use werk_runner::{Runner, TaskId, Value}; -use werk_util::{Annotated, Symbol}; +use werk_util::Annotated; + +stringleton::enable!(tests); #[test] fn test_path_resolution() { @@ -44,41 +47,35 @@ let exists-not-explicit-workspace = "" }; let globals = &workspace.manifest.global_variables; assert_eq!( - globals.get(&Symbol::new("exists-resolved")).unwrap().value, + globals.get(&sym!("exists-resolved")).unwrap().value, Value::from(foo_workspace.clone()) ); assert_eq!( - globals - .get(&Symbol::new("exists-explicit-out-dir")) - .unwrap() - .value, + globals.get(&sym!("exists-explicit-out-dir")).unwrap().value, Value::from(foo_output) ); assert_eq!( globals - .get(&Symbol::new("exists-explicit-workspace")) + .get(&sym!("exists-explicit-workspace")) .unwrap() .value, Value::from(foo_workspace.clone()) ); assert_eq!( - globals - .get(&Symbol::new("exists-not-resolved")) - .unwrap() - .value, + globals.get(&sym!("exists-not-resolved")).unwrap().value, Value::from(bar_output.clone()) ); assert_eq!( globals - .get(&Symbol::new("exists-not-explicit-out-dir")) + .get(&sym!("exists-not-explicit-out-dir")) .unwrap() .value, Value::from(bar_output.clone()) ); assert_eq!( globals - .get(&Symbol::new("exists-not-explicit-workspace")) + .get(&sym!("exists-not-explicit-workspace")) .unwrap() .value, Value::from(bar_workspace) diff --git a/werk-fs/Cargo.toml b/werk-fs/Cargo.toml index 590d16b0..c97cf9bc 100644 --- a/werk-fs/Cargo.toml +++ b/werk-fs/Cargo.toml @@ -13,6 +13,7 @@ winnow.workspace = true thiserror.workspace = true serde.workspace = true werk-util.workspace = true +stringleton.workspace = true [lints] workspace = true diff --git a/werk-fs/sym.rs b/werk-fs/sym.rs index f8b340cb..ab5239a1 100644 --- a/werk-fs/sym.rs +++ b/werk-fs/sym.rs @@ -1,4 +1,4 @@ -use werk_util::Symbol; +use stringleton::Symbol; use crate::{Absolute, Path, PathBuf}; diff --git a/werk-parser/Cargo.toml b/werk-parser/Cargo.toml index 5bc9eb95..4cc00aab 100644 --- a/werk-parser/Cargo.toml +++ b/werk-parser/Cargo.toml @@ -20,6 +20,7 @@ regex.workspace = true annotate-snippets.workspace = true serde.workspace = true werk-util.workspace = true +stringleton.workspace = true [dev-dependencies] anstream.workspace = true diff --git a/werk-parser/ast.rs b/werk-parser/ast.rs index ec849f00..1d98cb10 100644 --- a/werk-parser/ast.rs +++ b/werk-parser/ast.rs @@ -9,7 +9,7 @@ pub mod token; pub use expr::*; pub use string::*; -use werk_util::Symbol; +use stringleton::Symbol; /// Whitespace and comments within statements and expressions (not doc /// comments). diff --git a/werk-parser/ast/string.rs b/werk-parser/ast/string.rs index 59aaf985..1e8ae580 100644 --- a/werk-parser/ast/string.rs +++ b/werk-parser/ast/string.rs @@ -1,6 +1,7 @@ use std::{fmt::Write, hash::Hash as _}; -use werk_util::{SemanticHash, Span, Symbol}; +use stringleton::Symbol; +use werk_util::{SemanticHash, Span}; use crate::parser::{ escape_pattern_literal, escape_string_literal, parse_pattern_expr_unquoted, diff --git a/werk-parser/parser/string.rs b/werk-parser/parser/string.rs index 50a3d7ca..b80bc895 100644 --- a/werk-parser/parser/string.rs +++ b/werk-parser/parser/string.rs @@ -6,7 +6,8 @@ use crate::{ fatal, parser::{Input, Parser as _}, }; -use werk_util::{Offset, Symbol}; +use stringleton::Symbol; +use werk_util::Offset; use winnow::{ Parser, ascii::{dec_int, digit1, multispace1}, diff --git a/werk-runner/Cargo.toml b/werk-runner/Cargo.toml index edde224d..37fa6cd9 100644 --- a/werk-runner/Cargo.toml +++ b/werk-runner/Cargo.toml @@ -34,6 +34,7 @@ memchr = "2.7.4" annotate-snippets.workspace = true werk-util.workspace = true bitflags = "2.8.0" +stringleton.workspace = true [lints] workspace = true diff --git a/werk-runner/cache.rs b/werk-runner/cache.rs index 30eb6c52..8838eab6 100644 --- a/werk-runner/cache.rs +++ b/werk-runner/cache.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; +use stringleton::Symbol; use werk_fs::Absolute; -use werk_util::Symbol; /// The contents of `.werk-cache`. #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] diff --git a/werk-runner/eval.rs b/werk-runner/eval.rs index 90d2c40f..342bface 100644 --- a/werk-runner/eval.rs +++ b/werk-runner/eval.rs @@ -1,10 +1,11 @@ mod string; mod used; pub(crate) use string::*; +use stringleton::Symbol; pub use used::*; use werk_fs::Absolute; -use werk_util::{DiagnosticFileId, Spanned as _, Symbol}; +use werk_util::{DiagnosticFileId, Spanned as _}; use std::sync::Arc; diff --git a/werk-runner/eval/string.rs b/werk-runner/eval/string.rs index b3275eab..a6b207c0 100644 --- a/werk-runner/eval/string.rs +++ b/werk-runner/eval/string.rs @@ -1,9 +1,10 @@ use std::{borrow::Cow, fmt::Write as _, sync::Arc}; use indexmap::IndexMap; +use stringleton::Symbol; use werk_fs::Absolute; use werk_parser::ast; -use werk_util::{DiagnosticFileId, DiagnosticSpan, Symbol}; +use werk_util::{DiagnosticFileId, DiagnosticSpan}; use crate::{ AmbiguousPatternError, EvalError, Lookup, LookupValue, Pattern, PatternMatcher, PatternRegex, diff --git a/werk-runner/eval/used.rs b/werk-runner/eval/used.rs index dff3ab3d..beaa267a 100644 --- a/werk-runner/eval/used.rs +++ b/werk-runner/eval/used.rs @@ -3,8 +3,8 @@ use std::{ ops::{BitOr, BitOrAssign}, }; +use stringleton::Symbol; use werk_fs::{Absolute, SymPath}; -use werk_util::Symbol; use crate::cache::Hash128; diff --git a/werk-runner/ir.rs b/werk-runner/ir.rs index 1950efb6..153da82b 100644 --- a/werk-runner/ir.rs +++ b/werk-runner/ir.rs @@ -1,7 +1,8 @@ use indexmap::IndexMap; +use stringleton::Symbol; use werk_fs::Absolute; use werk_parser::ast; -use werk_util::{DiagnosticFileId, DiagnosticMainSourceMap, DiagnosticSpan, Symbol}; +use werk_util::{DiagnosticFileId, DiagnosticMainSourceMap, DiagnosticSpan}; use crate::{ AmbiguousPatternError, ConfigVar, EvalError, LocalVariables, Pattern, PatternMatchData, Value, diff --git a/werk-runner/lib.rs b/werk-runner/lib.rs index a2288fa4..5e8c7adf 100644 --- a/werk-runner/lib.rs +++ b/werk-runner/lib.rs @@ -30,3 +30,5 @@ pub use which::Error as WhichError; #[doc(no_inline)] pub use globset; + +stringleton::enable!(); diff --git a/werk-runner/outdatedness.rs b/werk-runner/outdatedness.rs index 127cd12c..cc46b1a6 100644 --- a/werk-runner/outdatedness.rs +++ b/werk-runner/outdatedness.rs @@ -3,8 +3,8 @@ use std::{ ops::{BitOr, BitOrAssign}, }; +use stringleton::Symbol; use werk_fs::{Absolute, SymPath}; -use werk_util::Symbol; use crate::{ TaskId, Workspace, diff --git a/werk-runner/runner.rs b/werk-runner/runner.rs index 94aab2f9..2791751d 100644 --- a/werk-runner/runner.rs +++ b/werk-runner/runner.rs @@ -3,8 +3,9 @@ use std::{future::Future, sync::Arc, time::SystemTime}; use futures::{StreamExt, channel::oneshot, future}; use indexmap::{IndexMap, map::Entry}; use parking_lot::Mutex; +use stringleton::sym; use werk_fs::{Absolute, Normalize as _, Path, SymPath}; -use werk_util::{Annotated, AsDiagnostic, DiagnosticSpan, Symbol, cancel}; +use werk_util::{Annotated, AsDiagnostic, DiagnosticSpan, cancel}; use crate::{ AmbiguousPatternError, BuildRecipeScope, ChildCaptureOutput, ChildLinesStream, Env, Error, @@ -378,7 +379,7 @@ impl<'a> Inner<'a> { ) -> Result { let mut scope = BuildRecipeScope::new(self.workspace, task_id, &recipe_match); scope.set( - Symbol::new("out"), + sym!("out"), Eval::inherent(Value::from(recipe_match.target_file.to_string())), ); @@ -514,7 +515,7 @@ impl<'a> Inner<'a> { // Make the `depfile` variable available to the recipe body. scope.set( - Symbol::from("depfile"), + sym!("depfile"), Eval::inherent(Value::String(depfile.clone())), ); diff --git a/werk-runner/runner/task.rs b/werk-runner/runner/task.rs index f555b666..24c1ad1f 100644 --- a/werk-runner/runner/task.rs +++ b/werk-runner/runner/task.rs @@ -1,6 +1,6 @@ use futures::channel::oneshot; +use stringleton::Symbol; use werk_fs::{Absolute, SymPath}; -use werk_util::Symbol; use crate::{Error, ir}; diff --git a/werk-runner/scope.rs b/werk-runner/scope.rs index 5c9cd641..b1112e4c 100644 --- a/werk-runner/scope.rs +++ b/werk-runner/scope.rs @@ -1,5 +1,6 @@ use ahash::HashMap; -use werk_util::{DiagnosticSpan, Symbol, SymbolRegistryLock}; +use stringleton::{Symbol, sym}; +use werk_util::DiagnosticSpan; use crate::{ Io, PatternMatchData, Render, TaskId, Value, Warning, Workspace, @@ -345,37 +346,24 @@ pub fn default_global_constants() -> &'static HashMap { std::sync::OnceLock::new(); GLOBAL_CONSTANTS.get_or_init(|| { let mut map = HashMap::default(); - let mut sym = SymbolRegistryLock::lock(); map.extend([ - (sym.insert("EMPTY"), Value::from(String::new())), + (sym!(EMPTY), Value::from(String::new())), + (sym!(EXE_SUFFIX), Value::from(exe_suffix().to_owned())), + (sym!(DYLIB_PREFIX), Value::from(dylib_prefix().to_owned())), + (sym!(DYLIB_SUFFIX), Value::from(dylib_suffix().to_owned())), ( - sym.insert("EXE_SUFFIX"), - Value::from(exe_suffix().to_owned()), - ), - ( - sym.insert("DYLIB_PREFIX"), - Value::from(dylib_prefix().to_owned()), - ), - ( - sym.insert("DYLIB_SUFFIX"), - Value::from(dylib_suffix().to_owned()), - ), - ( - sym.insert("STATICLIB_PREFIX"), + sym!(STATICLIB_PREFIX), Value::from(staticlib_prefix().to_owned()), ), ( - sym.insert("STATICLIB_SUFFIX"), + sym!(STATICLIB_SUFFIX), Value::from(staticlib_suffix().to_owned()), ), - (sym.insert("OS"), Value::from(current_os().to_owned())), - ( - sym.insert("OS_FAMILY"), - Value::from(current_os_family().to_owned()), - ), - (sym.insert("ARCH"), Value::from(current_arch().to_owned())), + (sym!(OS), Value::from(current_os().to_owned())), + (sym!(OS_FAMILY), Value::from(current_os_family().to_owned())), + (sym!(ARCH), Value::from(current_arch().to_owned())), ( - sym.insert("ARCH_FAMILY"), + sym!(ARCH_FAMILY), Value::from(current_arch_family().to_owned()), ), ]); @@ -383,26 +371,6 @@ pub fn default_global_constants() -> &'static HashMap { }) } -pub struct SymCache { - pub symbol_in: Symbol, - pub symbol_out: Symbol, - pub symbol_color: Symbol, -} - -impl SymCache { - pub fn get() -> &'static SymCache { - static CACHE: std::sync::OnceLock = std::sync::OnceLock::new(); - CACHE.get_or_init(|| { - let mut sym = SymbolRegistryLock::lock(); - SymCache { - symbol_in: sym.insert("in"), - symbol_out: sym.insert("out"), - symbol_color: sym.insert("COLOR"), - } - }) - } -} - impl Scope for Workspace { fn get(&self, name: Lookup) -> Option> { let Lookup::Ident(name) = name else { @@ -428,8 +396,7 @@ impl Scope for Workspace { } // Runtime constants. - let cache = SymCache::get(); - if name == cache.symbol_color { + if name == sym!(COLOR) { return Some(LookupValue::Owned(Eval::inherent(Value::from( if self.force_color { "1" } else { "0" }.to_owned(), )))); @@ -500,10 +467,9 @@ impl Scope for BuildRecipeScope<'_> { Lookup::InputFile => Some(LookupValue::ValueRef(Eval::inherent(&self.input_files))), Lookup::OutputFile => Some(LookupValue::ValueRef(Eval::inherent(&self.output_file))), Lookup::Ident(name) => { - let sym_cache = SymCache::get(); - if name == sym_cache.symbol_in { + if name == sym!(in) { return Some(LookupValue::ValueRef(Eval::inherent(&self.input_files))); - } else if name == sym_cache.symbol_out { + } else if name == sym!(out) { return Some(LookupValue::ValueRef(Eval::inherent(&self.output_file))); } diff --git a/werk-runner/workspace.rs b/werk-runner/workspace.rs index e640fd05..19b6205e 100644 --- a/werk-runner/workspace.rs +++ b/werk-runner/workspace.rs @@ -2,9 +2,10 @@ use ahash::HashMap; use indexmap::IndexMap; use parking_lot::Mutex; use std::{borrow::Cow, collections::hash_map, sync::Arc}; +use stringleton::Symbol; use werk_fs::{Absolute, Normalize as _, PathError}; use werk_parser::ast; -use werk_util::{DiagnosticFileId, DiagnosticSpan, Symbol}; +use werk_util::{DiagnosticFileId, DiagnosticSpan}; use crate::{ DirEntry, Error, EvalError, Io, Render, Value, Warning, diff --git a/werk-util/lib.rs b/werk-util/lib.rs index f3290d1e..62479d3c 100644 --- a/werk-util/lib.rs +++ b/werk-util/lib.rs @@ -3,10 +3,8 @@ mod diagnostic; mod os_str; mod semantic_hash; mod span; -mod symbol; pub use diagnostic::*; pub use os_str::*; pub use semantic_hash::*; pub use span::*; -pub use symbol::*; diff --git a/werk-util/symbol.rs b/werk-util/symbol.rs deleted file mode 100644 index ccf6f4ee..00000000 --- a/werk-util/symbol.rs +++ /dev/null @@ -1,221 +0,0 @@ -use std::borrow::Borrow; - -use hashbrown::{HashMap, hash_map::EntryRef}; -use parking_lot::{Mutex, MutexGuard}; - -#[derive(Clone, Copy, Eq)] -pub struct Symbol(&'static &'static str); - -impl PartialEq for Symbol { - #[inline] - fn eq(&self, other: &Self) -> bool { - std::ptr::eq(self.0, other.0) - } -} - -impl std::hash::Hash for Symbol { - #[inline] - fn hash(&self, state: &mut H) { - std::ptr::hash(self.0.as_ptr(), state); - } -} - -impl PartialOrd for Symbol { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Symbol { - #[inline] - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - (self.0.as_ptr() as usize).cmp(&(other.0.as_ptr() as usize)) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -struct SymStr(&'static &'static str); -impl From<&str> for SymStr { - #[inline] - fn from(s: &str) -> SymStr { - let string: &'static str = s.to_string().leak(); - let leaked: &'static &'static str = Box::leak(Box::new(string)); - Self(leaked) - } -} -impl Borrow for SymStr { - #[inline] - fn borrow(&self) -> &str { - self.0 - } -} - -struct Registry { - by_name: HashMap, -} -static REGISTRY: Mutex = Mutex::new(Registry { - by_name: HashMap::with_hasher(ahash::RandomState::with_seeds( - 0xb944_112d_2c57_0bb2, - 0xa9e3_3d0c_afb0_6253, - 0x9038_b72c_8d04_99f6, - 0x3715_c24b_7e23_6bf4, - )), -}); - -impl Symbol { - #[inline] - #[must_use] - pub fn new(string: &str) -> Symbol { - SymbolRegistryLock::lock().insert(string) - } - - #[inline] - #[must_use] - pub fn get(string: &str) -> Option { - SymbolRegistryLock::lock().get(string) - } - - #[inline] - #[must_use] - pub fn as_str(self) -> &'static str { - self.0 - } -} - -impl std::fmt::Debug for Symbol { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.as_str(), f) - } -} - -impl std::fmt::Display for Symbol { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.as_str(), f) - } -} - -impl AsRef for Symbol { - #[inline] - fn as_ref(&self) -> &str { - self.as_str() - } -} - -impl From<&str> for Symbol { - #[inline] - fn from(string: &str) -> Symbol { - Symbol::new(string) - } -} - -impl PartialEq for Symbol { - #[inline] - fn eq(&self, other: &str) -> bool { - self.as_str() == other - } -} - -impl PartialEq for str { - #[inline] - fn eq(&self, other: &Symbol) -> bool { - self == other.as_str() - } -} - -impl PartialEq<&str> for Symbol { - #[inline] - fn eq(&self, other: &&str) -> bool { - self.as_str() == *other - } -} - -impl PartialEq for &str { - #[inline] - fn eq(&self, other: &Symbol) -> bool { - *self == other.as_str() - } -} - -/// Bulk-registration of symbols. -pub struct SymbolRegistryLock { - lock: MutexGuard<'static, Registry>, -} - -impl SymbolRegistryLock { - #[inline] - #[must_use] - pub fn lock() -> Self { - Self { - lock: REGISTRY.lock(), - } - } - - #[inline] - #[must_use] - pub fn get(&self, string: &str) -> Option { - let (key, ()) = self.lock.by_name.get_key_value(string)?; - Some(Symbol(key.0)) - } - - #[inline] - #[must_use] - pub fn get_str(&self, sym: Symbol) -> &'static str { - sym.0 - } - - #[inline] - #[must_use] - pub fn insert(&mut self, string: &str) -> Symbol { - let registry = &mut *self.lock; - match registry.by_name.entry_ref(string) { - EntryRef::Occupied(occupied_entry) => Symbol(occupied_entry.key().0), - EntryRef::Vacant(vacant_entry_ref) => { - // String is leaked here via `SymStr::from`. - let occupied = vacant_entry_ref.insert_entry(()); - Symbol(occupied.key().0) - } - } - } -} - -impl serde::Serialize for Symbol { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.as_str().serialize(serializer) - } -} - -impl<'de> serde::Deserialize<'de> for Symbol { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let string = >::deserialize(deserializer)?; - Ok(Symbol::new(&string)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn basic() { - let i = 123; - - // Two different heap pointers. - let a = format!("hello {i}"); - let b = format!("hello {i}"); - - let a = Symbol::new(&a); - let b = Symbol::new(&b); - - assert_eq!(a, b); - assert_eq!(a.0.as_ptr(), b.0.as_ptr()); - } -}