cl-structures: Cleanup for GlobalSym
This commit is contained in:
parent
be604b7b45
commit
ede00c3c86
@ -7,42 +7,48 @@ use std::{
|
|||||||
sync::{OnceLock, RwLock},
|
sync::{OnceLock, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Holds a globally accessible [Interner] which uses [GlobalSym] as its [Symbol]
|
||||||
static GLOBAL_INTERNER: OnceLock<RwLock<Interner<GlobalSym>>> = OnceLock::new();
|
static GLOBAL_INTERNER: OnceLock<RwLock<Interner<GlobalSym>>> = OnceLock::new();
|
||||||
|
|
||||||
/// Gets the [GlobalSym] associated with this string, if there is one, or creates a new one
|
/// A unique identifier corresponding to a particular interned [String].
|
||||||
///
|
///
|
||||||
/// # Blocks
|
/// Copies of that string can be obtained with [GlobalSym::get] or [String::try_from].
|
||||||
/// Locks the Global Interner for writing. If it is already locked,
|
|
||||||
/// # May Panic
|
|
||||||
/// T
|
|
||||||
pub fn get_or_insert(s: &str) -> GlobalSym {
|
|
||||||
GLOBAL_INTERNER
|
|
||||||
.get_or_init(Default::default)
|
|
||||||
.write()
|
|
||||||
.expect("global interner should not have been held by a panicked thread")
|
|
||||||
.get_or_insert(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the [GlobalSym] associated with this string, if there is one
|
|
||||||
pub fn get(s: &str) -> Option<GlobalSym> {
|
|
||||||
GLOBAL_INTERNER.get()?.read().ok()?.get(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the [String] associated with this [GlobalSym], if there is one
|
|
||||||
///
|
///
|
||||||
/// Returns none if the global symbol table is poisoned.
|
/// New strings can be interned with [GlobalSym::new] or [GlobalSym::from]
|
||||||
pub fn get_string(sym: GlobalSym) -> Option<String> {
|
|
||||||
sym.try_into().ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct GlobalSym(NonZeroU32);
|
pub struct GlobalSym(NonZeroU32);
|
||||||
|
|
||||||
impl GlobalSym {
|
impl GlobalSym {
|
||||||
/// Gets a [GlobalSym] associated with the given string, if one exists
|
/// Gets the interned [GlobalSym] for the given value, or interns a new one.
|
||||||
|
///
|
||||||
|
/// # Blocks
|
||||||
|
/// This conversion blocks if the Global Interner lock is held.
|
||||||
|
///
|
||||||
|
/// # May Panic
|
||||||
|
/// Panics if the Global Interner's lock has been poisoned by a panic in another thread
|
||||||
|
pub fn new(value: &str) -> Self {
|
||||||
|
GLOBAL_INTERNER
|
||||||
|
.get_or_init(Default::default)
|
||||||
|
.write()
|
||||||
|
.expect("global interner should not be poisoned in another thread")
|
||||||
|
.get_or_insert(value)
|
||||||
|
}
|
||||||
|
/// Gets a [GlobalSym] associated with the given string, if one already exists
|
||||||
pub fn try_from_str(value: &str) -> Option<Self> {
|
pub fn try_from_str(value: &str) -> Option<Self> {
|
||||||
GLOBAL_INTERNER.get()?.read().ok()?.get(value)
|
GLOBAL_INTERNER.get()?.read().ok()?.get(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a copy of the value of the [GlobalSym]
|
||||||
|
// TODO: Make this copy-less
|
||||||
|
pub fn get(self) -> Option<String> {
|
||||||
|
String::try_from(self).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Looks up the string associated with this [GlobalSym],
|
||||||
|
/// and performs a transformation on it if it exists.
|
||||||
|
pub fn map<T>(&self, f: impl Fn(&str) -> T) -> Option<T> {
|
||||||
|
Some(f(GLOBAL_INTERNER.get()?.read().ok()?.get_str(*self)?))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for GlobalSym {
|
impl Display for GlobalSym {
|
||||||
@ -70,7 +76,7 @@ impl Symbol for GlobalSym {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for GlobalSym {
|
impl<T: AsRef<str>> From<T> for GlobalSym {
|
||||||
/// Converts to this type from the input type.
|
/// Converts to this type from the input type.
|
||||||
///
|
///
|
||||||
/// # Blocks
|
/// # Blocks
|
||||||
@ -78,12 +84,8 @@ impl From<&str> for GlobalSym {
|
|||||||
///
|
///
|
||||||
/// # May Panic
|
/// # May Panic
|
||||||
/// Panics if the Global Interner's lock has been poisoned by a panic in another thread
|
/// Panics if the Global Interner's lock has been poisoned by a panic in another thread
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: T) -> Self {
|
||||||
GLOBAL_INTERNER
|
Self::new(value.as_ref())
|
||||||
.get_or_init(Default::default)
|
|
||||||
.write()
|
|
||||||
.expect("global interner should not be poisoned in another thread")
|
|
||||||
.get_or_insert(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,19 +10,25 @@ fn globalsym_from_returns_unique_value_for_unique_keys() {
|
|||||||
assert_eq!(foo_baz, GlobalSym::from("foo_baz"));
|
assert_eq!(foo_baz, GlobalSym::from("foo_baz"));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn get_returns_none_before_init() {
|
fn try_from_str_returns_none_before_init() {
|
||||||
if let Some(value) = get("") {
|
if let Some(value) = GlobalSym::try_from_str("") {
|
||||||
panic!("{value}")
|
panic!("{value}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn get_returns_some_when_key_exists() {
|
fn try_from_str_returns_some_when_key_exists() {
|
||||||
let _ = GlobalSym::from("foo_bar");
|
let _ = GlobalSym::from("foo_bar");
|
||||||
assert!(dbg!(get("foo_bar")).is_some());
|
assert!(dbg!(GlobalSym::try_from_str("foo_bar")).is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_returns_the_same_thing_as_globalsym_from() {
|
fn try_from_str_returns_the_same_thing_as_globalsym_from() {
|
||||||
let foo_bar = GlobalSym::from("foo_bar");
|
let foo_bar = GlobalSym::from("foo_bar");
|
||||||
assert_eq!(Some(foo_bar), get("foo_bar"));
|
assert_eq!(Some(foo_bar), GlobalSym::try_from_str("foo_bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_works() {
|
||||||
|
let foo_bar = GlobalSym::from("foo_bar");
|
||||||
|
assert!(foo_bar.map(|sym| "foo_bar" == sym).unwrap());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user