1use std::collections::BTreeMap;
2
3use parking_lot::Mutex;
4use re_chunk_store::MissingChunkReporter;
5use vec1::Vec1;
6
7use re_chunk::{ArchetypeName, ComponentType};
8use re_sdk_types::blueprint::components::VisualizerInstructionId;
9use re_sdk_types::{Archetype, ComponentDescriptor, ComponentIdentifier, ComponentSet};
10
11use crate::{
12 IdentifiedViewSystem, ViewContext, ViewContextCollection, ViewQuery, ViewSystemExecutionError,
13 ViewSystemIdentifier,
14};
15
16#[derive(Debug, Clone, Default)]
17pub struct SortedComponentSet(linked_hash_map::LinkedHashMap<ComponentDescriptor, ()>);
18
19impl SortedComponentSet {
20 pub fn insert(&mut self, k: ComponentDescriptor) -> Option<()> {
21 self.0.insert(k, ())
22 }
23
24 pub fn extend(&mut self, iter: impl IntoIterator<Item = ComponentDescriptor>) {
25 self.0.extend(iter.into_iter().map(|k| (k, ())));
26 }
27
28 pub fn iter(&self) -> linked_hash_map::Keys<'_, ComponentDescriptor, ()> {
29 self.0.keys()
30 }
31
32 pub fn contains(&self, k: &ComponentDescriptor) -> bool {
33 self.0.contains_key(k)
34 }
35}
36
37impl FromIterator<ComponentDescriptor> for SortedComponentSet {
38 fn from_iter<I: IntoIterator<Item = ComponentDescriptor>>(iter: I) -> Self {
39 Self(iter.into_iter().map(|k| (k, ())).collect())
40 }
41}
42
43pub type DatatypeSet = std::collections::BTreeSet<arrow::datatypes::DataType>;
44
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct AnyPhysicalDatatypeRequirement {
47 pub target_component: ComponentIdentifier,
49
50 pub semantic_type: ComponentType,
54
55 pub physical_types: DatatypeSet,
59
60 pub allow_static_data: bool,
64}
65
66impl From<AnyPhysicalDatatypeRequirement> for RequiredComponents {
67 fn from(req: AnyPhysicalDatatypeRequirement) -> Self {
68 Self::AnyPhysicalDatatype(req)
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Default)]
74pub enum RequiredComponents {
75 #[default]
77 None,
78
79 AllComponents(ComponentSet),
81
82 AnyComponent(ComponentSet),
84
85 AnyPhysicalDatatype(AnyPhysicalDatatypeRequirement),
89}
90
91pub struct VisualizerQueryInfo {
93 pub relevant_archetype: Option<ArchetypeName>,
96
97 pub required: RequiredComponents,
99
100 pub queried: SortedComponentSet, }
108
109impl VisualizerQueryInfo {
110 pub fn from_archetype<A: Archetype>() -> Self {
111 Self {
112 relevant_archetype: A::name().into(),
113 required: RequiredComponents::AllComponents(
114 A::required_components()
115 .iter()
116 .map(|c| c.component)
117 .collect(),
118 ),
119 queried: A::all_components().iter().cloned().collect(),
120 }
121 }
122
123 pub fn empty() -> Self {
124 Self {
125 relevant_archetype: Default::default(),
126 required: RequiredComponents::None,
127 queried: SortedComponentSet::default(),
128 }
129 }
130
131 pub fn queried_components(&self) -> impl Iterator<Item = ComponentIdentifier> {
133 self.queried.iter().map(|desc| desc.component)
134 }
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
141pub enum VisualizerReportSeverity {
142 Warning,
146
147 Error,
151
152 OverallVisualizerError,
154}
155
156#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
158pub struct VisualizerReportContext {
159 pub component: Option<ComponentIdentifier>,
163
164 pub extra: Option<String>,
166}
167
168impl re_byte_size::SizeBytes for VisualizerReportContext {
169 fn heap_size_bytes(&self) -> u64 {
170 self.extra.heap_size_bytes()
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Hash)]
194pub struct VisualizerInstructionReport {
195 pub severity: VisualizerReportSeverity,
196 pub context: VisualizerReportContext,
197
198 pub summary: String,
200
201 pub details: Option<String>,
203}
204
205impl re_byte_size::SizeBytes for VisualizerInstructionReport {
206 fn heap_size_bytes(&self) -> u64 {
207 self.summary.heap_size_bytes()
208 + self.details.heap_size_bytes()
209 + self.context.heap_size_bytes()
210 }
211}
212
213impl VisualizerInstructionReport {
214 pub fn error(summary: impl Into<String>) -> Self {
216 Self {
217 severity: VisualizerReportSeverity::Error,
218 summary: summary.into(),
219 details: None,
220 context: VisualizerReportContext::default(),
221 }
222 }
223
224 pub fn warning(summary: impl Into<String>) -> Self {
226 Self {
227 severity: VisualizerReportSeverity::Warning,
228 summary: summary.into(),
229 details: None,
230 context: VisualizerReportContext::default(),
231 }
232 }
233}
234
235#[derive(Default)]
237pub struct VisualizerExecutionOutput {
238 pub draw_data: Vec<re_renderer::QueueableDrawData>,
242
243 pub reports_per_instruction:
251 Mutex<BTreeMap<VisualizerInstructionId, Vec1<VisualizerInstructionReport>>>,
252
253 missing_chunk_reporter: MissingChunkReporter,
255 }
261
262impl VisualizerExecutionOutput {
263 pub fn set_missing_chunks(&self) {
265 self.missing_chunk_reporter.report_missing_chunk();
266 }
267
268 pub fn any_missing_chunks(&self) -> bool {
270 self.missing_chunk_reporter.any_missing()
271 }
272
273 pub fn missing_chunk_reporter(&self) -> &MissingChunkReporter {
275 &self.missing_chunk_reporter
276 }
277
278 pub fn report_error_for(
280 &self,
281 instruction_id: VisualizerInstructionId,
282 error: impl Into<String>,
283 ) {
284 let report = VisualizerInstructionReport::error(error);
286 self.reports_per_instruction
287 .lock()
288 .entry(instruction_id)
289 .and_modify(|v| v.push(report.clone()))
290 .or_insert_with(|| vec1::vec1![report]);
291 }
292
293 pub fn report_warning_for(
295 &self,
296 instruction_id: VisualizerInstructionId,
297 warning: impl Into<String>,
298 ) {
299 let report = VisualizerInstructionReport::warning(warning);
301 self.reports_per_instruction
302 .lock()
303 .entry(instruction_id)
304 .and_modify(|v| v.push(report.clone()))
305 .or_insert_with(|| vec1::vec1![report]);
306 }
307
308 pub fn report(
310 &self,
311 instruction_id: VisualizerInstructionId,
312 report: VisualizerInstructionReport,
313 ) {
314 self.reports_per_instruction
315 .lock()
316 .entry(instruction_id)
317 .and_modify(|v| v.push(report.clone()))
318 .or_insert_with(|| vec1::vec1![report]);
319 }
320
321 pub fn with_draw_data(
322 mut self,
323 draw_data: impl IntoIterator<Item = re_renderer::QueueableDrawData>,
324 ) -> Self {
325 self.draw_data.extend(draw_data);
326 self
327 }
328}
329
330pub trait VisualizerSystem: Send + Sync + std::any::Any {
334 fn visualizer_query_info(&self, app_options: &crate::AppOptions) -> VisualizerQueryInfo;
342
343 fn execute(
347 &mut self,
348 ctx: &ViewContext<'_>,
349 query: &ViewQuery<'_>,
350 context_systems: &ViewContextCollection,
351 ) -> Result<VisualizerExecutionOutput, ViewSystemExecutionError>;
352
353 fn data(&self) -> Option<&dyn std::any::Any> {
359 None
360 }
361}
362
363pub struct VisualizerCollection {
364 pub systems: BTreeMap<ViewSystemIdentifier, Box<dyn VisualizerSystem>>,
365}
366
367impl VisualizerCollection {
368 #[inline]
369 pub fn get<T: VisualizerSystem + IdentifiedViewSystem + 'static>(
370 &self,
371 ) -> Result<&T, ViewSystemExecutionError> {
372 self.systems
373 .get(&T::identifier())
374 .and_then(|s| (s.as_ref() as &dyn std::any::Any).downcast_ref())
375 .ok_or_else(|| {
376 ViewSystemExecutionError::VisualizerSystemNotFound(T::identifier().as_str())
377 })
378 }
379
380 #[inline]
381 pub fn get_by_type_identifier(
382 &self,
383 name: ViewSystemIdentifier,
384 ) -> Result<&dyn VisualizerSystem, ViewSystemExecutionError> {
385 self.systems
386 .get(&name)
387 .map(|s| s.as_ref())
388 .ok_or_else(|| ViewSystemExecutionError::VisualizerSystemNotFound(name.as_str()))
389 }
390
391 #[inline]
392 pub fn iter(&self) -> impl Iterator<Item = &dyn VisualizerSystem> {
393 self.systems.values().map(|s| s.as_ref())
394 }
395
396 #[inline]
397 pub fn iter_with_identifiers(
398 &self,
399 ) -> impl Iterator<Item = (ViewSystemIdentifier, &dyn VisualizerSystem)> {
400 self.systems.iter().map(|s| (*s.0, s.1.as_ref()))
401 }
402
403 pub fn iter_visualizer_data<SpecificData: 'static>(
405 &self,
406 ) -> impl Iterator<Item = &'_ SpecificData> {
407 self.iter()
408 .filter_map(|visualizer| visualizer.data()?.downcast_ref::<SpecificData>())
409 }
410}