use re_entity_db::EntityDb;
use re_types_core::reflection::ComponentReflectionMap;
pub fn is_valid_blueprint(
blueprint: &EntityDb,
component_reflection: &ComponentReflectionMap,
) -> bool {
re_tracing::profile_function!();
let engine = blueprint.storage_engine();
let mut mismatches = vec![];
for (entity_path, column) in engine.schema().all_column_metadata() {
let Some(component_type) = column.descriptor.component_type else {
continue;
};
let Some(reflection) = component_reflection.get(&component_type) else {
continue;
};
if column.datatype != reflection.datatype {
mismatches.push(format!(
" {} of {entity_path}: found {}, expected {}",
column.descriptor, column.datatype, reflection.datatype,
));
}
}
if mismatches.is_empty() {
true
} else {
mismatches.sort();
re_log::warn_once!(
"Blueprint has {} component(s) with unexpected datatypes:\n{}",
mismatches.len(),
mismatches.join("\n"),
);
false
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use arrow::array::{Float32Array, Float64Array};
use re_chunk::{Chunk, RowId};
use re_entity_db::EntityDb;
use re_log_types::{StoreId, TimePoint};
use re_sdk_types::{Loggable as _, archetypes::Points3D, components::Radius};
use super::is_valid_blueprint;
fn reflection() -> re_types_core::reflection::ComponentReflectionMap {
re_sdk_types::reflection::generate_reflection()
.expect("failed to generate reflection")
.components
}
fn blueprint_with_radius_columns(
arrays: impl IntoIterator<Item = arrow::array::ArrayRef>,
) -> EntityDb {
let mut blueprint = EntityDb::new(StoreId::random(
re_log_types::StoreKind::Blueprint,
"test_app",
));
for (i, array) in arrays.into_iter().enumerate() {
let chunk = Chunk::builder(format!("/view/some-view/overrides/entity-{i}").as_str())
.with_row(
RowId::new(),
TimePoint::default(),
[(Points3D::descriptor_radii(), array)],
)
.build()
.expect("failed to build chunk");
blueprint
.add_chunk(&Arc::new(chunk))
.expect("failed to add chunk");
}
blueprint
}
fn blueprint_with_radius_column(array: arrow::array::ArrayRef) -> EntityDb {
blueprint_with_radius_columns([array])
}
#[test]
fn empty_blueprint_is_valid() {
let component_reflection = reflection();
let blueprint = EntityDb::new(StoreId::random(
re_log_types::StoreKind::Blueprint,
"test_app",
));
assert!(is_valid_blueprint(&blueprint, &component_reflection));
}
#[test]
fn matching_datatype_is_valid() {
let component_reflection = reflection();
assert_eq!(
Radius::arrow_datatype(),
arrow::datatypes::DataType::Float32
);
let blueprint = blueprint_with_radius_column(Arc::new(Float32Array::from(vec![1.0])));
assert!(is_valid_blueprint(&blueprint, &component_reflection));
}
#[test]
fn mismatched_datatype_is_invalid() {
let component_reflection = reflection();
let blueprint = blueprint_with_radius_column(Arc::new(Float64Array::from(vec![1.0])));
assert!(!is_valid_blueprint(&blueprint, &component_reflection));
}
#[test]
fn mismatch_after_valid_column_is_invalid() {
let component_reflection = reflection();
let blueprint = blueprint_with_radius_columns([
Arc::new(Float32Array::from(vec![1.0])) as arrow::array::ArrayRef,
Arc::new(Float64Array::from(vec![1.0])),
]);
assert!(!is_valid_blueprint(&blueprint, &component_reflection));
}
#[test]
fn multiple_mismatches_are_invalid() {
let component_reflection = reflection();
let blueprint = blueprint_with_radius_columns([
Arc::new(Float64Array::from(vec![1.0])) as arrow::array::ArrayRef,
Arc::new(Float64Array::from(vec![2.0])),
]);
assert!(!is_valid_blueprint(&blueprint, &component_reflection));
}
}