diff --git a/crates/re_data_store/src/store_read.rs b/crates/re_data_store/src/store_read.rs index d68d43cbf6035..d4a140cf9e275 100644 --- a/crates/re_data_store/src/store_read.rs +++ b/crates/re_data_store/src/store_read.rs @@ -239,7 +239,10 @@ impl DataStore { /// let components = &[cluster_key, primary]; /// let (_, cells) = store /// .latest_at(&query, ent_path, primary, components) - /// .unwrap_or((RowId::ZERO, [(); 2].map(|_| None))); + /// .map_or_else( + /// || (RowId::ZERO, [(); 2].map(|_| None)), + /// |(_, row_id, cells)| (row_id, cells), + /// ); /// /// let series: Result, _> = cells /// .iter() @@ -436,7 +439,10 @@ impl DataStore { /// let query = LatestAtQuery::new(query.timeline, latest_time); /// let (_, cells) = store /// .latest_at(&query, ent_path, primary, &components) - /// .unwrap_or((RowId::ZERO, [(); 2].map(|_| None))); + /// .map_or_else( + /// || (RowId::ZERO, [(); 2].map(|_| None)), + /// |(_, row_id, cells)| (row_id, cells), + /// ); /// dataframe_from_cells(cells) /// }; /// diff --git a/crates/re_data_ui/src/component_path.rs b/crates/re_data_ui/src/component_path.rs index 1c40a91311a23..8fabfd5929942 100644 --- a/crates/re_data_ui/src/component_path.rs +++ b/crates/re_data_ui/src/component_path.rs @@ -28,7 +28,7 @@ impl DataUi for ComponentPath { ui.label(format!( "Indicator component for the {archetype_name} archetype" )); - } else if let Some((_, component_data)) = + } else if let Some((_, _, component_data)) = re_query::get_component_with_instances(store, query, entity_path, *component_name) { super::component::EntityComponentWithInstances { diff --git a/crates/re_data_ui/src/instance_path.rs b/crates/re_data_ui/src/instance_path.rs index 6f8bc8185dbfb..0e58bc45e1068 100644 --- a/crates/re_data_ui/src/instance_path.rs +++ b/crates/re_data_ui/src/instance_path.rs @@ -60,7 +60,7 @@ impl DataUi for InstancePath { UiVerbosity::LimitHeight | UiVerbosity::Full => {} } - let Some((_, component_data)) = + let Some((_, _, component_data)) = get_component_with_instances(store, query, entity_path, component_name) else { continue; // no need to show components that are unset at this point in time diff --git a/crates/re_query/benches/query_benchmark.rs b/crates/re_query/benches/query_benchmark.rs index 72cb9c80a087b..9dcfc45b44b8b 100644 --- a/crates/re_query/benches/query_benchmark.rs +++ b/crates/re_query/benches/query_benchmark.rs @@ -272,7 +272,7 @@ fn query_and_visit_points(store: &DataStore, paths: &[EntityPath]) -> Vec(store, &query, path).unwrap(); + let (_, arch_view) = query_archetype::(store, &query, path).unwrap(); itertools::izip!( arch_view.iter_required_component::().unwrap(), arch_view.iter_optional_component::().unwrap() @@ -299,7 +299,7 @@ fn query_and_visit_strings(store: &DataStore, paths: &[EntityPath]) -> Vec(store, &query, path).unwrap(); + let (_, arch_view) = query_archetype::(store, &query, path).unwrap(); arch_view .iter_optional_component::() .unwrap() diff --git a/crates/re_query/src/archetype_view.rs b/crates/re_query/src/archetype_view.rs index aff4178e0b1e0..49aa69c5de3cb 100644 --- a/crates/re_query/src/archetype_view.rs +++ b/crates/re_query/src/archetype_view.rs @@ -232,6 +232,7 @@ where /// the required [`Component`]s using [`InstanceKey`] values. #[derive(Clone, Debug)] pub struct ArchetypeView { + // pub(crate) primary_data_time: Option, pub(crate) primary_row_id: RowId, pub(crate) components: BTreeMap, pub(crate) phantom: PhantomData, diff --git a/crates/re_query/src/query.rs b/crates/re_query/src/query.rs index 382fbe031bf45..71854900fec74 100644 --- a/crates/re_query/src/query.rs +++ b/crates/re_query/src/query.rs @@ -1,5 +1,5 @@ use re_data_store::{DataStore, LatestAtQuery}; -use re_log_types::{EntityPath, RowId}; +use re_log_types::{EntityPath, RowId, TimeInt}; use re_types_core::{components::InstanceKey, Archetype, ComponentName, Loggable}; use crate::{ArchetypeView, ComponentWithInstances, QueryError}; @@ -53,14 +53,16 @@ pub fn get_component_with_instances( query: &LatestAtQuery, ent_path: &EntityPath, component: ComponentName, -) -> Option<(RowId, ComponentWithInstances)> { +) -> Option<(Option, RowId, ComponentWithInstances)> { debug_assert_eq!(store.cluster_key(), InstanceKey::name()); let components = [InstanceKey::name(), component]; - let (_, row_id, mut cells) = store.latest_at(query, ent_path, component, &components)?; + let (data_time, row_id, mut cells) = + store.latest_at(query, ent_path, component, &components)?; Some(( + data_time, row_id, ComponentWithInstances { // NOTE: The unwrap cannot fail, the cluster key's presence is guaranteed @@ -119,7 +121,7 @@ pub fn query_archetype( store: &DataStore, query: &LatestAtQuery, ent_path: &EntityPath, -) -> crate::Result> { +) -> crate::Result<(Option, ArchetypeView)> { re_tracing::profile_function!(); let required_components: Vec<_> = A::required_components() @@ -138,9 +140,11 @@ pub fn query_archetype( } } - let (row_ids, required_components): (Vec<_>, Vec<_>) = - required_components.into_iter().flatten().unzip(); + use itertools::Itertools as _; + let (data_times, row_ids, required_components): (Vec<_>, Vec<_>, Vec<_>) = + required_components.into_iter().flatten().multiunzip(); + let data_time = data_times.first().unwrap_or(&None); let row_id = row_ids.first().unwrap_or(&RowId::ZERO); let recommended_components = A::recommended_components(); @@ -151,12 +155,15 @@ pub fn query_archetype( .chain(optional_components.iter()) .filter_map(|component| { get_component_with_instances(store, query, ent_path, *component) - .map(|(_, component_result)| component_result) + .map(|(_, _, component_result)| component_result) }); - Ok(ArchetypeView::from_components( - *row_id, - required_components.into_iter().chain(other_components), + Ok(( + *data_time, + ArchetypeView::from_components( + *row_id, + required_components.into_iter().chain(other_components), + ), )) } @@ -218,7 +225,7 @@ fn simple_get_component() { let ent_path = "point"; let query = LatestAtQuery::new(Timeline::new_sequence("frame_nr"), 123.into()); - let (_, component) = + let (_, _, component) = get_component_with_instances(&store, &query, &ent_path.into(), MyPoint::name()).unwrap(); #[cfg(feature = "polars")] @@ -253,7 +260,7 @@ fn simple_query_archetype() { let ent_path = "point"; let query = LatestAtQuery::new(Timeline::new_sequence("frame_nr"), 123.into()); - let arch_view = query_archetype::(&store, &query, &ent_path.into()).unwrap(); + let (_, arch_view) = query_archetype::(&store, &query, &ent_path.into()).unwrap(); let expected_positions = [MyPoint::new(1.0, 2.0), MyPoint::new(3.0, 4.0)]; let expected_colors = [None, Some(MyColor::from(0xff000000))]; diff --git a/crates/re_query/src/range.rs b/crates/re_query/src/range.rs index e42ef42f24182..68bd90cd1c4e3 100644 --- a/crates/re_query/src/range.rs +++ b/crates/re_query/src/range.rs @@ -63,10 +63,10 @@ pub fn range_archetype<'a, A: Archetype + 'a, const N: usize>( // NOTE: This will return none for `TimeInt::Min`, i.e. range queries that start infinitely far // into the past don't have a latest-at state! - let latest_time = query.range.min.as_i64().checked_sub(1).map(Into::into); + let query_time = query.range.min.as_i64().checked_sub(1).map(Into::into); let mut cwis_latest = None; - if let Some(latest_time) = latest_time { + if let Some(query_time) = query_time { let mut cwis_latest_raw: Vec<_> = std::iter::repeat_with(|| None) .take(components.len()) .collect(); @@ -77,10 +77,11 @@ pub fn range_archetype<'a, A: Archetype + 'a, const N: usize>( for (i, primary) in components.iter().enumerate() { cwis_latest_raw[i] = get_component_with_instances( store, - &LatestAtQuery::new(query.timeline, latest_time), + &LatestAtQuery::new(query.timeline, query_time), ent_path, *primary, - ); + ) + .map(|(_, row_id, cwi)| (row_id, cwi)); } if cwis_latest_raw[primary_col].is_some() { @@ -91,33 +92,31 @@ pub fn range_archetype<'a, A: Archetype + 'a, const N: usize>( // send the latest-at state before anything else cwis_latest .into_iter() - .map(move |cwis| (latest_time, true, cwis)) - .chain( - store - .range(query, ent_path, components) - .map(move |(time, row_id, mut cells)| { - // NOTE: The unwrap cannot fail, the cluster key's presence is guaranteed - // by the store. - let instance_keys = cells[cluster_col].take().unwrap(); - let is_primary = cells[primary_col].is_some(); - let cwis = cells - .into_iter() - .map(|cell| { - cell.map(|cell| { - ( - row_id, - ComponentWithInstances { - instance_keys: instance_keys.clone(), /* shallow */ - values: cell, - }, - ) - }) + .map(move |cwis| (query_time, true, cwis)) + .chain(store.range(query, ent_path, components).map( + move |(data_time, row_id, mut cells)| { + // NOTE: The unwrap cannot fail, the cluster key's presence is guaranteed + // by the store. + let instance_keys = cells[cluster_col].take().unwrap(); + let is_primary = cells[primary_col].is_some(); + let cwis = cells + .into_iter() + .map(|cell| { + cell.map(|cell| { + ( + row_id, + ComponentWithInstances { + instance_keys: instance_keys.clone(), /* shallow */ + values: cell, + }, + ) }) - .collect::>(); - (time, is_primary, cwis) - }), - ) - .filter_map(move |(time, is_primary, cwis)| { + }) + .collect::>(); + (data_time, is_primary, cwis) + }, + )) + .filter_map(move |(data_time, is_primary, cwis)| { for (i, cwi) in cwis .into_iter() .enumerate() @@ -138,7 +137,7 @@ pub fn range_archetype<'a, A: Archetype + 'a, const N: usize>( let arch_view = ArchetypeView::from_components(row_id, components); - (time, arch_view) + (data_time, arch_view) }) }) } diff --git a/crates/re_query/src/util.rs b/crates/re_query/src/util.rs index bb98eeab30260..45ec430040b55 100644 --- a/crates/re_query/src/util.rs +++ b/crates/re_query/src/util.rs @@ -11,7 +11,7 @@ pub fn query_archetype_with_history<'a, A: Archetype + 'a, const N: usize>( time: &'a TimeInt, history: &ExtraQueryHistory, ent_path: &'a EntityPath, -) -> crate::Result> + 'a> { +) -> crate::Result, ArchetypeView)> + 'a> { let visible_history = match timeline.typ() { re_log_types::TimeType::Time => history.nanos, re_log_types::TimeType::Sequence => history.sequences, @@ -30,6 +30,6 @@ pub fn query_archetype_with_history<'a, A: Archetype + 'a, const N: usize>( let range = range_archetype::(store, &range_query, ent_path); - Ok(itertools::Either::Right(range.map(|(_, entity)| entity))) + Ok(itertools::Either::Right(range)) } } diff --git a/crates/re_query/tests/archetype_query_tests.rs b/crates/re_query/tests/archetype_query_tests.rs index 00d077f1e79de..b5bfb1ed6826d 100644 --- a/crates/re_query/tests/archetype_query_tests.rs +++ b/crates/re_query/tests/archetype_query_tests.rs @@ -41,7 +41,8 @@ fn simple_query() { // Retrieve the view let timeline_query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - let arch_view = query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); + let (_, arch_view) = + query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); // We expect this to generate the following `DataFrame` // ┌──────────┬───────────┬────────────┐ @@ -105,7 +106,8 @@ fn timeless_query() { // Retrieve the view let timeline_query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - let arch_view = query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); + let (_, arch_view) = + query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); // We expect this to generate the following `DataFrame` // ┌──────────┬───────────┬────────────┐ @@ -167,7 +169,8 @@ fn no_instance_join_query() { // Retrieve the view let timeline_query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - let arch_view = query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); + let (_, arch_view) = + query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); // We expect this to generate the following `DataFrame` // ┌──────────┬───────────┬────────────┐ @@ -227,7 +230,8 @@ fn missing_column_join_query() { // Retrieve the view let timeline_query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - let arch_view = query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); + let (_, arch_view) = + query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); // We expect this to generate the following `DataFrame` // @@ -296,7 +300,8 @@ fn splatted_query() { // Retrieve the view let timeline_query = re_data_store::LatestAtQuery::new(timepoint[0].0, timepoint[0].1); - let arch_view = query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); + let (_, arch_view) = + query_archetype::(&store, &timeline_query, &ent_path.into()).unwrap(); // We expect this to generate the following `DataFrame` // ┌──────────┬───────────┬────────────┐ diff --git a/crates/re_query_cache/src/query.rs b/crates/re_query_cache/src/query.rs index 172feaee4760f..a4deae72bc960 100644 --- a/crates/re_query_cache/src/query.rs +++ b/crates/re_query_cache/src/query.rs @@ -105,7 +105,8 @@ macro_rules! impl_query_archetype { if bucket.is_empty() { let now = web_time::Instant::now(); - let arch_view = query_archetype::(store, &query, entity_path)?; + // TODO(cmc): cache deduplication. + let (_data_time, arch_view) = query_archetype::(store, &query, entity_path)?; bucket.[]::(query.at, &arch_view)?; @@ -152,7 +153,7 @@ macro_rules! impl_query_archetype { for (time, arch_view) in arch_views { let data = ( - // TODO(cmc): `ArchetypeView` should indicate its pov time. + // TODO(cmc): actual timeless caching support. (time.unwrap_or(TimeInt::MIN), arch_view.primary_row_id()), MaybeCachedComponentData::Raw(arch_view.iter_instance_keys().collect()), $(MaybeCachedComponentData::Raw(arch_view.iter_required_component::<$pov>()?.collect()),)+ @@ -168,11 +169,11 @@ macro_rules! impl_query_archetype { AnyQuery::LatestAt(query) if !cached => { re_tracing::profile_scope!("latest_at", format!("{query:?}")); - let arch_view = ::re_query::query_archetype::(store, query, entity_path)?; + let (data_time, arch_view) = ::re_query::query_archetype::(store, query, entity_path)?; let data = ( - // TODO(cmc): `ArchetypeView` should indicate its pov time. - (TimeInt::MIN, arch_view.primary_row_id()), + // TODO(cmc): actual timeless caching support. + (data_time.unwrap_or(TimeInt::MIN), arch_view.primary_row_id()), MaybeCachedComponentData::Raw(arch_view.iter_instance_keys().collect()), $(MaybeCachedComponentData::Raw(arch_view.iter_required_component::<$pov>()?.collect()),)+ $(MaybeCachedComponentData::Raw(arch_view.iter_optional_component::<$comp>()?.collect()),)* diff --git a/crates/re_query_cache/tests/latest_at.rs b/crates/re_query_cache/tests/latest_at.rs index 3fa32519f6c5d..1d3919029bbfb 100644 --- a/crates/re_query_cache/tests/latest_at.rs +++ b/crates/re_query_cache/tests/latest_at.rs @@ -230,7 +230,7 @@ fn query_and_compare(store: &DataStore, query: &LatestAtQuery, ent_path: &Entity ) .unwrap(); - let expected = re_query::query_archetype::(store, query, ent_path).unwrap(); + let (_, expected) = re_query::query_archetype::(store, query, ent_path).unwrap(); let expected_instance_keys = expected.iter_instance_keys().collect_vec(); let expected_positions = expected 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 9d63b46c86330..b96e7137ce61d 100644 --- a/crates/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/re_space_view_dataframe/src/space_view_class.rs @@ -162,7 +162,7 @@ impl SpaceViewClass for DataframeSpaceView { // TODO(#4466): make it explicit if that value results // from a splat joint. - if let Some((_, comp_inst)) = + if let Some((_, _, comp_inst)) = // This is a duplicate of the one above, but this ok since this codes runs // *only* for visible rows. get_component_with_instances( @@ -243,7 +243,7 @@ fn sorted_instance_paths_for<'a>( .filter(|comp| !comp.is_indicator_component()) .flat_map(|comp| { get_component_with_instances(store, latest_at_query, entity_path, comp) - .map(|(_, comp_inst)| comp_inst.instance_keys()) + .map(|(_, _, comp_inst)| comp_inst.instance_keys()) .unwrap_or_default() }) .filter(|instance_key| !instance_key.is_splat()) diff --git a/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs b/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs index 80c9686def34e..856c2772d1064 100644 --- a/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs +++ b/crates/re_space_view_spatial/src/visualizers/entity_iterator.rs @@ -80,10 +80,10 @@ where &data_result.accumulated_properties().visible_history, &data_result.entity_path, ) - .and_then(|entity_views| { - for ent_view in entity_views { + .and_then(|arch_views| { + for (_, arch_view) in arch_views { counter.num_primitives.fetch_add( - ent_view.num_instances(), + arch_view.num_instances(), std::sync::atomic::Ordering::Relaxed, ); @@ -91,7 +91,7 @@ where ctx, &data_result.entity_path, data_result.accumulated_properties(), - ent_view, + arch_view, &entity_context, )?; } diff --git a/crates/re_space_view_text_document/src/visualizer_system.rs b/crates/re_space_view_text_document/src/visualizer_system.rs index a9f5604509405..d48a99f7d056d 100644 --- a/crates/re_space_view_text_document/src/visualizer_system.rs +++ b/crates/re_space_view_text_document/src/visualizer_system.rs @@ -52,14 +52,13 @@ impl VisualizerSystem for TextDocumentSystem { let timeline_query = LatestAtQuery::new(query.timeline, query.latest_at); for data_result in query.iter_visible_data_results(Self::identifier()) { - // TODO(jleibs): this match can go away once we resolve: - // https://github.com/rerun-io/rerun/issues/3320 + // TODO(#3320): this match can go away once the issue is resolved match query_archetype::( store, &timeline_query, &data_result.entity_path, ) { - Ok(arch_view) => { + Ok((_, arch_view)) => { let bodies = arch_view.iter_required_component::()?; let media_types = arch_view.iter_optional_component::()?; diff --git a/crates/re_viewer_context/src/annotations.rs b/crates/re_viewer_context/src/annotations.rs index dadc5db45b765..f0985388ee67a 100644 --- a/crates/re_viewer_context/src/annotations.rs +++ b/crates/re_viewer_context/src/annotations.rs @@ -266,7 +266,7 @@ impl AnnotationMap { std::collections::btree_map::Entry::Vacant(entry) => { if query_archetype::(data_store, time_query, &parent) .ok() - .and_then(|view| Annotations::try_from_view(&view)) + .and_then(|(_, view)| Annotations::try_from_view(&view)) .map(|annotations| entry.insert(Arc::new(annotations))) .is_some() { diff --git a/crates/re_viewer_context/src/item.rs b/crates/re_viewer_context/src/item.rs index b749d74b92551..8e003e4053f20 100644 --- a/crates/re_viewer_context/src/item.rs +++ b/crates/re_viewer_context/src/item.rs @@ -147,7 +147,7 @@ pub fn resolve_mono_instance_path( return re_entity_db::InstancePath::entity_splat(instance.entity_path.clone()); }; for component in components { - if let Some((_row_id, instances)) = re_query::get_component_with_instances( + if let Some((_, _row_id, instances)) = re_query::get_component_with_instances( store, query, &instance.entity_path, diff --git a/crates/re_viewport/src/container.rs b/crates/re_viewport/src/container.rs index b9665724dcd25..d58e38d8dee71 100644 --- a/crates/re_viewport/src/container.rs +++ b/crates/re_viewport/src/container.rs @@ -120,7 +120,7 @@ impl ContainerBlueprint { visible, grid_columns, } = query_archetype(blueprint_db.store(), &query, &id.as_entity_path()) - .and_then(|arch| arch.to_archetype()) + .and_then(|(_, arch)| arch.to_archetype()) .map_err(|err| { if !matches!(err, re_query::QueryError::PrimaryNotFound(_)) { if cfg!(debug_assertions) { diff --git a/crates/re_viewport/src/space_view.rs b/crates/re_viewport/src/space_view.rs index f950a40dcd146..2f78f722b0f98 100644 --- a/crates/re_viewport/src/space_view.rs +++ b/crates/re_viewport/src/space_view.rs @@ -98,7 +98,7 @@ impl SpaceViewBlueprint { contents, visible, } = query_archetype(blueprint_db.store(), &query, &id.as_entity_path()) - .and_then(|arch| arch.to_archetype()) + .and_then(|(_, arch)| arch.to_archetype()) .map_err(|err| { if !matches!(err, re_query::QueryError::PrimaryNotFound(_)) { if cfg!(debug_assertions) { diff --git a/crates/re_viewport/src/viewport_blueprint.rs b/crates/re_viewport/src/viewport_blueprint.rs index 9dbb0c6fc7163..a5b3c36d4d50c 100644 --- a/crates/re_viewport/src/viewport_blueprint.rs +++ b/crates/re_viewport/src/viewport_blueprint.rs @@ -70,7 +70,7 @@ impl ViewportBlueprint { &query, &VIEWPORT_PATH.into(), ) - .and_then(|arch| arch.to_archetype()) + .and_then(|(_, arch)| arch.to_archetype()) { Ok(arch) => arch, Err(re_query::QueryError::PrimaryNotFound(_)) => { diff --git a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs index c7a6a1f43ea34..bea8ac59b3bad 100644 --- a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs +++ b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs @@ -61,7 +61,7 @@ impl VisualizerSystem for InstanceColorSystem { // For each entity in the space view that should be displayed with the `InstanceColorSystem`… for data_result in query.iter_visible_data_results(Self::identifier()) { // …gather all colors and their instance ids. - if let Ok(arch_view) = query_archetype::( + if let Ok((_, arch_view)) = query_archetype::( ctx.entity_db.store(), &ctx.current_query(), &data_result.entity_path, diff --git a/examples/rust/extend_viewer_ui/src/main.rs b/examples/rust/extend_viewer_ui/src/main.rs index 550fbcebda997..7bfae33b67b95 100644 --- a/examples/rust/extend_viewer_ui/src/main.rs +++ b/examples/rust/extend_viewer_ui/src/main.rs @@ -154,7 +154,7 @@ 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( + if let Some((_, _, component)) = re_query::get_component_with_instances( entity_db.store(), &query, entity_path,