use ahash::HashMap;
use once_cell::sync::Lazy;
use slotmap::SlotMap;
use smallvec::SmallVec;
use re_log_types::{EntityPath, EntityPathHash};
use crate::{blueprint_timeline, DataResult, ViewContext, ViewId, ViewState, ViewerContext};
slotmap::new_key_type! {
pub struct DataResultHandle;
}
pub struct QueryContext<'a> {
pub viewer_ctx: &'a ViewerContext<'a>,
pub target_entity_path: &'a re_log_types::EntityPath,
pub archetype_name: Option<re_types::ArchetypeName>,
pub query: &'a re_chunk_store::LatestAtQuery,
pub view_state: &'a dyn ViewState,
pub view_ctx: Option<&'a ViewContext<'a>>,
}
impl QueryContext<'_> {
#[inline]
pub fn recording(&self) -> &re_entity_db::EntityDb {
self.viewer_ctx.recording()
}
}
pub struct DataQueryResult {
pub tree: DataResultTree,
pub num_matching_entities: usize,
pub num_visualized_entities: usize,
pub component_defaults: re_query::LatestAtResults,
}
impl Default for DataQueryResult {
fn default() -> Self {
Self {
tree: Default::default(),
num_matching_entities: 0,
num_visualized_entities: 0,
component_defaults: re_query::LatestAtResults {
entity_path: "<defaults>".into(),
query: re_chunk_store::LatestAtQuery::latest(blueprint_timeline()),
compound_index: (re_chunk::TimeInt::STATIC, re_chunk::RowId::ZERO),
components: Default::default(),
},
}
}
}
impl DataQueryResult {
#[inline]
pub fn is_empty(&self) -> bool {
self.tree.is_empty()
}
#[inline]
pub fn contains_entity(&self, path: &EntityPath) -> bool {
self.tree
.lookup_result_by_path(path)
.map_or(false, |result| !result.tree_prefix_only)
}
}
impl Clone for DataQueryResult {
fn clone(&self) -> Self {
re_tracing::profile_function!();
Self {
tree: self.tree.clone(),
num_matching_entities: self.num_matching_entities,
num_visualized_entities: self.num_visualized_entities,
component_defaults: self.component_defaults.clone(),
}
}
}
#[derive(Clone, Default)]
pub struct DataResultTree {
data_results: SlotMap<DataResultHandle, DataResultNode>,
data_results_by_path: HashMap<EntityPathHash, DataResultHandle>,
root_handle: Option<DataResultHandle>,
}
#[derive(Clone, Debug)]
pub struct DataResultNode {
pub data_result: DataResult,
pub children: SmallVec<[DataResultHandle; 4]>,
}
impl DataResultTree {
pub fn new(
data_results: SlotMap<DataResultHandle, DataResultNode>,
root_handle: Option<DataResultHandle>,
) -> Self {
re_tracing::profile_function!();
let data_results_by_path = data_results
.iter()
.map(|(handle, node)| (node.data_result.entity_path.hash(), handle))
.collect();
Self {
data_results,
data_results_by_path,
root_handle,
}
}
pub fn root_handle(&self) -> Option<DataResultHandle> {
self.root_handle
}
pub fn root_node(&self) -> Option<&DataResultNode> {
self.root_handle
.and_then(|handle| self.data_results.get(handle))
}
pub fn visit<'a>(&'a self, visitor: &mut impl FnMut(&'a DataResultNode) -> bool) {
if let Some(root_handle) = self.root_handle {
self.visit_recursive(root_handle, visitor);
}
}
#[inline]
pub fn lookup_result(&self, handle: DataResultHandle) -> Option<&DataResult> {
self.data_results.get(handle).map(|node| &node.data_result)
}
#[inline]
pub fn lookup_node(&self, handle: DataResultHandle) -> Option<&DataResultNode> {
self.data_results.get(handle)
}
#[inline]
pub fn lookup_node_mut(&mut self, handle: DataResultHandle) -> Option<&mut DataResultNode> {
self.data_results.get_mut(handle)
}
#[inline]
pub fn lookup_node_by_path(&self, path: &EntityPath) -> Option<&DataResultNode> {
self.data_results_by_path
.get(&path.hash())
.and_then(|handle| self.lookup_node(*handle))
}
#[inline]
pub fn lookup_result_by_path(&self, path: &EntityPath) -> Option<&DataResult> {
self.data_results_by_path
.get(&path.hash())
.and_then(|handle| self.lookup_result(*handle))
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data_results_by_path.is_empty()
}
fn visit_recursive<'a>(
&'a self,
handle: DataResultHandle,
visitor: &mut impl FnMut(&'a DataResultNode) -> bool,
) {
if let Some(result) = self.data_results.get(handle) {
if visitor(result) {
for child in &result.children {
self.visit_recursive(*child, visitor);
}
}
}
}
}
static EMPTY_QUERY: Lazy<DataQueryResult> = Lazy::<DataQueryResult>::new(Default::default);
impl ViewerContext<'_> {
pub fn lookup_query_result(&self, id: ViewId) -> &DataQueryResult {
self.query_results.get(&id).unwrap_or_else(|| {
if cfg!(debug_assertions) {
re_log::warn!("Tried looking up a query that doesn't exist: {:?}", id);
} else {
re_log::debug!("Tried looking up a query that doesn't exist: {:?}", id);
}
&EMPTY_QUERY
})
}
}