1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
use std::collections::BTreeMap;

use re_types::{Archetype, ComponentName, ComponentNameSet};

use crate::{
    ApplicableEntities, ComponentFallbackProvider, IdentifiedViewSystem,
    SpaceViewSystemExecutionError, ViewContext, ViewContextCollection, ViewQuery,
    ViewSystemIdentifier, VisualizableEntities, VisualizableFilterContext,
    VisualizerAdditionalApplicabilityFilter,
};

#[derive(Debug, Clone, Default)]
pub struct SortedComponentNameSet(linked_hash_map::LinkedHashMap<ComponentName, ()>);

impl SortedComponentNameSet {
    pub fn insert(&mut self, k: ComponentName) -> Option<()> {
        self.0.insert(k, ())
    }

    pub fn extend(&mut self, iter: impl IntoIterator<Item = ComponentName>) {
        self.0.extend(iter.into_iter().map(|k| (k, ())));
    }

    pub fn iter(&self) -> linked_hash_map::Keys<'_, ComponentName, ()> {
        self.0.keys()
    }

    pub fn contains(&self, k: &ComponentName) -> bool {
        self.0.contains_key(k)
    }
}

impl FromIterator<ComponentName> for SortedComponentNameSet {
    fn from_iter<I: IntoIterator<Item = ComponentName>>(iter: I) -> Self {
        Self(iter.into_iter().map(|k| (k, ())).collect())
    }
}

pub struct VisualizerQueryInfo {
    /// These are not required, but if _any_ of these are found, it is a strong indication that this
    /// system should be active (if also the `required_components` are found).
    pub indicators: ComponentNameSet,

    /// Returns the minimal set of components that the system _requires_ in order to be instantiated.
    ///
    /// This does not include indicator components.
    pub required: ComponentNameSet,

    /// Returns the list of components that the system _queries_.
    ///
    /// Must include required, usually excludes indicators.
    /// Order should reflect order in archetype docs & user code as well as possible.
    pub queried: SortedComponentNameSet,
}

impl VisualizerQueryInfo {
    pub fn from_archetype<T: Archetype>() -> Self {
        Self {
            indicators: std::iter::once(T::indicator().name()).collect(),
            required: T::required_components()
                .iter()
                .map(ToOwned::to_owned)
                .collect(),
            queried: T::all_components().iter().map(ToOwned::to_owned).collect(),
        }
    }

    pub fn empty() -> Self {
        Self {
            indicators: ComponentNameSet::new(),
            required: ComponentNameSet::new(),
            queried: SortedComponentNameSet::default(),
        }
    }
}

/// Element of a scene derived from a single archetype query.
///
/// Is populated after scene contexts and has access to them.
///
/// All visualizers are expected to be able to provide a fallback value for any component they're using
/// via the [`ComponentFallbackProvider`] trait.
pub trait VisualizerSystem: Send + Sync + 'static {
    // TODO(andreas): This should be able to list out the ContextSystems it needs.

    /// Information about which components are queried by the visualizer.
    fn visualizer_query_info(&self) -> VisualizerQueryInfo;

    /// Filters a set of applicable entities (entities that have all required components),
    /// into to a set of visualizable entities.
    ///
    /// The context passed in here is generated by [`crate::SpaceViewClass::visualizable_filter_context`].
    #[inline]
    fn filter_visualizable_entities(
        &self,
        entities: ApplicableEntities,
        _context: &dyn VisualizableFilterContext,
    ) -> VisualizableEntities {
        VisualizableEntities(entities.0)
    }

    /// Additional filter for applicability.
    ///
    /// If none is specified, applicability is solely determined by required components.
    fn applicability_filter(&self) -> Option<Box<dyn VisualizerAdditionalApplicabilityFilter>> {
        None
    }

    /// Queries the chunk store and performs data conversions to make it ready for display.
    ///
    /// Mustn't query any data outside of the archetype.
    fn execute(
        &mut self,
        ctx: &ViewContext<'_>,
        query: &ViewQuery<'_>,
        context_systems: &ViewContextCollection,
    ) -> Result<Vec<re_renderer::QueueableDrawData>, SpaceViewSystemExecutionError>;

    /// Optionally retrieves a chunk store reference from the scene element.
    ///
    /// This is useful for retrieving data that is common to several visualizers of a [`crate::SpaceViewClass`].
    /// For example, if most visualizers produce ui elements, a concrete [`crate::SpaceViewClass`]
    /// can pick those up in its [`crate::SpaceViewClass::ui`] method by iterating over all visualizers.
    fn data(&self) -> Option<&dyn std::any::Any> {
        None
    }

    fn as_any(&self) -> &dyn std::any::Any;

    /// Returns the fallback provider for this visualizer.
    ///
    /// Visualizers should use this to report the fallback values they use when there is no data.
    /// The Rerun viewer will display these fallback values to the user to convey what the
    /// visualizer is doing.
    fn fallback_provider(&self) -> &dyn ComponentFallbackProvider;
}

pub struct VisualizerCollection {
    pub systems: BTreeMap<ViewSystemIdentifier, Box<dyn VisualizerSystem>>,
}

impl VisualizerCollection {
    #[inline]
    pub fn get<T: VisualizerSystem + IdentifiedViewSystem + 'static>(
        &self,
    ) -> Result<&T, SpaceViewSystemExecutionError> {
        self.systems
            .get(&T::identifier())
            .and_then(|s| s.as_any().downcast_ref())
            .ok_or_else(|| {
                SpaceViewSystemExecutionError::VisualizerSystemNotFound(T::identifier().as_str())
            })
    }

    #[inline]
    pub fn get_by_identifier(
        &self,
        name: ViewSystemIdentifier,
    ) -> Result<&dyn VisualizerSystem, SpaceViewSystemExecutionError> {
        self.systems
            .get(&name)
            .map(|s| s.as_ref())
            .ok_or_else(|| SpaceViewSystemExecutionError::VisualizerSystemNotFound(name.as_str()))
    }

    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = &dyn VisualizerSystem> {
        self.systems.values().map(|s| s.as_ref())
    }

    #[inline]
    pub fn iter_with_identifiers(
        &self,
    ) -> impl Iterator<Item = (ViewSystemIdentifier, &dyn VisualizerSystem)> {
        self.systems.iter().map(|s| (*s.0, s.1.as_ref()))
    }

    /// Iterate over all visualizer data that can be downcast to the given type.
    pub fn iter_visualizer_data<SpecificData: 'static>(
        &self,
    ) -> impl Iterator<Item = &'_ SpecificData> {
        self.iter().filter_map(|visualizer| {
            visualizer
                .data()
                .and_then(|data| data.downcast_ref::<SpecificData>())
        })
    }
}