vortex_session/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4pub 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/// A Vortex session encapsulates the set of extensible arrays, layouts, compute functions, dtypes,
22/// etc. that are available for use in a given context.
23///
24/// It is also the entry-point passed to dynamic libraries to initialize Vortex plugins.
25#[derive(Clone, Debug)]
26pub struct VortexSession(Arc<SessionVars>);
27
28impl VortexSession {
29    /// Create a new [`VortexSession`] with no session state.
30    ///
31    /// It is recommended to use the `default()` method instead provided by the main `vortex` crate.
32    pub fn empty() -> Self {
33        Self(Default::default())
34    }
35
36    /// Inserts a new session variable of type `V` with its default value.
37    ///
38    /// # Panics
39    ///
40    /// If a variable of that type already exists.
41    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
57/// Trait for accessing and modifying the state of a Vortex session.
58pub trait SessionExt: Sized + private::Sealed {
59    /// Returns the [`VortexSession`].
60    fn session(&self) -> VortexSession;
61
62    /// Returns the scope variable of type `V`, or inserts a default one if it does not exist.
63    fn get<V: SessionVar>(&self) -> Ref<'_, V>;
64
65    /// Returns the scope variable of type `V`, or inserts a default one if it does not exist.
66    ///
67    /// Note that the returned value internally holds a lock on the variable.
68    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    /// Returns the scope variable of type `V`, or inserts a default one if it does not exist.
82    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    /// Returns the scope variable of type `V`, or inserts a default one if it does not exist.
98    ///
99    /// Note that the returned value internally holds a lock on the variable.
100    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
117/// A TypeMap based on `https://docs.rs/http/1.2.0/src/http/extensions.rs.html#41-266`.
118type SessionVars = DashMap<TypeId, Box<dyn SessionVar>, BuildHasherDefault<IdHasher>>;
119
120/// With TypeIds as keys, there's no need to hash them. They are already hashes
121/// themselves, coming from the compiler. The IdHasher just holds the u64 of
122/// the TypeId, and then returns it, instead of doing any bit fiddling.
123#[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
142/// This trait defines variables that can be stored against a Vortex session.
143pub 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
158// NOTE(ngates): we don't want to expose that the internals of a session is a DashMap, so we have
159// our own wrapped Ref type.
160pub 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    /// Map this reference to a different target.
170    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    /// Map this mutable reference to a different target.
193    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}