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 71838d8acba5..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::{ @@ -251,6 +251,23 @@ fn preview_if_image_ui( entity_path: &re_log_types::EntityPath, component_map: &IntMap, ) -> Option<()> { + // First check assumptions: + 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()?; 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..238706096bb1 100644 --- a/crates/viewer/re_space_view_spatial/src/lib.rs +++ b/crates/viewer/re_space_view_spatial/src/lib.rs @@ -40,8 +40,12 @@ 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}, + static_assert_struct_has_fields, +}; use re_viewport_blueprint::{ViewProperty, ViewPropertyQueryError}; mod view_kind { @@ -57,6 +61,10 @@ fn resolution_of_image_at( query: &re_chunk_store::LatestAtQuery, entity_path: &re_log_types::EntityPath, ) -> Option { + // First check assumptions: + static_assert_struct_has_fields!(archetypes::Image, format: components::ImageFormat); + static_assert_struct_has_fields!(archetypes::EncodedImage, blob: components::Blob); + let db = ctx.recording(); if let Some((_, image_format)) = db.latest_at_component::(entity_path, query) {