use std::cmp::Ordering;
use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::LazyLock;
use std::sync::OnceLock;
use lasso::Spur;
use lasso::ThreadedRodeo;
use parking_lot::RwLock;
use vortex_error::VortexExpect;
use vortex_utils::aliases::dash_map::DashMap;
static INTERNER: LazyLock<ThreadedRodeo> = LazyLock::new(ThreadedRodeo::new);
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Id(Spur);
impl Id {
pub fn new(s: &str) -> Self {
Self(INTERNER.get_or_intern(s))
}
pub fn new_static(s: &'static str) -> Self {
Self(INTERNER.get_or_intern_static(s))
}
pub fn as_str(&self) -> &str {
let s = INTERNER.resolve(&self.0);
unsafe { &*(s as *const str) }
}
}
impl From<&str> for Id {
fn from(s: &str) -> Self {
Self::new(s)
}
}
impl Display for Id {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl Debug for Id {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Id(\"{}\")", self.as_str())
}
}
impl PartialOrd for Id {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Id {
fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
impl AsRef<str> for Id {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl PartialEq<&Id> for Id {
fn eq(&self, other: &&Id) -> bool {
self == *other
}
}
impl PartialEq<Id> for &Id {
fn eq(&self, other: &Id) -> bool {
*self == other
}
}
pub struct CachedId {
s: &'static str,
cached: OnceLock<Id>,
}
impl CachedId {
pub const fn new(s: &'static str) -> Self {
Self {
s,
cached: OnceLock::new(),
}
}
}
impl Deref for CachedId {
type Target = Id;
fn deref(&self) -> &Id {
self.cached.get_or_init(|| Id::new(self.s))
}
}
#[derive(Clone, Debug)]
pub struct Registry<T>(Arc<DashMap<Id, T>>);
impl<T> Default for Registry<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T: Clone> Registry<T> {
pub fn empty() -> Self {
Self(Default::default())
}
pub fn ids(&self) -> impl Iterator<Item = Id> + '_ {
self.0.iter().map(|i| *i.key())
}
pub fn items(&self) -> impl Iterator<Item = T> + '_ {
self.0.iter().map(|i| i.value().clone())
}
pub fn find_many<'a>(
&self,
ids: impl IntoIterator<Item = &'a Id>,
) -> impl Iterator<Item = Option<impl Deref<Target = T>>> {
ids.into_iter().map(|id| self.0.get(id))
}
pub fn find(&self, id: &Id) -> Option<T> {
self.0.get(id).as_deref().cloned()
}
pub fn register(&self, id: impl Into<Id>, item: impl Into<T>) {
self.0.insert(id.into(), item.into());
}
pub fn with(self, id: impl Into<Id>, item: impl Into<T>) -> Self {
self.register(id, item.into());
self
}
}
#[derive(Clone, Debug)]
pub struct ReadContext {
ids: Arc<[Id]>,
}
impl ReadContext {
pub fn new(ids: impl Into<Arc<[Id]>>) -> Self {
Self { ids: ids.into() }
}
pub fn resolve(&self, idx: u16) -> Option<Id> {
self.ids.get(idx as usize).cloned()
}
pub fn ids(&self) -> &[Id] {
&self.ids
}
}
#[derive(Clone, Debug)]
pub struct Context<T> {
ids: Arc<RwLock<Vec<Id>>>,
registry: Option<Registry<T>>,
}
impl<T> Default for Context<T> {
fn default() -> Self {
Self {
ids: Arc::new(RwLock::new(Vec::new())),
registry: None,
}
}
}
impl<T: Clone> Context<T> {
pub fn new(ids: Vec<Id>) -> Self {
Self {
ids: Arc::new(RwLock::new(ids)),
registry: None,
}
}
pub fn empty() -> Self {
Self::default()
}
pub fn with_registry(mut self, registry: Registry<T>) -> Self {
self.registry = Some(registry);
self
}
pub fn intern(&self, id: &Id) -> Option<u16> {
if let Some(registry) = &self.registry
&& registry.find(id).is_none()
{
return None;
}
let mut ids = self.ids.write();
if let Some(idx) = ids.iter().position(|e| e == id) {
return Some(u16::try_from(idx).vortex_expect("Cannot have more than u16::MAX items"));
}
let idx = ids.len();
assert!(
idx < u16::MAX as usize,
"Cannot have more than u16::MAX items"
);
ids.push(*id);
Some(u16::try_from(idx).vortex_expect("checked already"))
}
pub fn to_ids(&self) -> Vec<Id> {
self.ids.read().clone()
}
}