1pub mod registry;
5
6use std::any::Any;
7use std::any::TypeId;
8use std::any::type_name;
9use std::fmt::Debug;
10use std::hash::BuildHasherDefault;
11use std::hash::Hasher;
12use std::ops::Deref;
13use std::ops::DerefMut;
14use std::sync::Arc;
15
16use dashmap::DashMap;
17use dashmap::Entry;
18use vortex_error::VortexExpect;
19use vortex_error::vortex_panic;
20
21#[derive(Clone, Debug)]
26pub struct VortexSession(Arc<SessionVars>);
27
28impl VortexSession {
29 pub fn empty() -> Self {
33 Self(Default::default())
34 }
35
36 pub fn with<V: SessionVar + Default>(self) -> Self {
42 match self.0.entry(TypeId::of::<V>()) {
43 Entry::Occupied(_) => {
44 vortex_panic!(
45 "Session variable of type {} already exists",
46 type_name::<V>()
47 );
48 }
49 Entry::Vacant(e) => {
50 e.insert(Box::new(V::default()));
51 }
52 }
53 self
54 }
55}
56
57pub trait SessionExt: Sized + private::Sealed {
59 fn session(&self) -> VortexSession;
61
62 fn get<V: SessionVar>(&self) -> Ref<'_, V>;
64
65 fn get_mut<V: SessionVar>(&self) -> RefMut<'_, V>;
69}
70
71mod private {
72 pub trait Sealed {}
73 impl Sealed for super::VortexSession {}
74}
75
76impl SessionExt for VortexSession {
77 fn session(&self) -> VortexSession {
78 self.clone()
79 }
80
81 fn get<V: SessionVar>(&self) -> Ref<'_, V> {
83 Ref(self
84 .0
85 .get(&TypeId::of::<V>())
86 .unwrap_or_else(|| {
87 vortex_panic!("Session has not been initialized with {}", type_name::<V>())
88 })
89 .map(|v| {
90 (**v)
91 .as_any()
92 .downcast_ref::<V>()
93 .vortex_expect("Type mismatch - this is a bug")
94 }))
95 }
96
97 fn get_mut<V: SessionVar>(&self) -> RefMut<'_, V> {
101 RefMut(
102 self.0
103 .get_mut(&TypeId::of::<V>())
104 .unwrap_or_else(|| {
105 vortex_panic!("Session has not been initialized with {}", type_name::<V>())
106 })
107 .map(|v| {
108 (**v)
109 .as_any_mut()
110 .downcast_mut::<V>()
111 .vortex_expect("Type mismatch - this is a bug")
112 }),
113 )
114 }
115}
116
117type SessionVars = DashMap<TypeId, Box<dyn SessionVar>, BuildHasherDefault<IdHasher>>;
119
120#[derive(Default)]
124struct IdHasher(u64);
125
126impl Hasher for IdHasher {
127 #[inline]
128 fn finish(&self) -> u64 {
129 self.0
130 }
131
132 fn write(&mut self, _: &[u8]) {
133 unreachable!("TypeId calls write_u64");
134 }
135
136 #[inline]
137 fn write_u64(&mut self, id: u64) {
138 self.0 = id;
139 }
140}
141
142pub trait SessionVar: Any + Send + Sync + Debug + 'static {
144 fn as_any(&self) -> &dyn Any;
145 fn as_any_mut(&mut self) -> &mut dyn Any;
146}
147
148impl<T: Send + Sync + Debug + 'static> SessionVar for T {
149 fn as_any(&self) -> &dyn Any {
150 self
151 }
152
153 fn as_any_mut(&mut self) -> &mut dyn Any {
154 self
155 }
156}
157
158pub struct Ref<'a, T>(dashmap::mapref::one::MappedRef<'a, TypeId, Box<dyn SessionVar>, T>);
161impl<'a, T> Deref for Ref<'a, T> {
162 type Target = T;
163
164 fn deref(&self) -> &Self::Target {
165 &self.0
166 }
167}
168impl<'a, T> Ref<'a, T> {
169 pub fn map<F, U>(self, f: F) -> Ref<'a, U>
171 where
172 F: FnOnce(&T) -> &U,
173 {
174 Ref(self.0.map(f))
175 }
176}
177
178pub struct RefMut<'a, T>(dashmap::mapref::one::MappedRefMut<'a, TypeId, Box<dyn SessionVar>, T>);
179impl<'a, T> Deref for RefMut<'a, T> {
180 type Target = T;
181
182 fn deref(&self) -> &Self::Target {
183 &self.0
184 }
185}
186impl<'a, T> DerefMut for RefMut<'a, T> {
187 fn deref_mut(&mut self) -> &mut Self::Target {
188 self.0.deref_mut()
189 }
190}
191impl<'a, T> RefMut<'a, T> {
192 pub fn map<F, U>(self, f: F) -> RefMut<'a, U>
194 where
195 F: FnOnce(&mut T) -> &mut U,
196 {
197 RefMut(self.0.map(f))
198 }
199}