From 7b778e5742a2e5c9e537e0e245f8ea0310622027 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 2 Sep 2024 11:46:08 +0200 Subject: [PATCH 1/2] Sanity-check that an archetype has a component --- crates/viewer/re_data_ui/src/instance_path.rs | 16 ++++++++++++++++ crates/viewer/re_space_view_spatial/src/lib.rs | 16 ++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/viewer/re_data_ui/src/instance_path.rs b/crates/viewer/re_data_ui/src/instance_path.rs index 71838d8acba5..3e8dd50020a6 100644 --- a/crates/viewer/re_data_ui/src/instance_path.rs +++ b/crates/viewer/re_data_ui/src/instance_path.rs @@ -251,6 +251,22 @@ fn preview_if_image_ui( entity_path: &re_log_types::EntityPath, component_map: &IntMap, ) -> Option<()> { + // First check assumptions: + fn _check_image_has_buffer_format(image: &archetypes::Image) { + let _: components::ImageBuffer = image.buffer; + let _: components::ImageFormat = image.format; + } + + fn _check_depth_image_has_buffer_format(image: &archetypes::DepthImage) { + let _: components::ImageBuffer = image.buffer; + let _: components::ImageFormat = image.format; + } + + fn _check_segmentation_image_has_buffer_format(image: &archetypes::SegmentationImage) { + let _: components::ImageBuffer = image.buffer; + let _: components::ImageFormat = image.format; + } + let image_buffer = component_map.get(&components::ImageBuffer::name())?; let buffer_row_id = image_buffer.row_id()?; let image_buffer = image_buffer diff --git a/crates/viewer/re_space_view_spatial/src/lib.rs b/crates/viewer/re_space_view_spatial/src/lib.rs index 5519348f8556..aab9852cd6ec 100644 --- a/crates/viewer/re_space_view_spatial/src/lib.rs +++ b/crates/viewer/re_space_view_spatial/src/lib.rs @@ -40,8 +40,11 @@ use re_space_view::DataResultQuery as _; use re_viewer_context::{ImageDecodeCache, ViewContext, ViewerContext}; use re_renderer::RenderContext; -use re_types::components::{Color, MediaType, Resolution}; -use re_types::{blueprint::components::BackgroundKind, components::ImageFormat}; +use re_types::{ + archetypes, + blueprint::components::BackgroundKind, + components::{self, Color, ImageFormat, MediaType, Resolution}, +}; use re_viewport_blueprint::{ViewProperty, ViewPropertyQueryError}; mod view_kind { @@ -57,6 +60,15 @@ fn resolution_of_image_at( query: &re_chunk_store::LatestAtQuery, entity_path: &re_log_types::EntityPath, ) -> Option { + // First check assumptions: + fn _check_image_has_format(image: &archetypes::Image) { + let _: components::ImageFormat = image.format; + } + + fn _check_encoded_image_has_blob(image: &archetypes::EncodedImage) { + let _: components::Blob = image.blob; + } + let db = ctx.recording(); if let Some((_, image_format)) = db.latest_at_component::(entity_path, query) { From 2c1d8d1c1ee6cbdfebae7244494b5446a458eeec Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 10 Sep 2024 13:21:28 +0200 Subject: [PATCH 2/2] Add macro `static_assert_struct_has_fields!` --- crates/store/re_types_core/src/lib.rs | 47 +++++++++++++++++++ crates/viewer/re_data_ui/src/instance_path.rs | 31 ++++++------ .../viewer/re_space_view_spatial/src/lib.rs | 10 ++-- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/crates/store/re_types_core/src/lib.rs b/crates/store/re_types_core/src/lib.rs index 443e0254d0a0..95230e3eb3db 100644 --- a/crates/store/re_types_core/src/lib.rs +++ b/crates/store/re_types_core/src/lib.rs @@ -144,3 +144,50 @@ pub mod external { pub use arrow2; pub use re_tuid; } + +/// Useful macro for staticlly asserting that a `struct` contains some specific fields. +/// +/// In particular, this is useful to statcially check that an archetype +/// has a specific component. +/// +/// ``` +/// # #[macro_use] extern crate re_types_core; +/// struct Data { +/// x: f32, +/// y: String, +/// z: u32, +/// } +/// +/// static_assert_struct_has_fields!(Data, x: f32, y: String); +/// ``` +/// +/// This will fail to compile because the type is wrong: +/// +/// ```compile_fail +/// # #[macro_use] extern crate re_types_core; +/// struct Data { +/// x: f32, +/// } +/// +/// static_assert_struct_has_fields!(Data, x: u32); +/// ``` +/// +/// This will fail to compile because the field is missing: +/// +/// ```compile_fail +/// # #[macro_use] extern crate re_types_core; +/// struct Data { +/// x: f32, +/// } +/// +/// static_assert_struct_has_fields!(Data, nosuch: f32); +/// ``` +/// +#[macro_export] +macro_rules! static_assert_struct_has_fields { + ($strct:ty, $($field:ident: $field_typ:ty),+) => { + const _: fn(&$strct) = |s: &$strct| { + $(let _: &$field_typ = &s.$field;)+ + }; + } +} diff --git a/crates/viewer/re_data_ui/src/instance_path.rs b/crates/viewer/re_data_ui/src/instance_path.rs index 3e8dd50020a6..6db689510b4e 100644 --- a/crates/viewer/re_data_ui/src/instance_path.rs +++ b/crates/viewer/re_data_ui/src/instance_path.rs @@ -7,7 +7,7 @@ use re_types::{ archetypes, components, datatypes::{ChannelDatatype, ColorModel}, image::ImageKind, - Archetype, ComponentName, Loggable, + static_assert_struct_has_fields, Archetype, ComponentName, Loggable, }; use re_ui::{ContextExt as _, UiExt as _}; use re_viewer_context::{ @@ -252,20 +252,21 @@ fn preview_if_image_ui( component_map: &IntMap, ) -> Option<()> { // First check assumptions: - fn _check_image_has_buffer_format(image: &archetypes::Image) { - let _: components::ImageBuffer = image.buffer; - let _: components::ImageFormat = image.format; - } - - fn _check_depth_image_has_buffer_format(image: &archetypes::DepthImage) { - let _: components::ImageBuffer = image.buffer; - let _: components::ImageFormat = image.format; - } - - fn _check_segmentation_image_has_buffer_format(image: &archetypes::SegmentationImage) { - let _: components::ImageBuffer = image.buffer; - let _: components::ImageFormat = image.format; - } + static_assert_struct_has_fields!( + archetypes::Image, + buffer: components::ImageBuffer, + format: components::ImageFormat + ); + static_assert_struct_has_fields!( + archetypes::DepthImage, + buffer: components::ImageBuffer, + format: components::ImageFormat + ); + static_assert_struct_has_fields!( + archetypes::SegmentationImage, + buffer: components::ImageBuffer, + format: components::ImageFormat + ); let image_buffer = component_map.get(&components::ImageBuffer::name())?; let buffer_row_id = image_buffer.row_id()?; diff --git a/crates/viewer/re_space_view_spatial/src/lib.rs b/crates/viewer/re_space_view_spatial/src/lib.rs index aab9852cd6ec..238706096bb1 100644 --- a/crates/viewer/re_space_view_spatial/src/lib.rs +++ b/crates/viewer/re_space_view_spatial/src/lib.rs @@ -44,6 +44,7 @@ use re_types::{ archetypes, blueprint::components::BackgroundKind, components::{self, Color, ImageFormat, MediaType, Resolution}, + static_assert_struct_has_fields, }; use re_viewport_blueprint::{ViewProperty, ViewPropertyQueryError}; @@ -61,13 +62,8 @@ fn resolution_of_image_at( entity_path: &re_log_types::EntityPath, ) -> Option { // First check assumptions: - fn _check_image_has_format(image: &archetypes::Image) { - let _: components::ImageFormat = image.format; - } - - fn _check_encoded_image_has_blob(image: &archetypes::EncodedImage) { - let _: components::Blob = image.blob; - } + static_assert_struct_has_fields!(archetypes::Image, format: components::ImageFormat); + static_assert_struct_has_fields!(archetypes::EncodedImage, blob: components::Blob); let db = ctx.recording();