Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

New data APIs 6: cached archetype queries #5673

Merged
merged 12 commits into from
Apr 8, 2024
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crates/re_data_ui/src/annotation_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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 => {
Expand Down
2 changes: 1 addition & 1 deletion crates/re_data_ui/src/app_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions crates/re_data_ui/src/blueprint_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ impl<T: BlueprintIdRegistry> DataUi for BlueprintId<T> {
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(),
Expand Down
132 changes: 63 additions & 69 deletions crates/re_data_ui/src/component.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
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};

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<CachedLatestAtComponentResults>,
}

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("<pending>");
return;
};

let one_line = match verbosity {
UiVerbosity::Small => true,
Expand Down Expand Up @@ -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`
Expand All @@ -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 {
Expand All @@ -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)
));
}
}
Expand Down
46 changes: 26 additions & 20 deletions crates/re_data_ui/src/component_path.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use re_log_types::ComponentPath;
use re_viewer_context::{UiVerbosity, ViewerContext};

Expand All @@ -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,
Expand All @@ -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("<unset>");
} 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("<unset>");
} 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}")),
);
}
}
}
32 changes: 17 additions & 15 deletions crates/re_data_ui/src/component_ui_registry.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -39,18 +39,13 @@ pub fn add_to_registry<C: EntityDataUi + re_types::Component>(registry: &mut Com
registry.add(
C::name(),
Box::new(
|ctx, ui, verbosity, query, store, entity_path, component, instance| match component
.lookup::<C>(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::<C>(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);
}
},
),
);
Expand All @@ -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)");
Expand Down
Loading
Loading