diff --git a/crates/re_data_ui/src/annotation_context.rs b/crates/re_data_ui/src/annotation_context.rs index 843e293cba04..9e8a3c7e3d38 100644 --- a/crates/re_data_ui/src/annotation_context.rs +++ b/crates/re_data_ui/src/annotation_context.rs @@ -17,7 +17,7 @@ impl crate::EntityDataUi for re_types::components::ClassId { verbosity: re_viewer_context::UiVerbosity, entity_path: &re_log_types::EntityPath, query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let annotations = crate::annotations(ctx, query, entity_path); let class = annotations @@ -63,7 +63,7 @@ impl crate::EntityDataUi for re_types::components::KeypointId { _verbosity: re_viewer_context::UiVerbosity, entity_path: &re_log_types::EntityPath, query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { if let Some(info) = annotation_info(ctx, entity_path, query, self.0) { ui.horizontal(|ui| { @@ -102,7 +102,7 @@ impl DataUi for AnnotationContext { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { match verbosity { UiVerbosity::Small | UiVerbosity::Reduced => { diff --git a/crates/re_data_ui/src/app_id.rs b/crates/re_data_ui/src/app_id.rs index 50c55d0336f6..31ea2ca0f470 100644 --- a/crates/re_data_ui/src/app_id.rs +++ b/crates/re_data_ui/src/app_id.rs @@ -13,7 +13,7 @@ impl crate::DataUi for ApplicationId { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &EntityDb, ) { egui::Grid::new("application_id") .num_columns(2) diff --git a/crates/re_data_ui/src/blueprint_data.rs b/crates/re_data_ui/src/blueprint_data.rs index 344033d5abbf..5cae1a5ec929 100644 --- a/crates/re_data_ui/src/blueprint_data.rs +++ b/crates/re_data_ui/src/blueprint_data.rs @@ -10,12 +10,12 @@ impl DataUi for BlueprintId { ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { entity_path_button_to( ctx, query, - store, + db, ui, None, &self.as_entity_path(), diff --git a/crates/re_data_ui/src/component.rs b/crates/re_data_ui/src/component.rs index 95976dbf4043..d7973d302eeb 100644 --- a/crates/re_data_ui/src/component.rs +++ b/crates/re_data_ui/src/component.rs @@ -1,7 +1,10 @@ +use std::sync::Arc; + use egui::NumExt; -use re_entity_db::{EntityPath, InstancePath}; -use re_query::ComponentWithInstances; +use re_entity_db::{ + external::re_query_cache2::CachedLatestAtComponentResults, EntityPath, InstancePath, +}; use re_types::ComponentName; use re_ui::SyntaxHighlighting as _; use re_viewer_context::{UiVerbosity, ViewerContext}; @@ -9,38 +12,33 @@ use re_viewer_context::{UiVerbosity, ViewerContext}; use super::{table_for_verbosity, DataUi}; use crate::item_ui; -// We do NOT implement `DataUi` for just `ComponentWithInstances` -// because we also want the context of what entity it is part of! - /// All the values of a specific [`re_log_types::ComponentPath`]. -pub struct EntityComponentWithInstances { +pub struct EntityLatestAtResults { pub entity_path: EntityPath, - pub component_data: ComponentWithInstances, -} - -impl EntityComponentWithInstances { - pub fn component_name(&self) -> ComponentName { - self.component_data.name() - } - - pub fn num_instances(&self) -> usize { - self.component_data.len() - } + pub component_name: ComponentName, + pub results: Arc, } -impl DataUi for EntityComponentWithInstances { +impl DataUi for EntityLatestAtResults { fn data_ui( &self, ctx: &ViewerContext<'_>, ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { - re_tracing::profile_function!(self.component_name().full_name()); + re_tracing::profile_function!(self.component_name); - let instance_keys = self.component_data.instance_keys(); - let num_instances = self.num_instances(); + // TODO(#5607): what should happen if the promise is still pending? + let Some(num_instances) = self + .results + .raw(db.resolver(), self.component_name) + .map(|data| data.len()) + else { + ui.weak(""); + return; + }; let one_line = match verbosity { UiVerbosity::Small => true, @@ -71,7 +69,7 @@ impl DataUi for EntityComponentWithInstances { // ├───┼───┼───┼───┤ │ // │ │ x │…+2│…+3│ │ // └───┴───┴───┴───┘ ┘ - let displayed_row = if num_instances <= max_row { + let num_displayed_rows = if num_instances <= max_row { num_instances } else { // this accounts for the "…x more" using a row and handles `num_instances == 0` @@ -81,20 +79,16 @@ impl DataUi for EntityComponentWithInstances { if num_instances == 0 { ui.weak("(empty)"); } else if num_instances == 1 { - if let Some(instance_key) = instance_keys.first() { - ctx.component_ui_registry.ui( - ctx, - ui, - verbosity, - query, - store, - &self.entity_path, - &self.component_data, - instance_key, - ); - } else { - ui.label(ctx.re_ui.error_text("Error: missing instance key")); - } + ctx.component_ui_registry.ui( + ctx, + ui, + verbosity, + query, + db, + &self.entity_path, + &self.results, + &re_types::components::InstanceKey(0), + ); } else if one_line { ui.label(format!("{} values", re_format::format_uint(num_instances))); } else { @@ -106,49 +100,49 @@ impl DataUi for EntityComponentWithInstances { .header(re_ui::ReUi::table_header_height(), |mut header| { re_ui::ReUi::setup_table_header(&mut header); header.col(|ui| { - ui.label("Index"); + ui.label("Instance"); }); header.col(|ui| { - ui.label(self.component_name().short_name()); + ui.label(self.component_name.short_name()); }); }) .body(|mut body| { re_ui::ReUi::setup_table_body(&mut body); let row_height = re_ui::ReUi::table_line_height(); - body.rows(row_height, displayed_row, |mut row| { - if let Some(instance_key) = instance_keys.get(row.index()) { - row.col(|ui| { - let instance_path = - InstancePath::instance(self.entity_path.clone(), *instance_key); - item_ui::instance_path_button_to( - ctx, - query, - store, - ui, - None, - &instance_path, - instance_key.syntax_highlighted(ui.style()), - ); - }); - row.col(|ui| { - ctx.component_ui_registry.ui( - ctx, - ui, - UiVerbosity::Small, - query, - store, - &self.entity_path, - &self.component_data, - instance_key, - ); - }); - } + body.rows(row_height, num_displayed_rows, |mut row| { + let instance_key = re_types::components::InstanceKey(row.index() as _); + row.col(|ui| { + let instance_path = + InstancePath::instance(self.entity_path.clone(), instance_key); + item_ui::instance_path_button_to( + ctx, + query, + db, + ui, + None, + &instance_path, + instance_key.syntax_highlighted(ui.style()), + ); + }); + row.col(|ui| { + ctx.component_ui_registry.ui( + ctx, + ui, + UiVerbosity::Small, + query, + db, + &self.entity_path, + &self.results, + &instance_key, + ); + }); }); }); - if num_instances > displayed_row { + + if num_instances > num_displayed_rows { ui.label(format!( "…and {} more.", - re_format::format_uint(num_instances - displayed_row) + re_format::format_uint(num_instances - num_displayed_rows) )); } } diff --git a/crates/re_data_ui/src/component_path.rs b/crates/re_data_ui/src/component_path.rs index 49496d789fe0..35af64c88430 100644 --- a/crates/re_data_ui/src/component_path.rs +++ b/crates/re_data_ui/src/component_path.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use re_log_types::ComponentPath; use re_viewer_context::{UiVerbosity, ViewerContext}; @@ -10,7 +12,7 @@ impl DataUi for ComponentPath { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let Self { entity_path, @@ -21,27 +23,31 @@ impl DataUi for ComponentPath { ui.label(format!( "Indicator component for the {archetype_name} archetype" )); - } else if let Some((_, _, component_data)) = - re_query::get_component_with_instances(store, query, entity_path, *component_name) - { - super::component::EntityComponentWithInstances { - entity_path: self.entity_path.clone(), - component_data, - } - .data_ui(ctx, ui, verbosity, query, store); - } else if let Some(entity_tree) = ctx.recording().tree().subtree(entity_path) { - if entity_tree.entity.components.contains_key(component_name) { - ui.label(""); + } else { + let results = + db.query_caches2() + .latest_at(db.store(), query, entity_path, [*component_name]); + if let Some(results) = results.components.get(component_name) { + crate::EntityLatestAtResults { + entity_path: entity_path.clone(), + component_name: *component_name, + results: Arc::clone(results), + } + .data_ui(ctx, ui, verbosity, query, db); + } else if let Some(entity_tree) = ctx.recording().tree().subtree(entity_path) { + if entity_tree.entity.components.contains_key(component_name) { + ui.label(""); + } else { + ui.label(format!( + "Entity {entity_path:?} has no component {component_name:?}" + )); + } } else { - ui.label(format!( - "Entity {entity_path:?} has no component {component_name:?}" - )); + ui.label( + ctx.re_ui + .error_text(format!("Unknown component path: {self}")), + ); } - } else { - ui.label( - ctx.re_ui - .error_text(format!("Unknown component path: {self}")), - ); } } } diff --git a/crates/re_data_ui/src/component_ui_registry.rs b/crates/re_data_ui/src/component_ui_registry.rs index 28ed1571b684..e576b76c0b66 100644 --- a/crates/re_data_ui/src/component_ui_registry.rs +++ b/crates/re_data_ui/src/component_ui_registry.rs @@ -1,6 +1,6 @@ -use re_data_store::{DataStore, LatestAtQuery}; +use re_data_store::LatestAtQuery; +use re_entity_db::{external::re_query_cache2::CachedLatestAtComponentResults, EntityDb}; use re_log_types::{external::arrow2, EntityPath}; -use re_query::ComponentWithInstances; use re_types::external::arrow2::array::Utf8Array; use re_viewer_context::{ComponentUiRegistry, UiVerbosity, ViewerContext}; @@ -39,18 +39,13 @@ pub fn add_to_registry(registry: &mut Com registry.add( C::name(), Box::new( - |ctx, ui, verbosity, query, store, entity_path, component, instance| match component - .lookup::(instance) - { - Ok(component) => { - component.entity_data_ui(ctx, ui, verbosity, entity_path, query, store); - } - Err(re_query::QueryError::ComponentNotFound(_)) => { + |ctx, ui, verbosity, query, db, entity_path, component, instance| { + // TODO(#5607): what should happen if the promise is still pending? + if let Some(component) = component.instance::(db.resolver(), instance.0 as _) { + component.entity_data_ui(ctx, ui, verbosity, entity_path, query, db); + } else { ui.weak("(not found)"); } - Err(err) => { - re_log::warn_once!("Expected component {}, {}", C::name(), err); - } }, ), ); @@ -62,13 +57,20 @@ fn fallback_component_ui( ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &LatestAtQuery, - _store: &DataStore, + db: &EntityDb, _entity_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { + // TODO(#5607): what should happen if the promise is still pending? + let value = component + .component_name(db.resolver()) + .and_then(|component_name| { + component.instance_raw(db.resolver(), component_name, instance_key.0 as _) + }); + // No special ui implementation - use a generic one: - if let Some(value) = component.lookup_arrow(instance_key) { + if let Some(value) = value { arrow_ui(ui, verbosity, &*value); } else { ui.weak("(null)"); diff --git a/crates/re_data_ui/src/data.rs b/crates/re_data_ui/src/data.rs index 234a141c2b4f..ec481568d639 100644 --- a/crates/re_data_ui/src/data.rs +++ b/crates/re_data_ui/src/data.rs @@ -16,7 +16,7 @@ impl DataUi for [u8; 4] { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let [r, g, b, a] = self; let color = egui::Color32::from_rgba_unmultiplied(*r, *g, *b, *a); @@ -37,7 +37,7 @@ impl DataUi for Color { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let [r, g, b, a] = self.to_array(); let color = egui::Color32::from_rgba_unmultiplied(r, g, b, a); @@ -58,7 +58,7 @@ impl DataUi for ViewCoordinates { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { match verbosity { UiVerbosity::Small => { @@ -79,7 +79,7 @@ impl DataUi for re_types::datatypes::Mat3x3 { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { egui::Grid::new("mat3").num_columns(3).show(ui, |ui| { ui.monospace(self[0].to_string()); @@ -107,7 +107,7 @@ impl DataUi for re_types::datatypes::Vec2D { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { ui.label(self.to_string()); } @@ -120,7 +120,7 @@ impl DataUi for re_types::datatypes::Vec3D { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { ui.label(self.to_string()); } @@ -133,7 +133,7 @@ impl DataUi for LineStrip2D { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { match verbosity { UiVerbosity::Small | UiVerbosity::Reduced => { @@ -180,7 +180,7 @@ impl DataUi for LineStrip3D { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { match verbosity { UiVerbosity::Small | UiVerbosity::Reduced => { @@ -233,7 +233,7 @@ impl DataUi for MeshProperties { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let show_optional_indices = |ui: &mut egui::Ui| { if let Some(indices) = self.indices.as_ref() { diff --git a/crates/re_data_ui/src/data_source.rs b/crates/re_data_ui/src/data_source.rs index b1e90ccf1977..bdf3ed05db01 100644 --- a/crates/re_data_ui/src/data_source.rs +++ b/crates/re_data_ui/src/data_source.rs @@ -10,7 +10,7 @@ impl crate::DataUi for re_smart_channel::SmartChannelSource { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { ui.label(self.to_string()); diff --git a/crates/re_data_ui/src/editors.rs b/crates/re_data_ui/src/editors.rs index f00b01b17bcc..425cbc28eeca 100644 --- a/crates/re_data_ui/src/editors.rs +++ b/crates/re_data_ui/src/editors.rs @@ -1,9 +1,9 @@ // TODO(jleibs): Turn this into a trait use egui::NumExt as _; -use re_data_store::{DataStore, LatestAtQuery}; +use re_data_store::LatestAtQuery; +use re_entity_db::{external::re_query_cache2::CachedLatestAtComponentResults, EntityDb}; use re_log_types::EntityPath; -use re_query::ComponentWithInstances; use re_types::{ components::{ Color, MarkerShape, MarkerSize, Name, Radius, ScalarScattering, StrokeWidth, Text, @@ -20,16 +20,16 @@ fn edit_color_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_color = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_color(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_color(ctx, query, db, entity_path)); let current_color = current_color.into(); let mut edit_color = current_color; @@ -49,7 +49,7 @@ fn edit_color_ui( fn default_color( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, _entity_path: &EntityPath, ) -> Color { Color::from_rgb(255, 255, 255) @@ -63,16 +63,16 @@ fn edit_text_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_text = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_text(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_text(ctx, query, db, entity_path)); let current_text = current_text.to_string(); let mut edit_text = current_text.clone(); @@ -90,7 +90,7 @@ fn edit_text_ui( fn default_text( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, entity_path: &EntityPath, ) -> Text { Text::from(entity_path.to_string()) @@ -103,16 +103,16 @@ fn edit_name_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_text = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_name(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_name(ctx, query, db, entity_path)); let current_text = current_text.to_string(); let mut edit_text = current_text.clone(); @@ -130,7 +130,7 @@ fn edit_name_ui( fn default_name( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, entity_path: &EntityPath, ) -> Name { Name::from(entity_path.to_string()) @@ -144,16 +144,16 @@ fn edit_scatter_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_scatter = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_scatter(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_scatter(ctx, query, db, entity_path)); let current_scatter = current_scatter.0; let mut edit_scatter = current_scatter; @@ -179,7 +179,7 @@ fn edit_scatter_ui( fn default_scatter( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, _entity_path: &EntityPath, ) -> ScalarScattering { ScalarScattering::from(false) @@ -193,16 +193,16 @@ fn edit_radius_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_radius = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_radius(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_radius(ctx, query, db, entity_path)); let current_radius = current_radius.0; let mut edit_radius = current_radius; @@ -226,7 +226,7 @@ fn edit_radius_ui( fn default_radius( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, _entity_path: &EntityPath, ) -> Radius { Radius::from(1.0) @@ -240,16 +240,16 @@ fn edit_marker_shape_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_marker = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_marker_shape(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_marker_shape(ctx, query, db, entity_path)); let mut edit_marker = current_marker; @@ -290,7 +290,7 @@ fn edit_marker_shape_ui( fn default_marker_shape( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, _entity_path: &EntityPath, ) -> MarkerShape { MarkerShape::default() @@ -326,16 +326,16 @@ fn edit_stroke_width_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_stroke_width = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_stroke_width(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_stroke_width(ctx, query, db, entity_path)); let current_stroke_width = current_stroke_width.0; let mut edit_stroke_width = current_stroke_width; @@ -359,7 +359,7 @@ fn edit_stroke_width_ui( fn default_stroke_width( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, _entity_path: &EntityPath, ) -> StrokeWidth { StrokeWidth::from(1.0) @@ -373,16 +373,16 @@ fn edit_marker_size_ui( ui: &mut egui::Ui, _verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &re_types::components::InstanceKey, ) { let current_marker_size = component - .lookup::(instance_key) - .ok() - .unwrap_or_else(|| default_marker_size(ctx, query, store, entity_path)); + // TODO(#5607): what should happen if the promise is still pending? + .instance::(db.resolver(), instance_key.0 as _) + .unwrap_or_else(|| default_marker_size(ctx, query, db, entity_path)); let current_marker_size = current_marker_size.0; let mut edit_marker_size = current_marker_size; @@ -406,7 +406,7 @@ fn edit_marker_size_ui( fn default_marker_size( _ctx: &ViewerContext<'_>, _query: &LatestAtQuery, - _store: &DataStore, + _db: &EntityDb, _entity_path: &EntityPath, ) -> MarkerSize { MarkerSize::from(1.0) @@ -416,16 +416,16 @@ fn default_marker_size( fn register_editor<'a, C: Component + Loggable + 'static>( registry: &mut re_viewer_context::ComponentUiRegistry, - default: fn(&ViewerContext<'_>, &LatestAtQuery, &DataStore, &EntityPath) -> C, + default: fn(&ViewerContext<'_>, &LatestAtQuery, &EntityDb, &EntityPath) -> C, edit: fn( &ViewerContext<'_>, &mut egui::Ui, UiVerbosity, &LatestAtQuery, - &DataStore, + &EntityDb, &EntityPath, &EntityPath, - &ComponentWithInstances, + &CachedLatestAtComponentResults, &re_types::components::InstanceKey, ), ) where @@ -433,8 +433,8 @@ fn register_editor<'a, C: Component + Loggable + 'static>( { registry.add_editor( C::name(), - Box::new(move |ctx, query, store, entity_path| { - let c = default(ctx, query, store, entity_path); + Box::new(move |ctx, query, db, entity_path| { + let c = default(ctx, query, db, entity_path); [c].into() }), Box::new(edit), diff --git a/crates/re_data_ui/src/entity_db.rs b/crates/re_data_ui/src/entity_db.rs index 4faa5b61b30d..57a0007fa6f4 100644 --- a/crates/re_data_ui/src/entity_db.rs +++ b/crates/re_data_ui/src/entity_db.rs @@ -12,7 +12,7 @@ impl crate::DataUi for EntityDb { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let re_ui = &ctx.re_ui; diff --git a/crates/re_data_ui/src/entity_path.rs b/crates/re_data_ui/src/entity_path.rs index c4dd7d1df55c..6348b21ddbac 100644 --- a/crates/re_data_ui/src/entity_path.rs +++ b/crates/re_data_ui/src/entity_path.rs @@ -10,8 +10,8 @@ impl DataUi for re_entity_db::EntityPath { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { - InstancePath::entity_splat(self.clone()).data_ui(ctx, ui, verbosity, query, store); + InstancePath::entity_splat(self.clone()).data_ui(ctx, ui, verbosity, query, db); } } diff --git a/crates/re_data_ui/src/image.rs b/crates/re_data_ui/src/image.rs index 0548957b5993..491320baeb82 100644 --- a/crates/re_data_ui/src/image.rs +++ b/crates/re_data_ui/src/image.rs @@ -34,7 +34,7 @@ impl EntityDataUi for re_types::components::TensorData { verbosity: UiVerbosity, entity_path: &re_log_types::EntityPath, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { re_tracing::profile_function!(); @@ -53,7 +53,7 @@ impl EntityDataUi for re_types::components::TensorData { tensor_ui( ctx, query, - store, + db, ui, verbosity, entity_path, @@ -74,7 +74,7 @@ impl EntityDataUi for re_types::components::TensorData { pub fn tensor_ui( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, verbosity: UiVerbosity, entity_path: &re_entity_db::EntityPath, @@ -90,7 +90,7 @@ pub fn tensor_ui( .entry(|c: &mut TensorStatsCache| c.entry(tensor_data_row_id, tensor)); let debug_name = entity_path.to_string(); - let meaning = image_meaning_for_entity(entity_path, query, store); + let meaning = image_meaning_for_entity(entity_path, query, db.store()); let meter = if meaning == TensorDataMeaning::Depth { // TODO(#5607): what should happen if the promise is still pending? diff --git a/crates/re_data_ui/src/instance_path.rs b/crates/re_data_ui/src/instance_path.rs index 192c4206d470..11152fedd6f0 100644 --- a/crates/re_data_ui/src/instance_path.rs +++ b/crates/re_data_ui/src/instance_path.rs @@ -1,6 +1,7 @@ +use std::sync::Arc; + use re_entity_db::InstancePath; use re_log_types::ComponentPath; -use re_query::get_component_with_instances; use re_viewer_context::{UiVerbosity, ViewerContext}; use super::DataUi; @@ -13,14 +14,17 @@ impl DataUi for InstancePath { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let Self { entity_path, instance_key, } = self; - let Some(components) = store.all_components(&query.timeline(), entity_path) else { + let Some(components) = ctx + .recording_store() + .all_components(&query.timeline(), entity_path) + else { if ctx.recording().is_known_entity(entity_path) { // This is fine - e.g. we're looking at `/world` and the user has only logged to `/world/car`. ui.label(format!( @@ -71,9 +75,13 @@ impl DataUi for InstancePath { .num_columns(2) .show(ui, |ui| { for component_name in normal_components { - let Some((_, _, component_data)) = - get_component_with_instances(store, query, entity_path, component_name) - else { + let results = db.query_caches2().latest_at( + db.store(), + query, + entity_path, + [component_name], + ); + let Some(results) = results.components.get(&component_name) else { continue; // no need to show components that are unset at this point in time }; @@ -84,20 +92,21 @@ impl DataUi for InstancePath { ); if instance_key.is_splat() { - super::component::EntityComponentWithInstances { + crate::EntityLatestAtResults { entity_path: entity_path.clone(), - component_data, + component_name, + results: Arc::clone(results), } - .data_ui(ctx, ui, UiVerbosity::Small, query, store); + .data_ui(ctx, ui, UiVerbosity::Small, query, db); } else { ctx.component_ui_registry.ui( ctx, ui, UiVerbosity::Small, query, - store, + db, entity_path, - &component_data, + results, instance_key, ); } diff --git a/crates/re_data_ui/src/item_ui.rs b/crates/re_data_ui/src/item_ui.rs index 3d4c60dc58c2..001c3320297d 100644 --- a/crates/re_data_ui/src/item_ui.rs +++ b/crates/re_data_ui/src/item_ui.rs @@ -36,7 +36,7 @@ use super::DataUi; pub fn entity_path_button( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, space_view_id: Option, entity_path: &EntityPath, @@ -44,7 +44,7 @@ pub fn entity_path_button( instance_path_button_to( ctx, query, - store, + db, ui, space_view_id, &InstancePath::entity_splat(entity_path.clone()), @@ -56,7 +56,7 @@ pub fn entity_path_button( pub fn entity_path_parts_buttons( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, space_view_id: Option, entity_path: &EntityPath, @@ -68,7 +68,7 @@ pub fn entity_path_parts_buttons( // Show one single icon up-front instead: let instance_path = InstancePath::entity_splat(entity_path.clone()); - ui.add(instance_path_icon(&query.timeline(), store, &instance_path).as_image()); + ui.add(instance_path_icon(&query.timeline(), db, &instance_path).as_image()); let mut accumulated = Vec::new(); for part in entity_path.iter() { @@ -78,7 +78,7 @@ pub fn entity_path_parts_buttons( instance_path_button_to_ex( ctx, query, - store, + db, ui, space_view_id, &InstancePath::entity_splat(accumulated.clone().into()), @@ -94,7 +94,7 @@ pub fn entity_path_parts_buttons( pub fn entity_path_button_to( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, space_view_id: Option, entity_path: &EntityPath, @@ -103,7 +103,7 @@ pub fn entity_path_button_to( instance_path_button_to( ctx, query, - store, + db, ui, space_view_id, &InstancePath::entity_splat(entity_path.clone()), @@ -115,7 +115,7 @@ pub fn entity_path_button_to( pub fn instance_path_button( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, space_view_id: Option, instance_path: &InstancePath, @@ -123,7 +123,7 @@ pub fn instance_path_button( instance_path_button_to( ctx, query, - store, + db, ui, space_view_id, instance_path, @@ -137,12 +137,13 @@ pub fn instance_path_button( /// _on the current timeline_. pub fn instance_path_icon( timeline: &re_data_store::Timeline, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, instance_path: &InstancePath, ) -> &'static icons::Icon { if instance_path.is_splat() { // It is an entity path - if store + if db + .store() .all_components(timeline, &instance_path.entity_path) .is_some() { @@ -186,29 +187,20 @@ pub fn guess_instance_path_icon( instance_path: &InstancePath, ) -> &'static re_ui::icons::Icon { let (query, db) = guess_query_and_db_for_selected_entity(ctx, &instance_path.entity_path); - instance_path_icon(&query.timeline(), db.store(), instance_path) + instance_path_icon(&query.timeline(), db, instance_path) } /// Show an instance id and make it selectable. pub fn instance_path_button_to( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, space_view_id: Option, instance_path: &InstancePath, text: impl Into, ) -> egui::Response { - instance_path_button_to_ex( - ctx, - query, - store, - ui, - space_view_id, - instance_path, - text, - true, - ) + instance_path_button_to_ex(ctx, query, db, ui, space_view_id, instance_path, text, true) } /// Show an instance id and make it selectable. @@ -216,7 +208,7 @@ pub fn instance_path_button_to( fn instance_path_button_to_ex( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, space_view_id: Option, instance_path: &InstancePath, @@ -232,7 +224,7 @@ fn instance_path_button_to_ex( let response = if with_icon { ctx.re_ui.selectable_label_with_icon( ui, - instance_path_icon(&query.timeline(), store, instance_path), + instance_path_icon(&query.timeline(), db, instance_path), text, ctx.selection().contains_item(&item), re_ui::LabelStyle::Normal, @@ -242,7 +234,7 @@ fn instance_path_button_to_ex( }; let response = response.on_hover_ui(|ui| { - instance_hover_card_ui(ui, ctx, query, store, instance_path); + instance_hover_card_ui(ui, ctx, query, db, instance_path); }); cursor_interact_with_selectable(ctx, response, item) @@ -252,7 +244,7 @@ fn instance_path_button_to_ex( pub fn instance_path_parts_buttons( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, space_view_id: Option, instance_path: &InstancePath, @@ -263,7 +255,7 @@ pub fn instance_path_parts_buttons( ui.spacing_mut().item_spacing.x = 2.0; // Show one single icon up-front instead: - ui.add(instance_path_icon(&query.timeline(), store, instance_path).as_image()); + ui.add(instance_path_icon(&query.timeline(), db, instance_path).as_image()); let mut accumulated = Vec::new(); for part in instance_path.entity_path.iter() { @@ -273,7 +265,7 @@ pub fn instance_path_parts_buttons( instance_path_button_to_ex( ctx, query, - store, + db, ui, space_view_id, &InstancePath::entity_splat(accumulated.clone().into()), @@ -287,7 +279,7 @@ pub fn instance_path_parts_buttons( instance_path_button_to_ex( ctx, query, - store, + db, ui, space_view_id, instance_path, @@ -413,7 +405,7 @@ pub fn component_path_button_to( pub fn data_blueprint_button_to( ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ui: &mut egui::Ui, text: impl Into, space_view_id: SpaceViewId, @@ -426,7 +418,7 @@ pub fn data_blueprint_button_to( let response = ui .selectable_label(ctx.selection().contains_item(&item), text) .on_hover_ui(|ui| { - entity_hover_card_ui(ui, ctx, query, store, entity_path); + entity_hover_card_ui(ui, ctx, query, db, entity_path); }); cursor_interact_with_selectable(ctx, response, item) } @@ -510,7 +502,7 @@ pub fn instance_hover_card_ui( ui: &mut egui::Ui, ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, instance_path: &InstancePath, ) { if !ctx.recording().is_known_entity(&instance_path.entity_path) { @@ -537,7 +529,7 @@ pub fn instance_hover_card_ui( // TODO(emilk): per-component stats } - instance_path.data_ui(ctx, ui, UiVerbosity::Reduced, query, store); + instance_path.data_ui(ctx, ui, UiVerbosity::Reduced, query, db); } /// Displays the "hover card" (i.e. big tooltip) for an entity. @@ -545,11 +537,11 @@ pub fn entity_hover_card_ui( ui: &mut egui::Ui, ctx: &ViewerContext<'_>, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, entity_path: &EntityPath, ) { let instance_path = InstancePath::entity_splat(entity_path.clone()); - instance_hover_card_ui(ui, ctx, query, store, &instance_path); + instance_hover_card_ui(ui, ctx, query, db, &instance_path); } pub fn app_id_button_ui( @@ -572,8 +564,8 @@ pub fn app_id_button_ui( ctx, ui, re_viewer_context::UiVerbosity::Reduced, - &ctx.current_query(), // unused - ctx.recording_store(), // unused + &ctx.current_query(), // unused + ctx.recording(), // unused ); }); @@ -601,7 +593,7 @@ pub fn data_source_button_ui( ui, re_viewer_context::UiVerbosity::Reduced, &ctx.current_query(), - ctx.recording_store(), // unused + ctx.recording(), // unused ); }); @@ -704,7 +696,7 @@ pub fn entity_db_button_ui( ui, re_viewer_context::UiVerbosity::Reduced, &ctx.current_query(), - entity_db.store(), + entity_db, ); }); diff --git a/crates/re_data_ui/src/lib.rs b/crates/re_data_ui/src/lib.rs index 24f54eb4fa20..ab92ba5fd344 100644 --- a/crates/re_data_ui/src/lib.rs +++ b/crates/re_data_ui/src/lib.rs @@ -35,7 +35,7 @@ pub use crate::image::{ show_zoomed_image_region, show_zoomed_image_region_area_outline, tensor_summary_ui_grid_contents, }; -pub use component::EntityComponentWithInstances; +pub use component::EntityLatestAtResults; pub use component_ui_registry::{add_to_registry, create_component_ui_registry}; pub use image_meaning::image_meaning_for_entity; @@ -71,7 +71,7 @@ pub trait DataUi { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ); } @@ -87,7 +87,7 @@ pub trait EntityDataUi { verbosity: UiVerbosity, entity_path: &EntityPath, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ); } @@ -102,12 +102,12 @@ where verbosity: UiVerbosity, entity: &EntityPath, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { // This ensures that UI state is maintained per entity. For example, the collapsed state for // `AnnotationContext` component is not saved by all instances of the component. ui.push_id(entity.hash(), |ui| { - self.data_ui(ctx, ui, verbosity, query, store); + self.data_ui(ctx, ui, verbosity, query, db); }); } } @@ -121,7 +121,7 @@ impl DataUi for TimePoint { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { ui.vertical(|ui| { egui::Grid::new("time_point").num_columns(2).show(ui, |ui| { @@ -143,7 +143,7 @@ impl DataUi for [DataCell] { ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let mut sorted = self.to_vec(); sorted.sort_by_key(|cb| cb.component_name()); diff --git a/crates/re_data_ui/src/log_msg.rs b/crates/re_data_ui/src/log_msg.rs index a6636b5983e3..86559d0d0e67 100644 --- a/crates/re_data_ui/src/log_msg.rs +++ b/crates/re_data_ui/src/log_msg.rs @@ -13,11 +13,11 @@ impl DataUi for LogMsg { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { match self { - LogMsg::SetStoreInfo(msg) => msg.data_ui(ctx, ui, verbosity, query, store), - LogMsg::ArrowMsg(_, msg) => msg.data_ui(ctx, ui, verbosity, query, store), + LogMsg::SetStoreInfo(msg) => msg.data_ui(ctx, ui, verbosity, query, db), + LogMsg::ArrowMsg(_, msg) => msg.data_ui(ctx, ui, verbosity, query, db), LogMsg::BlueprintActivationCommand(BlueprintActivationCommand { blueprint_id, make_active, @@ -38,7 +38,7 @@ impl DataUi for SetStoreInfo { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let SetStoreInfo { row_id: _, info } = self; let StoreInfo { @@ -96,7 +96,7 @@ impl DataUi for ArrowMsg { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let table = match DataTable::from_arrow_msg(self) { Ok(table) => table, @@ -115,15 +115,15 @@ impl DataUi for ArrowMsg { Ok(row) => { egui::Grid::new("fields").num_columns(2).show(ui, |ui| { ui.monospace("entity_path:"); - item_ui::entity_path_button(ctx, query, store, ui, None, row.entity_path()); + item_ui::entity_path_button(ctx, query, db, ui, None, row.entity_path()); ui.end_row(); ui.monospace("time_point:"); - row.timepoint().data_ui(ctx, ui, verbosity, query, store); + row.timepoint().data_ui(ctx, ui, verbosity, query, db); ui.end_row(); ui.monospace("components:"); - row.cells().data_ui(ctx, ui, verbosity, query, store); + row.cells().data_ui(ctx, ui, verbosity, query, db); ui.end_row(); }); } diff --git a/crates/re_data_ui/src/material.rs b/crates/re_data_ui/src/material.rs index d17aba5c17a9..1e39d0197b57 100644 --- a/crates/re_data_ui/src/material.rs +++ b/crates/re_data_ui/src/material.rs @@ -10,11 +10,11 @@ impl DataUi for Material { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let show_optional_albedo_factor = |ui: &mut egui::Ui| { if let Some(albedo_factor) = self.albedo_factor { - Color(albedo_factor).data_ui(ctx, ui, verbosity, query, store); + Color(albedo_factor).data_ui(ctx, ui, verbosity, query, db); } else { ui.weak("(empty)"); } diff --git a/crates/re_data_ui/src/pinhole.rs b/crates/re_data_ui/src/pinhole.rs index 7b8b48b06838..0237e5b25e04 100644 --- a/crates/re_data_ui/src/pinhole.rs +++ b/crates/re_data_ui/src/pinhole.rs @@ -10,7 +10,7 @@ impl DataUi for PinholeProjection { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { if verbosity == UiVerbosity::Small { // See if this is a trivial pinhole, and can be displayed as such: @@ -24,12 +24,12 @@ impl DataUi for PinholeProjection { }; ui.label(format!("Focal length: {fl}\nPrincipal point: {pp}")) - .on_hover_ui(|ui| self.data_ui(ctx, ui, UiVerbosity::Reduced, query, store)); + .on_hover_ui(|ui| self.data_ui(ctx, ui, UiVerbosity::Reduced, query, db)); return; } } - self.0.data_ui(ctx, ui, verbosity, query, store); + self.0.data_ui(ctx, ui, verbosity, query, db); } } @@ -40,7 +40,7 @@ impl DataUi for Resolution { ui: &mut egui::Ui, _verbosity: UiVerbosity, _query: &re_data_store::LatestAtQuery, - _store: &re_data_store::DataStore, + _db: &re_entity_db::EntityDb, ) { let [x, y] = self.0 .0; ui.monospace(format!("{x}x{y}")); diff --git a/crates/re_data_ui/src/rotation3d.rs b/crates/re_data_ui/src/rotation3d.rs index 5a30b308d885..5b17d32cacaf 100644 --- a/crates/re_data_ui/src/rotation3d.rs +++ b/crates/re_data_ui/src/rotation3d.rs @@ -13,9 +13,9 @@ impl DataUi for components::Rotation3D { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { - self.0.data_ui(ctx, ui, verbosity, query, store); + self.0.data_ui(ctx, ui, verbosity, query, db); } } @@ -26,7 +26,7 @@ impl DataUi for datatypes::Rotation3D { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { match self { datatypes::Rotation3D::Quaternion(q) => { @@ -36,7 +36,7 @@ impl DataUi for datatypes::Rotation3D { datatypes::Rotation3D::AxisAngle(RotationAxisAngle { axis, angle }) => { egui::Grid::new("axis_angle").num_columns(2).show(ui, |ui| { ui.label("axis"); - axis.data_ui(ctx, ui, verbosity, query, store); + axis.data_ui(ctx, ui, verbosity, query, db); ui.end_row(); ui.label("angle"); diff --git a/crates/re_data_ui/src/store_id.rs b/crates/re_data_ui/src/store_id.rs index 3aef5003ed2a..ca173439d8e2 100644 --- a/crates/re_data_ui/src/store_id.rs +++ b/crates/re_data_ui/src/store_id.rs @@ -5,10 +5,10 @@ impl crate::DataUi for re_log_types::StoreId { ui: &mut egui::Ui, verbosity: re_viewer_context::UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { if let Some(entity_db) = ctx.store_context.bundle.get(self) { - entity_db.data_ui(ctx, ui, verbosity, query, store); + entity_db.data_ui(ctx, ui, verbosity, query, db); } else { ui.label(format!("{} ID {} (not found)", self.kind, self.id)); } diff --git a/crates/re_data_ui/src/transform3d.rs b/crates/re_data_ui/src/transform3d.rs index bb81f4b75266..7b334afc9be1 100644 --- a/crates/re_data_ui/src/transform3d.rs +++ b/crates/re_data_ui/src/transform3d.rs @@ -11,13 +11,13 @@ impl DataUi for re_types::components::Transform3D { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { match verbosity { UiVerbosity::Small => { // TODO(andreas): Preview some information instead of just a label with hover ui. ui.label("3D transform").on_hover_ui(|ui| { - self.data_ui(ctx, ui, UiVerbosity::LimitHeight, query, store); + self.data_ui(ctx, ui, UiVerbosity::LimitHeight, query, db); }); } @@ -36,7 +36,7 @@ impl DataUi for re_types::components::Transform3D { ui.label("3D transform"); ui.indent("transform_repr", |ui| { ui.label(dir_string); - self.0.data_ui(ctx, ui, verbosity, query, store); + self.0.data_ui(ctx, ui, verbosity, query, db); }); }); } @@ -52,9 +52,9 @@ impl DataUi for re_types::components::OutOfTreeTransform3D { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { - re_types::components::Transform3D(self.0).data_ui(ctx, ui, verbosity, query, store); + re_types::components::Transform3D(self.0).data_ui(ctx, ui, verbosity, query, db); } } @@ -66,21 +66,21 @@ impl DataUi for Transform3D { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { match verbosity { UiVerbosity::Small => { ui.label("3D transform").on_hover_ui(|ui| { - self.data_ui(ctx, ui, UiVerbosity::LimitHeight, query, store); + self.data_ui(ctx, ui, UiVerbosity::LimitHeight, query, db); }); } UiVerbosity::Full | UiVerbosity::LimitHeight | UiVerbosity::Reduced => match self { Transform3D::TranslationAndMat3x3(translation_matrix) => { - translation_matrix.data_ui(ctx, ui, verbosity, query, store); + translation_matrix.data_ui(ctx, ui, verbosity, query, db); } Transform3D::TranslationRotationScale(translation_rotation_scale) => { - translation_rotation_scale.data_ui(ctx, ui, verbosity, query, store); + translation_rotation_scale.data_ui(ctx, ui, verbosity, query, db); } }, } @@ -94,7 +94,7 @@ impl DataUi for TranslationRotationScale3D { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let TranslationRotationScale3D { translation, @@ -110,19 +110,19 @@ impl DataUi for TranslationRotationScale3D { // We still skip zero translations though since they are typically not logged explicitly. if let Some(translation) = translation { ui.label("translation"); - translation.data_ui(ctx, ui, verbosity, query, store); + translation.data_ui(ctx, ui, verbosity, query, db); ui.end_row(); } if let Some(rotation) = rotation { ui.label("rotation"); - rotation.data_ui(ctx, ui, verbosity, query, store); + rotation.data_ui(ctx, ui, verbosity, query, db); ui.end_row(); } if let Some(scale) = scale { ui.label("scale"); - scale.data_ui(ctx, ui, verbosity, query, store); + scale.data_ui(ctx, ui, verbosity, query, db); ui.end_row(); } }); @@ -136,14 +136,14 @@ impl DataUi for Scale3D { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { match self { Scale3D::Uniform(scale) => { ui.label(re_format::format_f32(*scale)); } Scale3D::ThreeD(v) => { - v.data_ui(ctx, ui, verbosity, query, store); + v.data_ui(ctx, ui, verbosity, query, db); } } } @@ -156,7 +156,7 @@ impl DataUi for TranslationAndMat3x3 { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let TranslationAndMat3x3 { translation, @@ -169,13 +169,13 @@ impl DataUi for TranslationAndMat3x3 { .show(ui, |ui| { if let Some(translation) = translation { ui.label("translation"); - translation.data_ui(ctx, ui, verbosity, query, store); + translation.data_ui(ctx, ui, verbosity, query, db); ui.end_row(); } if let Some(matrix) = mat3x3 { ui.label("matrix"); - matrix.data_ui(ctx, ui, verbosity, query, store); + matrix.data_ui(ctx, ui, verbosity, query, db); ui.end_row(); } }); diff --git a/crates/re_query2/src/promise.rs b/crates/re_query2/src/promise.rs index 65c44891b3af..a8f473c725a5 100644 --- a/crates/re_query2/src/promise.rs +++ b/crates/re_query2/src/promise.rs @@ -118,6 +118,15 @@ impl PromiseResult { } } + /// Returns the inner value if it's ready. + #[inline] + pub fn ok(self) -> Option { + match self { + PromiseResult::Ready(v) => Some(v), + _ => None, + } + } + /// Unwraps the resolved result if it's `Ready`, panics otherwise. #[inline] pub fn unwrap(self) -> T { diff --git a/crates/re_query_cache2/src/latest_at/helpers.rs b/crates/re_query_cache2/src/latest_at/helpers.rs index 559bc013336f..8ba0bb86d448 100644 --- a/crates/re_query_cache2/src/latest_at/helpers.rs +++ b/crates/re_query_cache2/src/latest_at/helpers.rs @@ -1,8 +1,227 @@ use re_data_store::{DataStore, LatestAtQuery}; use re_log_types::{EntityPath, RowId, TimeInt}; use re_types_core::Component; +use re_types_core::{external::arrow2::array::Array, ComponentName}; -use crate::{Caches, PromiseResolver, PromiseResult}; +use crate::{CachedLatestAtComponentResults, Caches, PromiseResolver, PromiseResult}; + +// --- + +impl CachedLatestAtComponentResults { + /// Returns the component data as a dense vector. + /// + /// Logs a warning and returns `None` if the component is missing or cannot be deserialized. + #[inline] + pub fn dense(&self, resolver: &PromiseResolver) -> Option<&[C]> { + let component_name = C::name(); + let level = re_log::Level::Warn; + match self.to_dense::(resolver).flatten() { + PromiseResult::Pending => { + re_log::debug_once!("Couldn't deserialize {component_name}: promise still pending",); + None + } + PromiseResult::Ready(data) => Some(data), + PromiseResult::Error(err) => { + re_log::log_once!( + level, + "Couldn't deserialize {component_name}: {}", + re_error::format_ref(&*err), + ); + None + } + } + } + + /// Returns the component data as an arrow array. + /// + /// Logs a warning and returns `None` if the component is missing or cannot be deserialized. + #[inline] + pub fn raw( + &self, + resolver: &PromiseResolver, + component_name: impl Into, + ) -> Option> { + let component_name = component_name.into(); + let level = re_log::Level::Warn; + match self.resolved(resolver) { + PromiseResult::Pending => { + re_log::debug_once!("Couldn't get {component_name}: promise still pending"); + None + } + PromiseResult::Ready(cell) => Some(cell.to_arrow()), + PromiseResult::Error(err) => { + re_log::log_once!( + level, + "Couldn't get {component_name}: {}", + re_error::format_ref(&*err), + ); + None + } + } + } + + /// Returns the component data of the single instance. + /// + /// This assumes that the row we get from the store only contains a single instance for this + /// component; it will log a warning otherwise. + /// + /// This should only be used for "mono-components" such as `Transform` and `Tensor`. + /// + /// Logs a warning and returns `None` if the component is missing or cannot be deserialized. + #[inline] + pub fn mono(&self, resolver: &PromiseResolver) -> Option { + let component_name = C::name(); + let level = re_log::Level::Warn; + match self.to_dense::(resolver).flatten() { + PromiseResult::Pending => { + re_log::debug_once!("Couldn't deserialize {component_name}: promise still pending",); + None + } + PromiseResult::Ready(data) if data.len() == 1 => Some(data[0].clone()), + PromiseResult::Ready(data) => { + re_log::log_once!( + level, + "Couldn't deserialize {component_name}: not a mono-batch (length: {})", + data.len(), + ); + None + } + PromiseResult::Error(err) => { + re_log::log_once!( + level, + "Couldn't deserialize {component_name}: {}", + re_error::format_ref(&*err), + ); + None + } + } + } + + /// Returns the component data of the single instance as an arrow array. + /// + /// This assumes that the row we get from the store only contains a single instance for this + /// component; it will log a warning otherwise. + /// + /// This should only be used for "mono-components" such as `Transform` and `Tensor`. + /// + /// Logs a warning and returns `None` if the component is missing or cannot be deserialized. + #[inline] + pub fn mono_raw( + &self, + resolver: &PromiseResolver, + component_name: impl Into, + ) -> Option> { + let component_name = component_name.into(); + let level = re_log::Level::Warn; + match self.resolved(resolver) { + PromiseResult::Pending => { + re_log::debug_once!("Couldn't get {component_name}: promise still pending"); + None + } + PromiseResult::Ready(cell) if cell.as_arrow_ref().len() == 1 => { + Some(cell.as_arrow_ref().sliced(0, 1)) + } + PromiseResult::Ready(cell) => { + re_log::log_once!( + level, + "Couldn't get {component_name}: not a mono-batch (length: {})", + cell.as_arrow_ref().len(), + ); + None + } + PromiseResult::Error(err) => { + re_log::log_once!( + level, + "Couldn't get {component_name}: {}", + re_error::format_ref(&*err), + ); + None + } + } + } + + /// Returns the component data of the specified instance. + /// + /// Logs a warning and returns `None` if the component is missing or cannot be deserialized, or + /// the index doesn't exist. + #[inline] + pub fn instance(&self, resolver: &PromiseResolver, index: usize) -> Option { + let component_name = C::name(); + let level = re_log::Level::Warn; + match self.to_dense::(resolver).flatten() { + PromiseResult::Pending => { + re_log::debug_once!("Couldn't deserialize {component_name}: promise still pending",); + None + } + PromiseResult::Ready(data) => { + // TODO(#5303): Figure out we'd like to integrate clamping semantics into selection panel. + // + // For now, we simply always clamp, which is the closest to the legacy behavior that the UI + // expects. + let index = usize::min(index, data.len().saturating_sub(1)); + + if data.len() > index { + Some(data[index].clone()) + } else { + re_log::log_once!( + level, + "Couldn't deserialize {component_name}: index not found (index: {index}, length: {})", + data.len(), + ); + None + } + } + PromiseResult::Error(err) => { + re_log::log_once!( + level, + "Couldn't deserialize {component_name}: {}", + re_error::format_ref(&*err), + ); + None + } + } + } + + /// Returns the component data of the specified instance as an arrow array. + /// + /// Logs a warning and returns `None` if the component is missing or cannot be deserialized, or + /// the index doesn't exist. + #[inline] + pub fn instance_raw( + &self, + resolver: &PromiseResolver, + component_name: impl Into, + index: usize, + ) -> Option> { + let component_name = component_name.into(); + let level = re_log::Level::Warn; + match self.resolved(resolver) { + PromiseResult::Pending => { + re_log::debug_once!("Couldn't get {component_name}: promise still pending"); + None + } + PromiseResult::Ready(cell) if cell.as_arrow_ref().len() > index => { + Some(cell.as_arrow_ref().sliced(index, 1)) + } + PromiseResult::Ready(cell) => { + re_log::log_once!( + level, + "Couldn't get {component_name}: index not found (index: {index}, length: {})", + cell.as_arrow_ref().len(), + ); + None + } + PromiseResult::Error(err) => { + re_log::log_once!( + level, + "Couldn't get {component_name}: {}", + re_error::format_ref(&*err), + ); + None + } + } + } +} // --- @@ -33,8 +252,6 @@ impl std::ops::Deref for CachedLatestAtMonoResult { } } -// --- - impl Caches { /// Get the latest index and value for a given dense [`re_types_core::Component`]. /// diff --git a/crates/re_query_cache2/src/latest_at/results.rs b/crates/re_query_cache2/src/latest_at/results.rs index 3355be18c032..c8a07e39cbd7 100644 --- a/crates/re_query_cache2/src/latest_at/results.rs +++ b/crates/re_query_cache2/src/latest_at/results.rs @@ -139,6 +139,15 @@ impl CachedLatestAtComponentResults { cached_heap_size_bytes: AtomicU64::new(0), } } + + /// Returns the [`ComponentName`] of the resolved data, if available. + #[inline] + pub fn component_name(&self, resolver: &PromiseResolver) -> Option { + match self.resolved(resolver) { + PromiseResult::Ready(cell) => Some(cell.component_name()), + _ => None, + } + } } impl SizeBytes for CachedLatestAtComponentResults { @@ -173,6 +182,16 @@ impl CachedLatestAtComponentResults { &self.index } + /// Returns the raw resolved data, if it's ready. + #[inline] + pub fn resolved(&self, resolver: &PromiseResolver) -> PromiseResult { + if let Some(cell) = self.promise.as_ref() { + resolver.resolve(cell) + } else { + PromiseResult::Pending + } + } + /// Returns the component data as a dense vector. /// /// Returns an error if the component is missing or cannot be deserialized. diff --git a/crates/re_space_view_dataframe/src/space_view_class.rs b/crates/re_space_view_dataframe/src/space_view_class.rs index 05f379c5c714..b6189eb53312 100644 --- a/crates/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/re_space_view_dataframe/src/space_view_class.rs @@ -86,7 +86,6 @@ impl SpaceViewClass for DataframeSpaceView { .cloned() .collect(); - let store = ctx.recording_store(); let latest_at_query = query.latest_at_query(); let sorted_instance_paths: Vec<_>; @@ -108,7 +107,12 @@ impl SpaceViewClass for DataframeSpaceView { sorted_instance_paths = sorted_entity_paths .iter() .flat_map(|entity_path| { - sorted_instance_paths_for(entity_path, store, &query.timeline, &latest_at_query) + sorted_instance_paths_for( + entity_path, + ctx.recording_store(), + &query.timeline, + &latest_at_query, + ) }) .collect(); @@ -117,7 +121,7 @@ impl SpaceViewClass for DataframeSpaceView { sorted_components = sorted_entity_paths .iter() .flat_map(|entity_path| { - store + ctx.recording_store() .all_components(&query.timeline, entity_path) .unwrap_or_default() }) @@ -148,32 +152,34 @@ impl SpaceViewClass for DataframeSpaceView { // of bounds" (aka cannot be joined to a primary component). row.col(|ui| { - instance_path_button(ctx, &latest_at_query, store, ui, None, instance); + instance_path_button(ctx, &latest_at_query, ctx.recording(), ui, None, instance); }); - for comp in &sorted_components { + for component_name in &sorted_components { row.col(|ui| { // TODO(#4466): make it explicit if that value results // from a splat joint. - if let Some((_, _, comp_inst)) = + let results = ctx.recording().query_caches2().latest_at( + ctx.recording_store(), + &latest_at_query, + &instance.entity_path, + [*component_name], + ); + + if let Some(results) = // This is a duplicate of the one above, but this ok since this codes runs // *only* for visible rows. - get_component_with_instances( - store, - &latest_at_query, - &instance.entity_path, - *comp, - ) + results.components.get(component_name) { ctx.component_ui_registry.ui( ctx, ui, UiVerbosity::Small, &latest_at_query, - store, + ctx.recording(), &instance.entity_path, - &comp_inst, + results, &instance.instance_key, ); } else { diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index c7e32c1a09a3..53e822295b99 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -587,12 +587,18 @@ pub fn picking( item_ui::instance_path_button( ctx, &query.latest_at_query(), - store, + ctx.recording(), ui, Some(query.space_view_id), &instance_path, ); - instance_path.data_ui(ctx, ui, UiVerbosity::Reduced, &ctx.current_query(), store); + instance_path.data_ui( + ctx, + ui, + UiVerbosity::Reduced, + &ctx.current_query(), + ctx.recording(), + ); }) }; } @@ -673,7 +679,7 @@ fn image_hover_ui( ui, UiVerbosity::Small, &ctx.current_query(), - ctx.recording_store(), + ctx.recording(), ); } else { // Show it all, like we do for any other thing we hover @@ -682,7 +688,7 @@ fn image_hover_ui( ui, UiVerbosity::Small, &ctx.current_query(), - ctx.recording_store(), + ctx.recording(), ); } diff --git a/crates/re_space_view_text_log/src/space_view_class.rs b/crates/re_space_view_text_log/src/space_view_class.rs index d7b2ee356ecc..ca5d0ae97848 100644 --- a/crates/re_space_view_text_log/src/space_view_class.rs +++ b/crates/re_space_view_text_log/src/space_view_class.rs @@ -359,7 +359,6 @@ fn table_ui( body_clip_rect = Some(body.max_rect()); let query = ctx.current_query(); - let store = ctx.recording_store(); let row_heights = entries.iter().map(|te| calc_row_height(te)); body.heterogeneous_rows(row_heights, |mut row| { @@ -410,7 +409,7 @@ fn table_ui( item_ui::entity_path_button( ctx, &query, - store, + ctx.recording(), ui, None, &entry.entity_path, diff --git a/crates/re_time_panel/src/data_density_graph.rs b/crates/re_time_panel/src/data_density_graph.rs index 50c4e5896c48..3a73e4c1c224 100644 --- a/crates/re_time_panel/src/data_density_graph.rs +++ b/crates/re_time_panel/src/data_density_graph.rs @@ -371,7 +371,7 @@ pub fn data_density_graph_ui( data_dentity_graph_painter: &mut DataDensityGraphPainter, ctx: &ViewerContext<'_>, time_ctrl: &mut TimeControl, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, time_area_response: &egui::Response, time_area_painter: &egui::Painter, ui: &egui::Ui, @@ -497,7 +497,7 @@ pub fn data_density_graph_ui( show_row_ids_tooltip( ctx, time_ctrl, - store, + db, ui.ctx(), item, hovered_time_range, @@ -529,7 +529,7 @@ fn make_brighter(color: Color32) -> Color32 { fn show_row_ids_tooltip( ctx: &ViewerContext<'_>, time_ctrl: &TimeControl, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, egui_ctx: &egui::Context, item: &TimePanelItem, time_range: TimeRange, @@ -561,12 +561,12 @@ fn show_row_ids_tooltip( let component_path = ComponentPath::new(entity_path.clone(), *component_name); item_ui::component_path_button(ctx, ui, &component_path); ui.add_space(8.0); - component_path.data_ui(ctx, ui, verbosity, &query, store); + component_path.data_ui(ctx, ui, verbosity, &query, db); } else { let instance_path = re_entity_db::InstancePath::entity_splat(entity_path.clone()); - item_ui::instance_path_button(ctx, &query, store, ui, None, &instance_path); + item_ui::instance_path_button(ctx, &query, db, ui, None, &instance_path); ui.add_space(8.0); - instance_path.data_ui(ctx, ui, verbosity, &query, store); + instance_path.data_ui(ctx, ui, verbosity, &query, db); } }); } diff --git a/crates/re_time_panel/src/lib.rs b/crates/re_time_panel/src/lib.rs index 4e5c2e685d3a..6aea8b62c413 100644 --- a/crates/re_time_panel/src/lib.rs +++ b/crates/re_time_panel/src/lib.rs @@ -553,9 +553,9 @@ impl TimePanel { ) { let tree_has_data_in_current_timeline = time_ctrl.tree_has_data_in_current_timeline(tree); - let store = match self.source { - TimePanelSource::Recording => ctx.recording_store(), - TimePanelSource::Blueprint => ctx.store_context.blueprint.store(), + let db = match self.source { + TimePanelSource::Recording => ctx.recording(), + TimePanelSource::Blueprint => ctx.store_context.blueprint, }; // The last part of the path component @@ -632,7 +632,7 @@ impl TimePanel { ui, ctx, &time_ctrl.current_query(), - store, + db, &tree.path, ); }); @@ -689,7 +689,7 @@ impl TimePanel { &mut self.data_density_graph_painter, ctx, time_ctrl, - store, + db, time_area_response, time_area_painter, ui, @@ -807,16 +807,16 @@ impl TimePanel { highlight_timeline_row(ui, ctx, time_area_painter, &item.to_item(), &row_rect); - let store = match self.source { - TimePanelSource::Recording => ctx.recording_store(), - TimePanelSource::Blueprint => ctx.store_context.blueprint.store(), + let db = match self.source { + TimePanelSource::Recording => ctx.recording(), + TimePanelSource::Blueprint => ctx.store_context.blueprint, }; data_density_graph::data_density_graph_ui( &mut self.data_density_graph_painter, ctx, time_ctrl, - store, + db, time_area_response, time_area_painter, ui, diff --git a/crates/re_viewer/src/ui/override_ui.rs b/crates/re_viewer/src/ui/override_ui.rs index b69f46aca3b3..ae6e37ed0594 100644 --- a/crates/re_viewer/src/ui/override_ui.rs +++ b/crates/re_viewer/src/ui/override_ui.rs @@ -2,11 +2,10 @@ use std::collections::{BTreeMap, BTreeSet}; use itertools::Itertools; -use re_data_store::{DataStore, LatestAtQuery}; +use re_data_store::LatestAtQuery; use re_data_ui::is_component_visible_in_ui; use re_entity_db::{EntityDb, InstancePath}; use re_log_types::{DataCell, DataRow, RowId, StoreKind}; -use re_query_cache::external::re_query::get_component_with_instances; use re_space_view::{determine_visualizable_entities, SpaceViewBlueprint}; use re_types_core::{ components::{InstanceKey, VisualizerOverrides}, @@ -33,7 +32,6 @@ pub fn override_ui( // entity from the blueprint-inspector since it isn't "part" of a space-view to provide // the overrides. let query = ctx.current_query(); - let store = ctx.recording_store(); let query_result = ctx.lookup_query_result(space_view.id); let Some(data_result) = query_result @@ -80,7 +78,7 @@ pub fn override_ui( add_new_override( ctx, &query, - store, + ctx.recording(), ui, &view_systems, &component_to_vis, @@ -142,23 +140,39 @@ pub fn override_ui( StoreKind::Blueprint => { let store = ctx.store_context.blueprint.store(); let query = ctx.blueprint_query; - get_component_with_instances(store, query, path, *component_name) + ctx.store_context + .blueprint + .query_caches2() + .latest_at(store, query, entity_path, [*component_name]) + .components + .get(component_name) + .cloned() /* arc */ } StoreKind::Recording => { - get_component_with_instances(store, &query, path, *component_name) + ctx.recording() + .query_caches2() + .latest_at( + ctx.recording_store(), + &query, + entity_path, + [*component_name], + ) + .components + .get(component_name) + .cloned() /* arc */ } }; - if let Some((_, _, component_data)) = component_data { + if let Some(results) = component_data { ctx.component_ui_registry.edit_ui( ctx, ui, UiVerbosity::Small, &query, - store, + ctx.recording(), path, &overrides.individual_override_path, - &component_data, + &results, instance_key, ); } else { @@ -176,7 +190,7 @@ pub fn override_ui( pub fn add_new_override( ctx: &ViewerContext<'_>, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, ui: &mut egui::Ui, view_systems: &re_viewer_context::VisualizerCollection, component_to_vis: &BTreeMap, @@ -228,7 +242,8 @@ pub fn add_new_override( let mut splat_cell: DataCell = [InstanceKey::SPLAT].into(); splat_cell.compute_size_bytes(); - let Some(mut initial_data) = store + let Some(mut initial_data) = db + .store() .latest_at(query, &data_result.entity_path, *component, &components) .and_then(|result| result.2[0].clone()) .and_then(|cell| { @@ -243,7 +258,7 @@ pub fn add_new_override( sys.initial_override_value( ctx, query, - store, + db.store(), &data_result.entity_path, component, ) @@ -253,7 +268,7 @@ pub fn add_new_override( ctx.component_ui_registry.default_value( ctx, query, - store, + db, &data_result.entity_path, component, ) diff --git a/crates/re_viewer/src/ui/recordings_panel.rs b/crates/re_viewer/src/ui/recordings_panel.rs index 880863647912..5f094b276516 100644 --- a/crates/re_viewer/src/ui/recordings_panel.rs +++ b/crates/re_viewer/src/ui/recordings_panel.rs @@ -202,8 +202,8 @@ fn app_and_its_recordings_ui( ctx, ui, UiVerbosity::Reduced, - &ctx.current_query(), // unused - ctx.recording_store(), // unused + &ctx.current_query(), // unused + ctx.recording(), // unused ); }); diff --git a/crates/re_viewer/src/ui/selection_panel.rs b/crates/re_viewer/src/ui/selection_panel.rs index d91d4a65bb44..b311b38055bd 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -148,13 +148,7 @@ impl SelectionPanel { } else { (ctx.current_query(), ctx.recording()) }; - data_ui_item.data_ui( - ctx, - ui, - multi_selection_verbosity, - &query, - db.store(), - ); + data_ui_item.data_ui(ctx, ui, multi_selection_verbosity, &query, db); }); } @@ -385,7 +379,7 @@ fn what_is_selected_ui( ui.horizontal(|ui| { ui.label("component of"); - item_ui::entity_path_button(ctx, &query, db.store(), ui, None, entity_path); + item_ui::entity_path_button(ctx, &query, db, ui, None, entity_path); }); list_existing_data_blueprints(ui, ctx, &entity_path.clone().into(), viewport); @@ -443,14 +437,7 @@ fn what_is_selected_ui( guess_query_and_db_for_selected_entity(ctx, &instance_path.entity_path); ui.horizontal(|ui| { ui.label("Parent"); - item_ui::entity_path_parts_buttons( - ctx, - &query, - db.store(), - ui, - None, - &parent, - ); + item_ui::entity_path_parts_buttons(ctx, &query, db, ui, None, &parent); }); } } @@ -492,7 +479,7 @@ fn what_is_selected_ui( item_ui::entity_path_parts_buttons( ctx, &query, - db.store(), + db, ui, Some(*space_view_id), &parent, @@ -550,7 +537,7 @@ fn list_existing_data_blueprints( item_ui::instance_path_button_to( ctx, &query, - db.store(), + db, ui, Some(*space_view_id), instance_path, @@ -1307,17 +1294,10 @@ fn depth_props_ui( if backproject_depth { ui.label("Pinhole"); - item_ui::entity_path_button( - ctx, - &query, - db.store(), - ui, - None, - &image_projection_ent_path, - ) - .on_hover_text( - "The entity path of the pinhole transform being used to do the backprojection.", - ); + item_ui::entity_path_button(ctx, &query, db, ui, None, &image_projection_ent_path) + .on_hover_text( + "The entity path of the pinhole transform being used to do the backprojection.", + ); ui.end_row(); depth_from_world_scale_ui(ui, &mut entity_props.depth_from_world_scale); diff --git a/crates/re_viewer_context/src/component_ui_registry.rs b/crates/re_viewer_context/src/component_ui_registry.rs index 5ec1e81f08e9..f687e5ec6168 100644 --- a/crates/re_viewer_context/src/component_ui_registry.rs +++ b/crates/re_viewer_context/src/component_ui_registry.rs @@ -1,9 +1,10 @@ use std::collections::BTreeMap; -use re_data_store::{DataStore, LatestAtQuery}; -use re_entity_db::EntityPath; +use re_data_store::LatestAtQuery; +use re_entity_db::{ + external::re_query_cache2::CachedLatestAtComponentResults, EntityDb, EntityPath, +}; use re_log_types::DataCell; -use re_query::ComponentWithInstances; use re_types::{components::InstanceKey, ComponentName, Loggable as _}; use crate::ViewerContext; @@ -39,9 +40,9 @@ type ComponentUiCallback = Box< &mut egui::Ui, UiVerbosity, &LatestAtQuery, - &DataStore, + &EntityDb, &EntityPath, - &ComponentWithInstances, + &CachedLatestAtComponentResults, &InstanceKey, ) + Send + Sync, @@ -53,17 +54,17 @@ type ComponentEditCallback = Box< &mut egui::Ui, UiVerbosity, &LatestAtQuery, - &DataStore, + &EntityDb, &EntityPath, &EntityPath, - &ComponentWithInstances, + &CachedLatestAtComponentResults, &InstanceKey, ) + Send + Sync, >; type DefaultValueCallback = Box< - dyn Fn(&ViewerContext<'_>, &LatestAtQuery, &DataStore, &EntityPath) -> DataCell + Send + Sync, + dyn Fn(&ViewerContext<'_>, &LatestAtQuery, &EntityDb, &EntityPath) -> DataCell + Send + Sync, >; /// How to display components in a Ui. @@ -119,14 +120,19 @@ impl ComponentUiRegistry { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &InstanceKey, ) { - re_tracing::profile_function!(component.name().full_name()); + let Some(component_name) = component.component_name(db.resolver()) else { + // TODO(#5607): what should happen if the promise is still pending? + return; + }; + + re_tracing::profile_function!(component_name.full_name()); - if component.name() == InstanceKey::name() { + if component_name == InstanceKey::name() { // The user wants to show a ui for the `InstanceKey` component - well, that's easy: ui.label(instance_key.to_string()); return; @@ -134,14 +140,14 @@ impl ComponentUiRegistry { let ui_callback = self .component_uis - .get(&component.name()) + .get(&component_name) .unwrap_or(&self.fallback_ui); (*ui_callback)( ctx, ui, verbosity, query, - store, + db, entity_path, component, instance_key, @@ -156,21 +162,26 @@ impl ComponentUiRegistry { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, override_path: &EntityPath, - component: &ComponentWithInstances, + component: &CachedLatestAtComponentResults, instance_key: &InstanceKey, ) { - re_tracing::profile_function!(component.name().full_name()); + let Some(component_name) = component.component_name(db.resolver()) else { + // TODO(#5607): what should happen if the promise is still pending? + return; + }; + + re_tracing::profile_function!(component_name.full_name()); - if let Some((_, edit_callback)) = self.component_editors.get(&component.name()) { + if let Some((_, edit_callback)) = self.component_editors.get(&component_name) { (*edit_callback)( ctx, ui, verbosity, query, - store, + db, entity_path, override_path, component, @@ -183,7 +194,7 @@ impl ComponentUiRegistry { ui, verbosity, query, - store, + db, entity_path, component, instance_key, @@ -197,7 +208,7 @@ impl ComponentUiRegistry { &self, ctx: &ViewerContext<'_>, query: &LatestAtQuery, - store: &DataStore, + db: &EntityDb, entity_path: &EntityPath, component: &ComponentName, ) -> Option { @@ -205,6 +216,6 @@ impl ComponentUiRegistry { self.component_editors .get(component) - .map(|(default_value, _)| (*default_value)(ctx, query, store, entity_path)) + .map(|(default_value, _)| (*default_value)(ctx, query, db, entity_path)) } } diff --git a/crates/re_viewport/src/blueprint/data_ui.rs b/crates/re_viewport/src/blueprint/data_ui.rs index ae5010180662..7ed45bc2274a 100644 --- a/crates/re_viewport/src/blueprint/data_ui.rs +++ b/crates/re_viewport/src/blueprint/data_ui.rs @@ -11,10 +11,10 @@ impl DataUi for IncludedSpaceView { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let space_view: SpaceViewId = self.0.into(); - space_view.data_ui(ctx, ui, verbosity, query, store); + space_view.data_ui(ctx, ui, verbosity, query, db); } } @@ -26,10 +26,10 @@ impl DataUi for SpaceViewMaximized { ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, - store: &re_data_store::DataStore, + db: &re_entity_db::EntityDb, ) { let space_view: SpaceViewId = self.0.into(); - space_view.data_ui(ctx, ui, verbosity, query, store); + space_view.data_ui(ctx, ui, verbosity, query, db); } } diff --git a/crates/re_viewport/src/space_view_entity_picker.rs b/crates/re_viewport/src/space_view_entity_picker.rs index 4b59093a9537..23c268f67d63 100644 --- a/crates/re_viewport/src/space_view_entity_picker.rs +++ b/crates/re_viewport/src/space_view_entity_picker.rs @@ -154,7 +154,6 @@ fn add_entities_line_ui( re_tracing::profile_function!(); let query = ctx.current_query(); - let store = ctx.recording_store(); ui.horizontal(|ui| { let entity_path = &entity_tree.path; @@ -177,7 +176,7 @@ fn add_entities_line_ui( let response = item_ui::instance_path_button_to( ctx, &query, - store, + ctx.recording(), ui, Some(space_view.id), &InstancePath::entity_splat(entity_path.clone()), diff --git a/crates/re_viewport/src/viewport_blueprint_ui.rs b/crates/re_viewport/src/viewport_blueprint_ui.rs index aa57a27e67b1..602d91c32e0a 100644 --- a/crates/re_viewport/src/viewport_blueprint_ui.rs +++ b/crates/re_viewport/src/viewport_blueprint_ui.rs @@ -523,8 +523,6 @@ impl Viewport<'_, '_> { space_view_visible: bool, projection_mode: bool, ) { - let store = ctx.recording_store(); - let entity_path = node_or_path.path(); if projection_mode && entity_path == &space_view.space_origin { @@ -662,7 +660,13 @@ impl Viewport<'_, '_> { let response = response.on_hover_ui(|ui| { let query = ctx.current_query(); - re_data_ui::item_ui::entity_hover_card_ui(ui, ctx, &query, store, entity_path); + re_data_ui::item_ui::entity_hover_card_ui( + ui, + ctx, + &query, + ctx.recording(), + entity_path, + ); if empty_origin { ui.label(ctx.re_ui.warning_text( diff --git a/examples/rust/custom_space_view/src/color_coordinates_space_view.rs b/examples/rust/custom_space_view/src/color_coordinates_space_view.rs index 2c53a75d60b9..8c4bce111ac9 100644 --- a/examples/rust/custom_space_view/src/color_coordinates_space_view.rs +++ b/examples/rust/custom_space_view/src/color_coordinates_space_view.rs @@ -275,7 +275,7 @@ fn color_space_ui( item_ui::instance_path_button( ctx, &ctx.current_query(), - ctx.recording_store(), + ctx.recording(), ui, Some(query.space_view_id), &instance, @@ -285,7 +285,7 @@ fn color_space_ui( ui, UiVerbosity::Reduced, &ctx.current_query(), - ctx.recording_store(), + ctx.recording(), ); }); ctx.select_hovered_on_click(&interact, Item::DataResult(query.space_view_id, instance)); diff --git a/examples/rust/extend_viewer_ui/src/main.rs b/examples/rust/extend_viewer_ui/src/main.rs index d0ac54af050e..fbc37dee872b 100644 --- a/examples/rust/extend_viewer_ui/src/main.rs +++ b/examples/rust/extend_viewer_ui/src/main.rs @@ -1,8 +1,7 @@ //! This example shows how to wrap the Rerun Viewer in your own GUI. use re_viewer::external::{ - arrow2, eframe, egui, re_data_store, re_entity_db, re_log, re_log_types, re_memory, re_query, - re_types, + arrow2, eframe, egui, re_data_store, re_entity_db, re_log, re_log_types, re_memory, re_types, }; // By using `re_memory::AccountingAllocator` Rerun can keep track of exactly how much memory it is using, @@ -153,20 +152,26 @@ fn component_ui( // just show the last value logged for each component: let query = re_data_store::LatestAtQuery::latest(timeline); - if let Some((_, _, component)) = re_query::get_component_with_instances( + let results = entity_db.query_caches2().latest_at( entity_db.store(), &query, entity_path, - component_name, - ) { + [component_name], + ); + let component = results + .components + .get(&component_name) + .and_then(|result| result.raw(entity_db.resolver(), component_name)); + + if let Some(data) = component { egui::ScrollArea::vertical() .auto_shrink([false, true]) .show(ui, |ui| { // Iterate over all the instances (e.g. all the points in the point cloud): - for instance_key in component.instance_keys() { - if let Some(value) = component.lookup_arrow(&instance_key) { - ui.label(format_arrow(&*value)); - } + + let num_instances = data.len(); + for i in 0..num_instances { + ui.label(format_arrow(&*data.sliced(i, 1))); } }); };