diff --git a/crates/re_data_ui/src/component.rs b/crates/re_data_ui/src/component.rs index 61b6072da1ba..999d2813f03b 100644 --- a/crates/re_data_ui/src/component.rs +++ b/crates/re_data_ui/src/component.rs @@ -1,32 +1,23 @@ +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_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<'_>, @@ -35,10 +26,17 @@ impl DataUi for EntityComponentWithInstances { query: &re_data_store::LatestAtQuery, 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, @@ -69,7 +67,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` @@ -79,20 +77,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, - db, - &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", @@ -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("Instance key"); + 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, - db, - ui, - None, - &instance_path, - instance_key.to_string(), - ); - }); - row.col(|ui| { - ctx.component_ui_registry.ui( - ctx, - ui, - UiVerbosity::Small, - query, - db, - &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.to_string(), + ); + }); + 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_number(num_instances - displayed_row) + re_format::format_number(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 6f28864043fa..bd36cc422df0 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}; @@ -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(db.store(), query, entity_path, *component_name) - { - super::component::EntityComponentWithInstances { - entity_path: self.entity_path.clone(), - component_data, - } - .data_ui(ctx, ui, verbosity, query, db); - } else if let Some(entity_tree) = ctx.entity_db.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.entity_db.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 8e64c4613dcc..e576b76c0b66 100644 --- a/crates/re_data_ui/src/component_ui_registry.rs +++ b/crates/re_data_ui/src/component_ui_registry.rs @@ -1,7 +1,6 @@ use re_data_store::LatestAtQuery; -use re_entity_db::EntityDb; +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}; @@ -40,18 +39,13 @@ pub fn add_to_registry(registry: &mut Com registry.add( C::name(), Box::new( - |ctx, ui, verbosity, query, db, entity_path, component, instance| match component - .lookup::(instance) - { - Ok(component) => { + |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); - } - Err(re_query::QueryError::ComponentNotFound(_)) => { + } else { ui.weak("(not found)"); } - Err(err) => { - re_log::warn_once!("Expected component {}, {}", C::name(), err); - } }, ), ); @@ -63,13 +57,20 @@ fn fallback_component_ui( ui: &mut egui::Ui, verbosity: UiVerbosity, _query: &LatestAtQuery, - _db: &EntityDb, + 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/editors.rs b/crates/re_data_ui/src/editors.rs index 7184cd46fde7..7f5487908554 100644 --- a/crates/re_data_ui/src/editors.rs +++ b/crates/re_data_ui/src/editors.rs @@ -2,9 +2,8 @@ use egui::NumExt as _; use re_data_store::LatestAtQuery; -use re_entity_db::EntityDb; +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, @@ -24,12 +23,12 @@ fn edit_color_ui( 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() + // 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(); @@ -67,12 +66,12 @@ fn edit_text_ui( 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() + // 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(); @@ -107,12 +106,12 @@ fn edit_name_ui( 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() + // 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(); @@ -148,12 +147,12 @@ fn edit_scatter_ui( 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() + // 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; @@ -197,12 +196,12 @@ fn edit_radius_ui( 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() + // 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; @@ -244,12 +243,12 @@ fn edit_marker_shape_ui( 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() + // 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; @@ -327,12 +326,12 @@ fn edit_stroke_width_ui( 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() + // 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; @@ -374,12 +373,12 @@ fn edit_marker_size_ui( 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() + // 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; @@ -423,7 +422,7 @@ fn register_editor<'a, C: Component + Loggable + 'static>( &EntityDb, &EntityPath, &EntityPath, - &ComponentWithInstances, + &CachedLatestAtComponentResults, &re_types::components::InstanceKey, ), ) where diff --git a/crates/re_data_ui/src/instance_path.rs b/crates/re_data_ui/src/instance_path.rs index 41239e9a4115..6f4cdd0752b5 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; @@ -71,12 +72,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( + let results = db.query_caches2().latest_at( db.store(), query, entity_path, - component_name, - ) else { + [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 }; @@ -87,9 +89,10 @@ 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, db); } else { @@ -100,7 +103,7 @@ impl DataUi for InstancePath { query, db, entity_path, - &component_data, + results, instance_key, ); } diff --git a/crates/re_data_ui/src/lib.rs b/crates/re_data_ui/src/lib.rs index fa7e0eb0220e..6d6395735efc 100644 --- a/crates/re_data_ui/src/lib.rs +++ b/crates/re_data_ui/src/lib.rs @@ -33,7 +33,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; 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 4b75f53b1ba4..897d9e4a87ac 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,7 @@ impl SpaceViewClass for DataframeSpaceView { .cloned() .collect(); - let store = ctx.entity_db.store(); + let db = ctx.entity_db; let latest_at_query = query.latest_at_query(); let sorted_instance_paths: Vec<_>; @@ -108,7 +108,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, + db.store(), + &query.timeline, + &latest_at_query, + ) }) .collect(); @@ -117,7 +122,7 @@ impl SpaceViewClass for DataframeSpaceView { sorted_components = sorted_entity_paths .iter() .flat_map(|entity_path| { - store + db.store() .all_components(&query.timeline, entity_path) .unwrap_or_default() }) @@ -151,20 +156,22 @@ impl SpaceViewClass for DataframeSpaceView { instance_path_button(ctx, &latest_at_query, ctx.entity_db, 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 = db.query_caches2().latest_at( + db.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, @@ -173,7 +180,7 @@ impl SpaceViewClass for DataframeSpaceView { &latest_at_query, ctx.entity_db, &instance.entity_path, - &comp_inst, + results, &instance.instance_key, ); } else { diff --git a/crates/re_viewer/src/ui/override_ui.rs b/crates/re_viewer/src/ui/override_ui.rs index 354786e89b23..ea638db69c4a 100644 --- a/crates/re_viewer/src/ui/override_ui.rs +++ b/crates/re_viewer/src/ui/override_ui.rs @@ -6,7 +6,6 @@ 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}, @@ -142,17 +141,22 @@ 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) + db.query_caches2() + .latest_at(store, query, entity_path, [*component_name]) + .components + .get(component_name) + .cloned() /* arc */ + } + StoreKind::Recording => { + db.query_caches2() + .latest_at(db.store(), &query, entity_path, [*component_name]) + .components + .get(component_name) + .cloned() /* arc */ } - StoreKind::Recording => get_component_with_instances( - db.store(), - &query, - path, - *component_name, - ), }; - if let Some((_, _, component_data)) = component_data { + if let Some(results) = component_data { ctx.component_ui_registry.edit_ui( ctx, ui, @@ -161,7 +165,7 @@ pub fn override_ui( db, path, &overrides.individual_override_path, - &component_data, + &results, instance_key, ); } else { diff --git a/crates/re_viewer_context/src/component_ui_registry.rs b/crates/re_viewer_context/src/component_ui_registry.rs index b2c1f2247632..5d14a2016076 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::LatestAtQuery; -use re_entity_db::{EntityDb, EntityPath}; +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; @@ -41,7 +42,7 @@ type ComponentUiCallback = Box< &LatestAtQuery, &EntityDb, &EntityPath, - &ComponentWithInstances, + &CachedLatestAtComponentResults, &InstanceKey, ) + Send + Sync, @@ -56,7 +57,7 @@ type ComponentEditCallback = Box< &EntityDb, &EntityPath, &EntityPath, - &ComponentWithInstances, + &CachedLatestAtComponentResults, &InstanceKey, ) + Send + Sync, @@ -121,12 +122,17 @@ impl ComponentUiRegistry { query: &LatestAtQuery, 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,7 +140,7 @@ impl ComponentUiRegistry { let ui_callback = self .component_uis - .get(&component.name()) + .get(&component_name) .unwrap_or(&self.fallback_ui); (*ui_callback)( ctx, @@ -159,12 +165,17 @@ impl ComponentUiRegistry { 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,