pub mod registry;
use std::any::Any;
use std::any::TypeId;
use std::any::type_name;
use std::fmt::Debug;
use std::hash::BuildHasherDefault;
use std::hash::Hasher;
use std::ops::Deref;
use std::ops::DerefMut;
use std::sync::Arc;
use dashmap::DashMap;
use dashmap::Entry;
use vortex_error::VortexExpect;
use vortex_error::vortex_panic;
#[derive(Clone, Debug)]
pub struct VortexSession(Arc<SessionVars>);
impl VortexSession {
pub fn empty() -> Self {
Self(Default::default())
}
pub fn with<V: SessionVar + Default>(self) -> Self {
match self.0.entry(TypeId::of::<V>()) {
Entry::Occupied(_) => {
vortex_panic!(
"Session variable of type {} already exists",
type_name::<V>()
);
}
Entry::Vacant(e) => {
e.insert(Box::new(V::default()));
}
}
self
}
}
pub trait SessionExt: Sized + private::Sealed {
fn session(&self) -> VortexSession;
fn get<V: SessionVar + Default>(&self) -> Ref<'_, V>;
fn get_opt<V: SessionVar>(&self) -> Option<Ref<'_, V>>;
fn get_mut<V: SessionVar + Default>(&self) -> RefMut<'_, V>;
fn get_mut_opt<V: SessionVar>(&self) -> Option<RefMut<'_, V>>;
}
mod private {
pub trait Sealed {}
impl Sealed for super::VortexSession {}
}
impl SessionExt for VortexSession {
fn session(&self) -> VortexSession {
self.clone()
}
fn get<V: SessionVar + Default>(&self) -> Ref<'_, V> {
if let Some(v) = self.0.get(&TypeId::of::<V>()) {
return Ref(v.map(|v| {
(**v)
.as_any()
.downcast_ref::<V>()
.vortex_expect("Type mismatch - this is a bug")
}));
}
Ref(self
.0
.entry(TypeId::of::<V>())
.or_insert_with(|| Box::new(V::default()))
.downgrade()
.map(|v| {
(**v)
.as_any()
.downcast_ref::<V>()
.vortex_expect("Type mismatch - this is a bug")
}))
}
fn get_opt<V: SessionVar>(&self) -> Option<Ref<'_, V>> {
self.0.get(&TypeId::of::<V>()).map(|v| {
Ref(v.map(|v| {
(**v)
.as_any()
.downcast_ref::<V>()
.vortex_expect("Type mismatch - this is a bug")
}))
})
}
fn get_mut<V: SessionVar + Default>(&self) -> RefMut<'_, V> {
RefMut(
self.0
.entry(TypeId::of::<V>())
.or_insert_with(|| Box::new(V::default()))
.map(|v| {
(**v)
.as_any_mut()
.downcast_mut::<V>()
.vortex_expect("Type mismatch - this is a bug")
}),
)
}
fn get_mut_opt<V: SessionVar>(&self) -> Option<RefMut<'_, V>> {
self.0.get_mut(&TypeId::of::<V>()).map(|v| {
RefMut(v.map(|v| {
(**v)
.as_any_mut()
.downcast_mut::<V>()
.vortex_expect("Type mismatch - this is a bug")
}))
})
}
}
type SessionVars = DashMap<TypeId, Box<dyn SessionVar>, BuildHasherDefault<IdHasher>>;
#[derive(Default)]
struct IdHasher(u64);
impl Hasher for IdHasher {
#[inline]
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, _: &[u8]) {
unreachable!("TypeId calls write_u64");
}
#[inline]
fn write_u64(&mut self, id: u64) {
self.0 = id;
}
}
pub trait SessionVar: Any + Send + Sync + Debug + 'static {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T: Send + Sync + Debug + 'static> SessionVar for T {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
pub struct Ref<'a, T>(dashmap::mapref::one::MappedRef<'a, TypeId, Box<dyn SessionVar>, T>);
impl<'a, T> Deref for Ref<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, T> Ref<'a, T> {
pub fn map<F, U>(self, f: F) -> Ref<'a, U>
where
F: FnOnce(&T) -> &U,
{
Ref(self.0.map(f))
}
}
pub struct RefMut<'a, T>(dashmap::mapref::one::MappedRefMut<'a, TypeId, Box<dyn SessionVar>, T>);
impl<'a, T> Deref for RefMut<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, T> DerefMut for RefMut<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.deref_mut()
}
}
impl<'a, T> RefMut<'a, T> {
pub fn map<F, U>(self, f: F) -> RefMut<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
{
RefMut(self.0.map(f))
}
}