use re_chunk_store::LatestAtQuery;
use re_entity_db::{external::re_query::LatestAtResults, EntityDb};
use re_log_types::EntityPath;
use re_types::{
external::arrow2, Archetype, ArchetypeName, ComponentBatch, ComponentName, DeserializationError,
};
use re_viewer_context::{
external::re_entity_db::EntityTree, ComponentFallbackError, ComponentFallbackProvider,
QueryContext, SpaceViewId, SpaceViewSystemExecutionError, ViewerContext,
};
#[derive(thiserror::Error, Debug)]
pub enum ViewPropertyQueryError {
#[error(transparent)]
SerializationError(#[from] re_types::DeserializationError),
#[error(transparent)]
ComponentFallbackError(#[from] ComponentFallbackError),
}
impl From<ViewPropertyQueryError> for SpaceViewSystemExecutionError {
fn from(val: ViewPropertyQueryError) -> Self {
match val {
ViewPropertyQueryError::SerializationError(err) => err.into(),
ViewPropertyQueryError::ComponentFallbackError(err) => err.into(),
}
}
}
pub struct ViewProperty {
pub blueprint_store_path: EntityPath,
archetype_name: ArchetypeName,
component_names: Vec<ComponentName>,
query_results: LatestAtResults,
blueprint_query: LatestAtQuery,
}
impl ViewProperty {
pub fn from_archetype<A: Archetype>(
blueprint_db: &EntityDb,
blueprint_query: &LatestAtQuery,
view_id: SpaceViewId,
) -> Self {
Self::from_archetype_impl(
blueprint_db,
blueprint_query.clone(),
view_id,
A::name(),
A::all_components().as_ref(),
)
}
fn from_archetype_impl(
blueprint_db: &EntityDb,
blueprint_query: LatestAtQuery,
space_view_id: SpaceViewId,
archetype_name: ArchetypeName,
component_names: &[ComponentName],
) -> Self {
let blueprint_store_path =
entity_path_for_view_property(space_view_id, blueprint_db.tree(), archetype_name);
let query_results = blueprint_db.latest_at(
&blueprint_query,
&blueprint_store_path,
component_names.iter().copied(),
);
Self {
blueprint_store_path,
archetype_name,
query_results,
component_names: component_names.to_vec(),
blueprint_query,
}
}
pub fn component_or_fallback<C: re_types::Component + Default>(
&self,
ctx: &ViewerContext<'_>,
fallback_provider: &dyn ComponentFallbackProvider,
view_state: &dyn re_viewer_context::SpaceViewState,
) -> Result<C, ViewPropertyQueryError> {
self.component_array_or_fallback::<C>(ctx, fallback_provider, view_state)?
.into_iter()
.next()
.ok_or(ComponentFallbackError::UnexpectedEmptyFallback.into())
}
pub fn component_array_or_fallback<C: re_types::Component + Default>(
&self,
ctx: &ViewerContext<'_>,
fallback_provider: &dyn ComponentFallbackProvider,
view_state: &dyn re_viewer_context::SpaceViewState,
) -> Result<Vec<C>, ViewPropertyQueryError> {
let component_name = C::name();
C::from_arrow(
self.component_or_fallback_raw(ctx, component_name, fallback_provider, view_state)
.as_ref(),
)
.map_err(|err| err.into())
}
#[inline]
pub fn component_or_empty<C: re_types::Component>(
&self,
) -> Result<Option<C>, DeserializationError> {
self.component_array()
.map(|v| v.and_then(|v| v.into_iter().next()))
}
pub fn component_array<C: re_types::Component>(
&self,
) -> Result<Option<Vec<C>>, DeserializationError> {
let component_name = C::name();
self.component_raw(component_name)
.map(|raw| C::from_arrow(raw.as_ref()))
.transpose()
}
pub fn component_array_or_empty<C: re_types::Component>(
&self,
) -> Result<Vec<C>, DeserializationError> {
self.component_array()
.map(|value| value.unwrap_or_default())
}
pub fn component_row_id(&self, component_name: ComponentName) -> Option<re_chunk::RowId> {
self.query_results
.get(&component_name)
.and_then(|unit| unit.row_id())
}
pub fn component_raw(
&self,
component_name: ComponentName,
) -> Option<Box<dyn arrow2::array::Array>> {
self.query_results
.get(&component_name)
.and_then(|unit| unit.component_batch_raw(&component_name))
}
fn component_or_fallback_raw(
&self,
ctx: &ViewerContext<'_>,
component_name: ComponentName,
fallback_provider: &dyn ComponentFallbackProvider,
view_state: &dyn re_viewer_context::SpaceViewState,
) -> Box<dyn arrow2::array::Array> {
if let Some(value) = self.component_raw(component_name) {
if value.len() > 0 {
return value;
}
}
fallback_provider.fallback_for(&self.query_context(ctx, view_state), component_name)
}
pub fn save_blueprint_component(
&self,
ctx: &ViewerContext<'_>,
components: &dyn ComponentBatch,
) {
ctx.save_blueprint_component(&self.blueprint_store_path, components);
}
pub fn clear_blueprint_component<C: re_types::Component>(&self, ctx: &ViewerContext<'_>) {
ctx.clear_blueprint_component_by_name(&self.blueprint_store_path, C::name());
}
pub fn reset_blueprint_component<C: re_types::Component>(&self, ctx: &ViewerContext<'_>) {
ctx.reset_blueprint_component_by_name(&self.blueprint_store_path, C::name());
}
pub fn reset_all_components(&self, ctx: &ViewerContext<'_>) {
for &component_name in &self.component_names {
ctx.reset_blueprint_component_by_name(&self.blueprint_store_path, component_name);
}
}
pub fn reset_all_components_to_empty(&self, ctx: &ViewerContext<'_>) {
for &component_name in self.query_results.components.keys() {
ctx.clear_blueprint_component_by_name(&self.blueprint_store_path, component_name);
}
}
pub fn any_non_empty(&self) -> bool {
self.query_results.components.keys().any(|name| {
self.component_raw(*name)
.map_or(false, |raw| !raw.is_empty())
})
}
pub fn query_context<'a>(
&'a self,
viewer_ctx: &'a ViewerContext<'_>,
view_state: &'a dyn re_viewer_context::SpaceViewState,
) -> QueryContext<'a> {
QueryContext {
viewer_ctx,
target_entity_path: &self.blueprint_store_path,
archetype_name: Some(self.archetype_name),
query: &self.blueprint_query,
view_state,
view_ctx: None,
}
}
}
pub fn entity_path_for_view_property(
space_view_id: SpaceViewId,
_blueprint_entity_tree: &EntityTree,
archetype_name: ArchetypeName,
) -> EntityPath {
let space_view_blueprint_path = space_view_id.as_entity_path();
space_view_blueprint_path.join(&EntityPath::from_single_string(archetype_name.short_name()))
}