vortex_layout/reader_context.rs
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::any::Any;
5use std::sync::Arc;
6
7use vortex_session::registry::Id;
8use vortex_utils::aliases::hash_map::HashMap;
9
10/// Per-reader-tree dependency context, threaded through [`crate::VTable::new_reader`].
11///
12/// Holds an [`Id`]-keyed registry of `Arc<dyn Any>` values. Ancestors publish via
13/// [`Self::with`]; descendants retrieve via [`Self::get`]. This is a *read-only* channel
14/// from the descendant's perspective — they can only consume what an ancestor chose to
15/// publish.
16///
17/// [`Self::with`] returns a derived context that copies the existing map and inserts or
18/// replaces one entry — original unchanged, so concurrent reader-tree constructions each
19/// derive their own context without races. Contexts are cheap to clone via internal `Arc`
20/// and can be captured by lazy children helpers.
21#[derive(Clone, Default)]
22pub struct LayoutReaderContext {
23 values: Arc<HashMap<Id, Arc<dyn Any + Send + Sync>>>,
24}
25
26impl std::fmt::Debug for LayoutReaderContext {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.debug_struct("LayoutReaderContext")
29 .field("ids", &self.values.keys().collect::<Vec<_>>())
30 .finish()
31 }
32}
33
34impl LayoutReaderContext {
35 /// Creates a new, empty context.
36 pub fn new() -> Self {
37 Self::default()
38 }
39
40 /// Returns a new context that publishes `value` under `id`.
41 ///
42 /// The original context is unchanged. If a value was already published under the
43 /// same `id`, the new one replaces it in the returned context — so two ancestors
44 /// using the same well-known static id give descendants "nearest ancestor wins".
45 pub fn with<T: Any + Send + Sync>(&self, id: Id, value: Arc<T>) -> Self {
46 let mut values = HashMap::clone(&self.values);
47 values.insert(id, value);
48 Self {
49 values: Arc::new(values),
50 }
51 }
52
53 /// Returns the value published under `id`, downcast to `T`. Returns `None` if no
54 /// ancestor published under that id, or if the published value is not a `T`.
55 pub fn get<T: Any + Send + Sync>(&self, id: Id) -> Option<Arc<T>> {
56 self.values
57 .get(&id)
58 .and_then(|v| Arc::clone(v).downcast::<T>().ok())
59 }
60}