use std::borrow::Cow;
use crate::fx::FxHashMap as HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::OnceLock;
static RENAMES: OnceLock<HashMap<String, String>> = OnceLock::new();
static REVERSE: OnceLock<HashMap<String, String>> = OnceLock::new();
static FIELD_RENAMES: OnceLock<HashMap<std::sync::Arc<str>, Vec<FieldRename>>> = OnceLock::new();
static FIELD_ACTIVE: AtomicBool = AtomicBool::new(false);
static FIELD_OWNERS: OnceLock<std::collections::HashSet<std::sync::Arc<str>>> = OnceLock::new();
pub struct FieldRename {
pub name: std::sync::Arc<str>,
pub desc: std::sync::Arc<str>,
pub display: std::sync::Arc<str>,
}
pub fn set_field_renames(map: HashMap<std::sync::Arc<str>, Vec<FieldRename>>) {
if !map.is_empty() {
FIELD_ACTIVE.store(true, Ordering::Relaxed);
let _ = FIELD_OWNERS.set(
map.iter()
.filter(|(_, v)| !v.is_empty())
.map(|(k, _)| k.clone())
.collect(),
);
}
let _ = FIELD_RENAMES.set(map);
}
#[inline]
pub fn owner_has_renames(owner: &str) -> bool {
FIELD_ACTIVE.load(Ordering::Relaxed)
&& FIELD_OWNERS.get().is_some_and(|s| s.contains(owner))
}
#[inline]
pub fn member_rename_active() -> bool {
FIELD_ACTIVE.load(Ordering::Relaxed)
}
#[inline]
pub fn field_display(owner: &str, name: &str, desc: &str) -> Option<&'static str> {
if !FIELD_ACTIVE.load(Ordering::Relaxed) {
return None;
}
FIELD_RENAMES
.get()?
.get(owner)?
.iter()
.find(|fr| &*fr.name == name && &*fr.desc == desc)
.map(|fr| fr.display.as_ref())
}
static ACTIVE: AtomicBool = AtomicBool::new(false);
pub fn with_renames<R>(f: impl FnOnce(&HashMap<String, String>) -> R) -> Option<R> {
RENAMES.get().map(f)
}
pub fn set_class_renames(map: HashMap<String, String>) {
if !map.is_empty() {
ACTIVE.store(true, Ordering::Relaxed);
}
let rev: HashMap<String, String> = map
.iter()
.filter(|(k, v)| k != v)
.map(|(k, v)| (v.clone(), k.clone()))
.collect();
let _ = REVERSE.set(rev);
let _ = RENAMES.set(map);
}
#[inline]
pub fn is_renamed_display(internal: &str) -> bool {
REVERSE.get().is_some_and(|m| m.contains_key(internal))
}
#[inline]
pub fn unrename_class(internal: &str) -> Cow<'_, str> {
if !ACTIVE.load(Ordering::Relaxed) {
return Cow::Borrowed(internal);
}
let Some(map) = REVERSE.get() else {
return Cow::Borrowed(internal);
};
if let Some(o) = map.get(internal) {
return Cow::Owned(o.clone());
}
let mut s = internal;
while let Some(i) = s.rfind('$') {
if s.as_bytes().get(i + 1) == Some(&b'/') {
s = &s[..i];
continue;
}
s = &s[..i];
if let Some(o) = map.get(s) {
let suffix = &internal[s.len()..];
return Cow::Owned(format!("{o}{suffix}"));
}
}
Cow::Borrowed(internal)
}
#[inline]
pub fn apply_class_rename(internal: &str) -> Cow<'_, str> {
if !ACTIVE.load(Ordering::Relaxed) {
return Cow::Borrowed(internal);
}
let Some(map) = RENAMES.get() else {
return Cow::Borrowed(internal);
};
if let Some(d) = map.get(internal) {
return if d == internal {
Cow::Borrowed(internal)
} else {
Cow::Owned(d.clone())
};
}
let mut s = internal;
while let Some(i) = s.rfind('$') {
if s.as_bytes().get(i + 1) == Some(&b'/') {
s = &s[..i];
continue;
}
s = &s[..i];
match map.get(s) {
Some(d) if d != s => {
let suffix = &internal[s.len()..];
return Cow::Owned(format!("{d}{suffix}"));
}
Some(_) => return Cow::Borrowed(internal),
None => continue,
}
}
Cow::Borrowed(internal)
}