use std::collections::BTreeMap;
use parking_lot::Mutex;
use re_chunk_store::MissingChunkReporter;
use vec1::Vec1;
use re_chunk::{ArchetypeName, ComponentType};
use re_sdk_types::blueprint::components::VisualizerInstructionId;
use re_sdk_types::{Archetype, ComponentDescriptor, ComponentIdentifier, ComponentSet};
use crate::{
IdentifiedViewSystem, ViewContext, ViewContextCollection, ViewQuery, ViewSystemExecutionError,
ViewSystemIdentifier,
};
#[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 type DatatypeSet = std::collections::BTreeSet<arrow::datatypes::DataType>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AnyPhysicalDatatypeRequirement {
pub target_component: ComponentIdentifier,
pub semantic_type: ComponentType,
pub physical_types: DatatypeSet,
pub allow_static_data: bool,
}
impl From<AnyPhysicalDatatypeRequirement> for RequiredComponents {
fn from(req: AnyPhysicalDatatypeRequirement) -> Self {
Self::AnyPhysicalDatatype(req)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum RequiredComponents {
#[default]
None,
AllComponents(ComponentSet),
AnyComponent(ComponentSet),
AnyPhysicalDatatype(AnyPhysicalDatatypeRequirement),
}
pub struct VisualizerQueryInfo {
pub relevant_archetype: Option<ArchetypeName>,
pub required: RequiredComponents,
pub queried: SortedComponentSet, }
impl VisualizerQueryInfo {
pub fn from_archetype<A: Archetype>() -> Self {
Self {
relevant_archetype: A::name().into(),
required: RequiredComponents::AllComponents(
A::required_components()
.iter()
.map(|c| c.component)
.collect(),
),
queried: A::all_components().iter().cloned().collect(),
}
}
pub fn empty() -> Self {
Self {
relevant_archetype: Default::default(),
required: RequiredComponents::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()
}
}
impl VisualizerInstructionReport {
pub fn error(summary: impl Into<String>) -> Self {
Self {
severity: VisualizerReportSeverity::Error,
summary: summary.into(),
details: None,
context: VisualizerReportContext::default(),
}
}
pub fn warning(summary: impl Into<String>) -> Self {
Self {
severity: VisualizerReportSeverity::Warning,
summary: summary.into(),
details: None,
context: VisualizerReportContext::default(),
}
}
}
#[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_error_for(
&self,
instruction_id: VisualizerInstructionId,
error: impl Into<String>,
) {
let report = VisualizerInstructionReport::error(error);
self.reports_per_instruction
.lock()
.entry(instruction_id)
.and_modify(|v| v.push(report.clone()))
.or_insert_with(|| vec1::vec1![report]);
}
pub fn report_warning_for(
&self,
instruction_id: VisualizerInstructionId,
warning: impl Into<String>,
) {
let report = VisualizerInstructionReport::warning(warning);
self.reports_per_instruction
.lock()
.entry(instruction_id)
.and_modify(|v| v.push(report.clone()))
.or_insert_with(|| vec1::vec1![report]);
}
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>())
}
}