use std::collections::BTreeMap;
use parking_lot::Mutex;
use re_chunk_store::MissingChunkReporter;
use vec1::Vec1;
use re_chunk::ArchetypeName;
use re_sdk_types::blueprint::components::VisualizerInstructionId;
use re_sdk_types::{ComponentDescriptor, ComponentIdentifier};
use crate::{
BufferAndFormatConstraint, IdentifiedViewSystem, SingleRequiredComponentConstraint,
ViewContext, ViewContextCollection, ViewQuery, ViewSystemExecutionError, ViewSystemIdentifier,
VisualizabilityConstraints,
};
#[derive(Debug, Clone, Default)]
pub struct SortedComponentSet(linked_hash_map::LinkedHashMap<ComponentDescriptor, ()>);
impl SortedComponentSet {
pub fn insert(&mut self, k: ComponentDescriptor) -> Option<()> {
self.0.insert(k, ())
}
pub fn extend(&mut self, iter: impl IntoIterator<Item = ComponentDescriptor>) {
self.0.extend(iter.into_iter().map(|k| (k, ())));
}
pub fn iter(&self) -> linked_hash_map::Keys<'_, ComponentDescriptor, ()> {
self.0.keys()
}
pub fn contains(&self, k: &ComponentDescriptor) -> bool {
self.0.contains_key(k)
}
}
impl FromIterator<ComponentDescriptor> for SortedComponentSet {
fn from_iter<I: IntoIterator<Item = ComponentDescriptor>>(iter: I) -> Self {
Self(iter.into_iter().map(|k| (k, ())).collect())
}
}
pub struct VisualizerQueryInfo {
pub relevant_archetype: Option<ArchetypeName>,
pub constraints: VisualizabilityConstraints,
pub queried: SortedComponentSet,
}
impl VisualizerQueryInfo {
pub fn buffer_and_format<Buffer: re_sdk_types::Component, Format: re_sdk_types::Component>(
buffer_descriptor: &ComponentDescriptor,
format_descriptor: &ComponentDescriptor,
all_queried_components: &[ComponentDescriptor],
) -> Self {
let query_info = Self {
relevant_archetype: format_descriptor.archetype,
constraints: BufferAndFormatConstraint::new::<Buffer, Format>(
buffer_descriptor,
format_descriptor,
)
.into(),
queried: all_queried_components.iter().cloned().collect(),
};
re_log::debug_assert!(
query_info
.queried
.iter()
.any(|desc| desc == buffer_descriptor),
"The buffer component must be part of the queried components."
);
re_log::debug_assert!(
query_info
.queried
.iter()
.any(|desc| desc == format_descriptor),
"The format component must be part of the queried components."
);
query_info
}
pub fn single_required_component<C: re_sdk_types::Component>(
target_component_descriptor: &ComponentDescriptor,
all_queried_components: &[ComponentDescriptor],
) -> Self {
let query_info = Self {
relevant_archetype: target_component_descriptor.archetype,
constraints: SingleRequiredComponentConstraint::new::<C>(target_component_descriptor)
.into(),
queried: all_queried_components.iter().cloned().collect(),
};
re_log::debug_assert!(
query_info
.queried
.iter()
.any(|desc| desc == target_component_descriptor),
"The required component must be part of the queried components."
);
query_info
}
pub fn empty() -> Self {
Self {
relevant_archetype: Default::default(),
constraints: VisualizabilityConstraints::None,
queried: SortedComponentSet::default(),
}
}
pub fn queried_components(&self) -> impl Iterator<Item = ComponentIdentifier> {
self.queried.iter().map(|desc| desc.component)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum VisualizerReportSeverity {
Warning,
Error,
OverallVisualizerError,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct VisualizerReportContext {
pub component: Option<ComponentIdentifier>,
pub extra: Option<String>,
}
impl re_byte_size::SizeBytes for VisualizerReportContext {
fn heap_size_bytes(&self) -> u64 {
self.extra.heap_size_bytes()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VisualizerInstructionReport {
pub severity: VisualizerReportSeverity,
pub context: VisualizerReportContext,
pub summary: String,
pub details: Option<String>,
}
impl re_byte_size::SizeBytes for VisualizerInstructionReport {
fn heap_size_bytes(&self) -> u64 {
self.summary.heap_size_bytes()
+ self.details.heap_size_bytes()
+ self.context.heap_size_bytes()
}
}
#[derive(Default)]
pub struct VisualizerExecutionOutput {
pub draw_data: Vec<re_renderer::QueueableDrawData>,
pub reports_per_instruction:
Mutex<BTreeMap<VisualizerInstructionId, Vec1<VisualizerInstructionReport>>>,
missing_chunk_reporter: MissingChunkReporter,
}
impl VisualizerExecutionOutput {
pub fn set_missing_chunks(&self) {
self.missing_chunk_reporter.report_missing_chunk();
}
pub fn any_missing_chunks(&self) -> bool {
self.missing_chunk_reporter.any_missing()
}
pub fn missing_chunk_reporter(&self) -> &MissingChunkReporter {
&self.missing_chunk_reporter
}
pub fn report_unspecified_source(
&self,
instruction_id: VisualizerInstructionId,
severity: VisualizerReportSeverity,
summary: impl Into<String>,
) {
self.report(
instruction_id,
VisualizerInstructionReport {
severity,
summary: summary.into(),
details: None,
context: VisualizerReportContext::default(),
},
);
}
pub fn report(
&self,
instruction_id: VisualizerInstructionId,
report: VisualizerInstructionReport,
) {
self.reports_per_instruction
.lock()
.entry(instruction_id)
.and_modify(|v| v.push(report.clone()))
.or_insert_with(|| vec1::vec1![report]);
}
pub fn with_draw_data(
mut self,
draw_data: impl IntoIterator<Item = re_renderer::QueueableDrawData>,
) -> Self {
self.draw_data.extend(draw_data);
self
}
}
pub trait VisualizerSystem: Send + Sync + std::any::Any {
fn visualizer_query_info(&self, app_options: &crate::AppOptions) -> VisualizerQueryInfo;
fn execute(
&mut self,
ctx: &ViewContext<'_>,
query: &ViewQuery<'_>,
context_systems: &ViewContextCollection,
) -> Result<VisualizerExecutionOutput, ViewSystemExecutionError>;
fn data(&self) -> Option<&dyn std::any::Any> {
None
}
}
pub struct VisualizerCollection {
pub systems: BTreeMap<ViewSystemIdentifier, Box<dyn VisualizerSystem>>,
}
impl VisualizerCollection {
#[inline]
pub fn get<T: VisualizerSystem + IdentifiedViewSystem + 'static>(
&self,
) -> Result<&T, ViewSystemExecutionError> {
self.systems
.get(&T::identifier())
.and_then(|s| (s.as_ref() as &dyn std::any::Any).downcast_ref())
.ok_or_else(|| {
ViewSystemExecutionError::VisualizerSystemNotFound(T::identifier().as_str())
})
}
#[inline]
pub fn get_by_type_identifier(
&self,
name: ViewSystemIdentifier,
) -> Result<&dyn VisualizerSystem, ViewSystemExecutionError> {
self.systems
.get(&name)
.map(|s| s.as_ref())
.ok_or_else(|| ViewSystemExecutionError::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()))
}
pub fn iter_visualizer_data<SpecificData: 'static>(
&self,
) -> impl Iterator<Item = &'_ SpecificData> {
self.iter()
.filter_map(|visualizer| visualizer.data()?.downcast_ref::<SpecificData>())
}
pub fn contains_visualizer_type(&self, name: ViewSystemIdentifier) -> bool {
self.systems.contains_key(&name)
}
}