From 236599f71fec84cd41079733681bb07ab90b5569 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 4 Mar 2024 14:21:50 +0100 Subject: [PATCH] `Uuid` & `IncludedSpaceView` types are now serializable in python (#5372) ### What * part of #4167 Steps towards serializable `ViewportBlueprint`. Adjusted structure a bit: it used to be `IncludedSpaceViews` (plural) it's now `IncludedSpaceView` (singular) and we store a component array on the `ViewportBlueprint archetype. Also, uuid needed some extra love on codegen as well. ### Checklist * [x] I have read and agree to [Contributor Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and the [Code of Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md) * [x] I've included a screenshot or gif (if applicable) * [x] I have tested the web demo (if applicable): * Using newly built examples: [app.rerun.io](https://app.rerun.io/pr/5372/index.html) * Using examples from latest `main` build: [app.rerun.io](https://app.rerun.io/pr/5372/index.html?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [app.rerun.io](https://app.rerun.io/pr/5372/index.html?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [x] The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG * [x] If applicable, add a new check to the [release checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)! - [PR Build Summary](https://build.rerun.io/pr/5372) - [Docs preview](https://rerun.io/preview/67d77ed6fb8d0bcfa952dc6c3d300b713eb6ef77/docs) - [Examples preview](https://rerun.io/preview/67d77ed6fb8d0bcfa952dc6c3d300b713eb6ef77/examples) - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) --- Cargo.lock | 2 + .../re_types/definitions/rerun/blueprint.fbs | 2 +- .../archetypes/viewport_blueprint.fbs | 2 +- ...pace_views.fbs => included_space_view.fbs} | 5 +- .../definitions/rerun/datatypes/uuid.fbs | 6 +- .../blueprint/components/included_queries.rs | 115 ++++++- crates/re_types/src/datatypes/uuid.rs | 247 ++++++--------- .../src/blueprint/validation_gen/mod.rs | 4 +- .../src/blueprint_helpers.rs | 56 +++- crates/re_viewport/Cargo.toml | 2 + .../archetypes/viewport_blueprint.rs | 27 +- .../src/blueprint/components/.gitattributes | 2 +- .../components/included_space_view.rs | 286 ++++++++++++++++++ .../components/included_space_views.rs | 195 ------------ .../src/blueprint/components/mod.rs | 4 +- .../blueprint/components/root_container.rs | 177 +++++++++-- .../components/space_view_maximized.rs | 126 ++++++-- crates/re_viewport/src/blueprint/data_ui.rs | 22 +- crates/re_viewport/src/viewport_blueprint.rs | 33 +- examples/python/raw_mesh/main.py | 4 +- .../archetypes/viewport_blueprint.hpp | 10 +- rerun_cpp/src/rerun/blueprint/components.hpp | 2 +- .../rerun/blueprint/components/.gitattributes | 4 +- .../blueprint/components/included_queries.cpp | 2 +- .../components/included_space_view.cpp | 58 ++++ ...pace_views.hpp => included_space_view.hpp} | 45 +-- .../components/included_space_views.cpp | 77 ----- .../blueprint/components/root_container.cpp | 4 +- .../blueprint/components/root_container.hpp | 6 +- .../components/space_view_maximized.cpp | 6 +- .../components/space_view_maximized.hpp | 4 +- rerun_cpp/src/rerun/datatypes/uuid.cpp | 34 +-- rerun_cpp/src/rerun/datatypes/uuid.hpp | 5 +- rerun_py/rerun_sdk/rerun/_converters.py | 7 +- rerun_py/rerun_sdk/rerun/_validators.py | 5 + .../archetypes/viewport_blueprint.py | 6 +- .../rerun/blueprint/components/.gitattributes | 2 +- .../rerun/blueprint/components/__init__.py | 16 +- .../blueprint/components/included_queries.py | 11 +- .../components/included_space_view.py | 32 ++ .../components/included_space_views.py | 81 ----- rerun_py/rerun_sdk/rerun/datatypes/uuid.py | 29 +- .../rerun_sdk/rerun/datatypes/uuid_ext.py | 33 ++ rerun_py/tests/unit/common_arrays.py | 21 ++ rerun_py/tests/unit/test_uuid.py | 27 ++ .../tests/unit/test_viewport_blueprint.py | 56 ++++ 46 files changed, 1174 insertions(+), 726 deletions(-) rename crates/re_types/definitions/rerun/blueprint/components/{included_space_views.fbs => included_space_view.fbs} (73%) create mode 100644 crates/re_viewport/src/blueprint/components/included_space_view.rs delete mode 100644 crates/re_viewport/src/blueprint/components/included_space_views.rs create mode 100644 rerun_cpp/src/rerun/blueprint/components/included_space_view.cpp rename rerun_cpp/src/rerun/blueprint/components/{included_space_views.hpp => included_space_view.hpp} (51%) delete mode 100644 rerun_cpp/src/rerun/blueprint/components/included_space_views.cpp create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/included_space_view.py delete mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/included_space_views.py create mode 100644 rerun_py/rerun_sdk/rerun/datatypes/uuid_ext.py create mode 100644 rerun_py/tests/unit/test_uuid.py create mode 100644 rerun_py/tests/unit/test_viewport_blueprint.py diff --git a/Cargo.lock b/Cargo.lock index f4c9671ddb3b..aa805f63be02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5117,6 +5117,8 @@ name = "re_viewport" version = "0.15.0-alpha.1+dev" dependencies = [ "ahash", + "array-init", + "bytemuck", "egui", "egui_tiles", "glam", diff --git a/crates/re_types/definitions/rerun/blueprint.fbs b/crates/re_types/definitions/rerun/blueprint.fbs index c69f03ab755c..1c0fbe702f35 100644 --- a/crates/re_types/definitions/rerun/blueprint.fbs +++ b/crates/re_types/definitions/rerun/blueprint.fbs @@ -8,7 +8,7 @@ include "./blueprint/components/entity_properties_component.fbs"; include "./blueprint/components/grid_columns.fbs"; include "./blueprint/components/included_contents.fbs"; include "./blueprint/components/included_queries.fbs"; -include "./blueprint/components/included_space_views.fbs"; +include "./blueprint/components/included_space_view.fbs"; include "./blueprint/components/panel_view.fbs"; include "./blueprint/components/query_expressions.fbs"; include "./blueprint/components/root_container.fbs"; diff --git a/crates/re_types/definitions/rerun/blueprint/archetypes/viewport_blueprint.fbs b/crates/re_types/definitions/rerun/blueprint/archetypes/viewport_blueprint.fbs index 11533f6b79b6..a6fa133e8276 100644 --- a/crates/re_types/definitions/rerun/blueprint/archetypes/viewport_blueprint.fbs +++ b/crates/re_types/definitions/rerun/blueprint/archetypes/viewport_blueprint.fbs @@ -16,7 +16,7 @@ table ViewportBlueprint ( // --- Required --- /// All of the space-views that belong to the viewport. - space_views: rerun.blueprint.components.IncludedSpaceViews ("attr.rerun.component_required", order: 1000); + space_views: [rerun.blueprint.components.IncludedSpaceView] ("attr.rerun.component_required", order: 1000); // --- Optional --- diff --git a/crates/re_types/definitions/rerun/blueprint/components/included_space_views.fbs b/crates/re_types/definitions/rerun/blueprint/components/included_space_view.fbs similarity index 73% rename from crates/re_types/definitions/rerun/blueprint/components/included_space_views.fbs rename to crates/re_types/definitions/rerun/blueprint/components/included_space_view.fbs index c9886698d8ff..1807c7ba44d8 100644 --- a/crates/re_types/definitions/rerun/blueprint/components/included_space_views.fbs +++ b/crates/re_types/definitions/rerun/blueprint/components/included_space_view.fbs @@ -13,11 +13,12 @@ namespace rerun.blueprint.components; /// The id of a `SpaceView`. /// /// Unstable. Used for the ongoing blueprint experimentations. -table IncludedSpaceViews ( +table IncludedSpaceView ( "attr.rerun.scope": "blueprint", + "attr.python.aliases": "npt.NDArray[np.uint8], npt.ArrayLike, Sequence[int], bytes", "attr.rust.derive": "Default", "attr.rust.override_crate": "re_viewport", "attr.rust.repr": "transparent" ) { - space_view_ids: [rerun.datatypes.Uuid] (order: 100); + space_view_ids: rerun.datatypes.Uuid (order: 100); } diff --git a/crates/re_types/definitions/rerun/datatypes/uuid.fbs b/crates/re_types/definitions/rerun/datatypes/uuid.fbs index f8cf00731a9d..f25b942795f3 100644 --- a/crates/re_types/definitions/rerun/datatypes/uuid.fbs +++ b/crates/re_types/definitions/rerun/datatypes/uuid.fbs @@ -12,9 +12,9 @@ namespace rerun.datatypes; /// A 16-byte uuid. struct Uuid ( - // TODO(jleibs): Figure out why we can't make this transparent. - // The deserializer barfs on list of fixed-sized-list. - //"attr.arrow.transparent", + "attr.arrow.transparent", + "attr.python.aliases": "npt.NDArray[Any], npt.ArrayLike, Sequence[int], bytes", + "attr.python.array_aliases": "npt.NDArray[Any], npt.ArrayLike, Sequence[Sequence[int]], Sequence[int], Sequence[bytes]", "attr.rust.derive": "Default, Copy, PartialEq, Eq", "attr.rust.repr": "transparent" ) { diff --git a/crates/re_types/src/blueprint/components/included_queries.rs b/crates/re_types/src/blueprint/components/included_queries.rs index 3de1ed289104..7896bd59494e 100644 --- a/crates/re_types/src/blueprint/components/included_queries.rs +++ b/crates/re_types/src/blueprint/components/included_queries.rs @@ -113,8 +113,46 @@ impl ::re_types_core::Loggable for IncludedQueries { Self::arrow_datatype(), offsets, { - _ = data0_inner_bitmap; - crate::datatypes::Uuid::to_arrow_opt(data0_inner_data)? + use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; + let data0_inner_data_inner_data: Vec<_> = data0_inner_data + .iter() + .map(|datum| { + datum + .map(|datum| { + let crate::datatypes::Uuid { bytes } = datum; + bytes + }) + .unwrap_or_default() + }) + .flatten() + .map(Some) + .collect(); + let data0_inner_data_inner_bitmap: Option = + data0_inner_bitmap.as_ref().map(|bitmap| { + bitmap + .iter() + .map(|i| std::iter::repeat(i).take(16usize)) + .flatten() + .collect::>() + .into() + }); + FixedSizeListArray::new( + DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ), + PrimitiveArray::new( + DataType::UInt8, + data0_inner_data_inner_data + .into_iter() + .map(|v| v.unwrap_or_default()) + .collect(), + data0_inner_data_inner_bitmap, + ) + .boxed(), + data0_inner_bitmap, + ) + .boxed() }, data0_bitmap, ) @@ -147,10 +185,77 @@ impl ::re_types_core::Loggable for IncludedQueries { } else { let arrow_data_inner = { let arrow_data_inner = &**arrow_data.values(); - crate::datatypes::Uuid::from_arrow_opt(arrow_data_inner) - .with_context("rerun.blueprint.components.IncludedQueries#query_ids")? + { + let arrow_data_inner = arrow_data_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ); + let actual = arrow_data_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.IncludedQueries#query_ids")?; + if arrow_data_inner.is_empty() { + Vec::new() + } else { + let offsets = (0..) + .step_by(16usize) + .zip((16usize..).step_by(16usize).take(arrow_data_inner.len())); + let arrow_data_inner_inner = { + let arrow_data_inner_inner = &**arrow_data_inner.values(); + arrow_data_inner_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::UInt8; + let actual = arrow_data_inner_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context( + "rerun.blueprint.components.IncludedQueries#query_ids", + )? + .into_iter() + .map(|opt| opt.copied()) + .collect::>() + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets, + arrow_data_inner.validity(), + ) + .map(|elem| { + elem.map(|(start, end)| { + debug_assert!(end - start == 16usize); + if end as usize > arrow_data_inner_inner.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_inner_inner.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = unsafe { + arrow_data_inner_inner + .get_unchecked(start as usize..end as usize) + }; + let data = data.iter().cloned().map(Option::unwrap_or_default); + let arr = array_init::from_iter(data).unwrap(); + Ok(arr) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt.map(|res_or_opt| { + res_or_opt.map(|bytes| crate::datatypes::Uuid { bytes }) + }) + }) + .collect::>>>()? + } .into_iter() - .collect::>() + } + .collect::>() }; let offsets = arrow_data.offsets(); arrow2::bitmap::utils::ZipValidity::new_with_validity( diff --git a/crates/re_types/src/datatypes/uuid.rs b/crates/re_types/src/datatypes/uuid.rs index e4a490c54d6e..c1b5f73d085c 100644 --- a/crates/re_types/src/datatypes/uuid.rs +++ b/crates/re_types/src/datatypes/uuid.rs @@ -68,14 +68,10 @@ impl ::re_types_core::Loggable for Uuid { #[inline] fn arrow_datatype() -> arrow2::datatypes::DataType { use arrow2::datatypes::*; - DataType::Struct(std::sync::Arc::new(vec![Field::new( - "bytes", - DataType::FixedSizeList( - std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), - 16usize, - ), - false, - )])) + DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ) } #[allow(clippy::wildcard_imports)] @@ -88,77 +84,57 @@ impl ::re_types_core::Loggable for Uuid { use ::re_types_core::{Loggable as _, ResultExt as _}; use arrow2::{array::*, datatypes::*}; Ok({ - let (somes, data): (Vec<_>, Vec<_>) = data + let (somes, bytes): (Vec<_>, Vec<_>) = data .into_iter() .map(|datum| { let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + let datum = datum.map(|datum| { + let Self { bytes } = datum.into_owned(); + bytes + }); (datum.is_some(), datum) }) .unzip(); - let bitmap: Option = { + let bytes_bitmap: Option = { let any_nones = somes.iter().any(|some| !*some); any_nones.then(|| somes.into()) }; - StructArray::new( - ::arrow_datatype(), - vec![{ - let (somes, bytes): (Vec<_>, Vec<_>) = data - .iter() - .map(|datum| { - let datum = datum.as_ref().map(|datum| { - let Self { bytes, .. } = &**datum; - bytes.clone() - }); - (datum.is_some(), datum) - }) - .unzip(); - let bytes_bitmap: Option = { - let any_nones = somes.iter().any(|some| !*some); - any_nones.then(|| somes.into()) - }; - { - use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; - let bytes_inner_data: Vec<_> = bytes + { + use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; + let bytes_inner_data: Vec<_> = bytes + .iter() + .flat_map(|v| match v { + Some(v) => itertools::Either::Left(v.iter().cloned()), + None => itertools::Either::Right( + std::iter::repeat(Default::default()).take(16usize), + ), + }) + .map(Some) + .collect(); + let bytes_inner_bitmap: Option = + bytes_bitmap.as_ref().map(|bitmap| { + bitmap .iter() - .flat_map(|v| match v { - Some(v) => itertools::Either::Left(v.iter().cloned()), - None => itertools::Either::Right( - std::iter::repeat(Default::default()).take(16usize), - ), - }) - .map(Some) - .collect(); - let bytes_inner_bitmap: Option = - bytes_bitmap.as_ref().map(|bitmap| { - bitmap - .iter() - .map(|i| std::iter::repeat(i).take(16usize)) - .flatten() - .collect::>() - .into() - }); - FixedSizeListArray::new( - DataType::FixedSizeList( - std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), - 16usize, - ), - PrimitiveArray::new( - DataType::UInt8, - bytes_inner_data - .into_iter() - .map(|v| v.unwrap_or_default()) - .collect(), - bytes_inner_bitmap, - ) - .boxed(), - bytes_bitmap, - ) - .boxed() - } - }], - bitmap, - ) - .boxed() + .map(|i| std::iter::repeat(i).take(16usize)) + .flatten() + .collect::>() + .into() + }); + FixedSizeListArray::new( + Self::arrow_datatype(), + PrimitiveArray::new( + DataType::UInt8, + bytes_inner_data + .into_iter() + .map(|v| v.unwrap_or_default()) + .collect(), + bytes_inner_bitmap, + ) + .boxed(), + bytes_bitmap, + ) + .boxed() + } }) } @@ -174,112 +150,65 @@ impl ::re_types_core::Loggable for Uuid { Ok({ let arrow_data = arrow_data .as_any() - .downcast_ref::() + .downcast_ref::() .ok_or_else(|| { let expected = Self::arrow_datatype(); let actual = arrow_data.data_type().clone(); DeserializationError::datatype_mismatch(expected, actual) }) - .with_context("rerun.datatypes.Uuid")?; + .with_context("rerun.datatypes.Uuid#bytes")?; if arrow_data.is_empty() { Vec::new() } else { - let (arrow_data_fields, arrow_data_arrays) = - (arrow_data.fields(), arrow_data.values()); - let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data_fields - .iter() - .map(|field| field.name.as_str()) - .zip(arrow_data_arrays) - .collect(); - let bytes = { - if !arrays_by_name.contains_key("bytes") { - return Err(DeserializationError::missing_struct_field( - Self::arrow_datatype(), - "bytes", - )) - .with_context("rerun.datatypes.Uuid"); - } - let arrow_data = &**arrays_by_name["bytes"]; - { - let arrow_data = arrow_data - .as_any() - .downcast_ref::() - .ok_or_else(|| { - let expected = DataType::FixedSizeList( - std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), - 16usize, - ); - let actual = arrow_data.data_type().clone(); - DeserializationError::datatype_mismatch(expected, actual) - }) - .with_context("rerun.datatypes.Uuid#bytes")?; - if arrow_data.is_empty() { - Vec::new() - } else { - let offsets = (0..) - .step_by(16usize) - .zip((16usize..).step_by(16usize).take(arrow_data.len())); - let arrow_data_inner = { - let arrow_data_inner = &**arrow_data.values(); - arrow_data_inner - .as_any() - .downcast_ref::() - .ok_or_else(|| { - let expected = DataType::UInt8; - let actual = arrow_data_inner.data_type().clone(); - DeserializationError::datatype_mismatch(expected, actual) - }) - .with_context("rerun.datatypes.Uuid#bytes")? - .into_iter() - .map(|opt| opt.copied()) - .collect::>() - }; - arrow2::bitmap::utils::ZipValidity::new_with_validity( - offsets, - arrow_data.validity(), - ) - .map(|elem| { - elem.map(|(start, end)| { - debug_assert!(end - start == 16usize); - if end as usize > arrow_data_inner.len() { - return Err(DeserializationError::offset_slice_oob( - (start, end), - arrow_data_inner.len(), - )); - } - - #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] - let data = unsafe { - arrow_data_inner.get_unchecked(start as usize..end as usize) - }; - let data = data.iter().cloned().map(Option::unwrap_or_default); - let arr = array_init::from_iter(data).unwrap(); - Ok(arr) - }) - .transpose() - }) - .collect::>>>()? - } + let offsets = (0..) + .step_by(16usize) + .zip((16usize..).step_by(16usize).take(arrow_data.len())); + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + arrow_data_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::UInt8; + let actual = arrow_data_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.datatypes.Uuid#bytes")? .into_iter() - } + .map(|opt| opt.copied()) + .collect::>() }; arrow2::bitmap::utils::ZipValidity::new_with_validity( - ::itertools::izip!(bytes), + offsets, arrow_data.validity(), ) - .map(|opt| { - opt.map(|(bytes)| { - Ok(Self { - bytes: bytes - .ok_or_else(DeserializationError::missing_data) - .with_context("rerun.datatypes.Uuid#bytes")?, - }) + .map(|elem| { + elem.map(|(start, end)| { + debug_assert!(end - start == 16usize); + if end as usize > arrow_data_inner.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_inner.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_inner.get_unchecked(start as usize..end as usize) }; + let data = data.iter().cloned().map(Option::unwrap_or_default); + let arr = array_init::from_iter(data).unwrap(); + Ok(arr) }) .transpose() }) - .collect::>>() - .with_context("rerun.datatypes.Uuid")? + .collect::>>>()? } - }) + .into_iter() + } + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .map(|res| res.map(|bytes| Some(Self { bytes }))) + .collect::>>>() + .with_context("rerun.datatypes.Uuid#bytes") + .with_context("rerun.datatypes.Uuid")?) } } diff --git a/crates/re_viewer/src/blueprint/validation_gen/mod.rs b/crates/re_viewer/src/blueprint/validation_gen/mod.rs index cc2e87a9a9f0..4b4e5f6562b7 100644 --- a/crates/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/re_viewer/src/blueprint/validation_gen/mod.rs @@ -19,7 +19,7 @@ pub use re_viewport::blueprint::components::AutoLayout; pub use re_viewport::blueprint::components::AutoSpaceViews; pub use re_viewport::blueprint::components::ContainerKind; pub use re_viewport::blueprint::components::GridColumns; -pub use re_viewport::blueprint::components::IncludedSpaceViews; +pub use re_viewport::blueprint::components::IncludedSpaceView; pub use re_viewport::blueprint::components::RootContainer; pub use re_viewport::blueprint::components::SpaceViewMaximized; pub use re_viewport::blueprint::components::ViewportLayout; @@ -39,7 +39,7 @@ pub fn is_valid_blueprint(blueprint: &EntityDb) -> bool { && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) - && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) diff --git a/crates/re_viewer_context/src/blueprint_helpers.rs b/crates/re_viewer_context/src/blueprint_helpers.rs index 9bebf295c6e6..72fafcd10da9 100644 --- a/crates/re_viewer_context/src/blueprint_helpers.rs +++ b/crates/re_viewer_context/src/blueprint_helpers.rs @@ -24,21 +24,55 @@ impl ViewerContext<'_> { C: re_types::Component + Clone + 'a, std::borrow::Cow<'a, C>: std::convert::From, { + self.save_blueprint_component_data_cell(entity_path, [component].into(), 1); + } + + /// Helper to save an iterator of components to the blueprint store. + pub fn save_blueprint_component_iter<'a, C>( + &self, + entity_path: &EntityPath, + components: impl Iterator, + ) where + C: re_types::Component + Clone + 'a, + std::borrow::Cow<'a, C>: std::convert::From, + { + let components = components.collect::>(); + let num_instances = components.len() as u32; + self.save_blueprint_component_data_cell(entity_path, components.into(), num_instances); + } + + fn save_blueprint_component_data_cell( + &self, + entity_path: &EntityPath, + mut data_cell: DataCell, + num_instances: u32, + ) { let timepoint = blueprint_timepoint_for_writes(); - let mut splat_cell: DataCell = [InstanceKey::SPLAT].into(); - splat_cell.compute_size_bytes(); + data_cell.compute_size_bytes(); - let mut component: DataCell = [component].into(); - component.compute_size_bytes(); + let data_row_result = if num_instances == 1 { + let mut splat_cell: DataCell = [InstanceKey::SPLAT].into(); + splat_cell.compute_size_bytes(); - match DataRow::from_cells( - RowId::new(), - timepoint.clone(), - entity_path.clone(), - 1, - [splat_cell, component], - ) { + DataRow::from_cells( + RowId::new(), + timepoint.clone(), + entity_path.clone(), + num_instances, + [splat_cell, data_cell], + ) + } else { + DataRow::from_cells( + RowId::new(), + timepoint.clone(), + entity_path.clone(), + num_instances, + [data_cell], + ) + }; + + match data_row_result { Ok(row) => self .command_sender .send_system(SystemCommand::UpdateBlueprint( diff --git a/crates/re_viewport/Cargo.toml b/crates/re_viewport/Cargo.toml index f3e92ab48858..a43d9e6a5787 100644 --- a/crates/re_viewport/Cargo.toml +++ b/crates/re_viewport/Cargo.toml @@ -37,7 +37,9 @@ re_ui.workspace = true re_viewer_context.workspace = true ahash.workspace = true +array-init.workspace = true arrow2.workspace = true +bytemuck.workspace = true egui_tiles.workspace = true egui.workspace = true glam.workspace = true diff --git a/crates/re_viewport/src/blueprint/archetypes/viewport_blueprint.rs b/crates/re_viewport/src/blueprint/archetypes/viewport_blueprint.rs index 7ae63cee2324..33e2e7ee7727 100644 --- a/crates/re_viewport/src/blueprint/archetypes/viewport_blueprint.rs +++ b/crates/re_viewport/src/blueprint/archetypes/viewport_blueprint.rs @@ -25,7 +25,7 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; #[derive(Clone, Debug, Default)] pub struct ViewportBlueprint { /// All of the space-views that belong to the viewport. - pub space_views: crate::blueprint::components::IncludedSpaceViews, + pub space_views: Vec, /// The layout of the space-views pub layout: Option, @@ -58,7 +58,7 @@ impl ::re_types_core::SizeBytes for ViewportBlueprint { #[inline] fn is_pod() -> bool { - ::is_pod() + >::is_pod() && >::is_pod() && >::is_pod() && >::is_pod() @@ -68,7 +68,7 @@ impl ::re_types_core::SizeBytes for ViewportBlueprint { } static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = - once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.IncludedSpaceViews".into()]); + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.IncludedSpaceView".into()]); static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.ViewportBlueprintIndicator".into()]); @@ -88,7 +88,7 @@ static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 6usize]> = static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 8usize]> = once_cell::sync::Lazy::new(|| { [ - "rerun.blueprint.components.IncludedSpaceViews".into(), + "rerun.blueprint.components.IncludedSpaceView".into(), "rerun.blueprint.components.ViewportBlueprintIndicator".into(), "rerun.blueprint.components.AutoLayout".into(), "rerun.blueprint.components.AutoSpaceViews".into(), @@ -152,15 +152,14 @@ impl ::re_types_core::Archetype for ViewportBlueprint { .collect(); let space_views = { let array = arrays_by_name - .get("rerun.blueprint.components.IncludedSpaceViews") + .get("rerun.blueprint.components.IncludedSpaceView") .ok_or_else(DeserializationError::missing_data) .with_context("rerun.blueprint.archetypes.ViewportBlueprint#space_views")?; - ::from_arrow_opt(&**array) + ::from_arrow_opt(&**array) .with_context("rerun.blueprint.archetypes.ViewportBlueprint#space_views")? .into_iter() - .next() - .flatten() - .ok_or_else(DeserializationError::missing_data) + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .collect::>>() .with_context("rerun.blueprint.archetypes.ViewportBlueprint#space_views")? }; let layout = @@ -255,14 +254,18 @@ impl ::re_types_core::AsComponents for ViewportBlueprint { #[inline] fn num_instances(&self) -> usize { - 1 + self.space_views.len() } } impl ViewportBlueprint { - pub fn new(space_views: impl Into) -> Self { + pub fn new( + space_views: impl IntoIterator< + Item = impl Into, + >, + ) -> Self { Self { - space_views: space_views.into(), + space_views: space_views.into_iter().map(Into::into).collect(), layout: None, root_container: None, maximized: None, diff --git a/crates/re_viewport/src/blueprint/components/.gitattributes b/crates/re_viewport/src/blueprint/components/.gitattributes index 7bf34b1171a9..94acd9b40f79 100644 --- a/crates/re_viewport/src/blueprint/components/.gitattributes +++ b/crates/re_viewport/src/blueprint/components/.gitattributes @@ -5,7 +5,7 @@ auto_layout.rs linguist-generated=true auto_space_views.rs linguist-generated=true container_kind.rs linguist-generated=true grid_columns.rs linguist-generated=true -included_space_views.rs linguist-generated=true +included_space_view.rs linguist-generated=true mod.rs linguist-generated=true root_container.rs linguist-generated=true space_view_maximized.rs linguist-generated=true diff --git a/crates/re_viewport/src/blueprint/components/included_space_view.rs b/crates/re_viewport/src/blueprint/components/included_space_view.rs new file mode 100644 index 000000000000..13044575f9b2 --- /dev/null +++ b/crates/re_viewport/src/blueprint/components/included_space_view.rs @@ -0,0 +1,286 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_view.fbs". + +#![allow(trivial_numeric_casts)] +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::iter_on_single_items)] +#![allow(clippy::map_flatten)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] +#![allow(clippy::unnecessary_cast)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: The id of a `SpaceView`. +/// +/// Unstable. Used for the ongoing blueprint experimentations. +#[derive(Clone, Debug, Default)] +#[repr(transparent)] +pub struct IncludedSpaceView(pub crate::datatypes::Uuid); + +impl ::re_types_core::SizeBytes for IncludedSpaceView { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +impl> From for IncludedSpaceView { + fn from(v: T) -> Self { + Self(v.into()) + } +} + +impl std::borrow::Borrow for IncludedSpaceView { + #[inline] + fn borrow(&self) -> &crate::datatypes::Uuid { + &self.0 + } +} + +impl std::ops::Deref for IncludedSpaceView { + type Target = crate::datatypes::Uuid; + + #[inline] + fn deref(&self) -> &crate::datatypes::Uuid { + &self.0 + } +} + +::re_types_core::macros::impl_into_cow!(IncludedSpaceView); + +impl ::re_types_core::Loggable for IncludedSpaceView { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.IncludedSpaceView".into() + } + + #[allow(clippy::wildcard_imports)] + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + use arrow2::datatypes::*; + DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ) + } + + #[allow(clippy::wildcard_imports)] + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data0): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + let datum = datum.map(|datum| { + let Self(data0) = datum.into_owned(); + data0 + }); + (datum.is_some(), datum) + }) + .unzip(); + let data0_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; + let data0_inner_data: Vec<_> = data0 + .iter() + .map(|datum| { + datum + .map(|datum| { + let crate::datatypes::Uuid { bytes } = datum; + bytes + }) + .unwrap_or_default() + }) + .flatten() + .map(Some) + .collect(); + let data0_inner_bitmap: Option = + data0_bitmap.as_ref().map(|bitmap| { + bitmap + .iter() + .map(|i| std::iter::repeat(i).take(16usize)) + .flatten() + .collect::>() + .into() + }); + FixedSizeListArray::new( + Self::arrow_datatype(), + PrimitiveArray::new( + DataType::UInt8, + data0_inner_data + .into_iter() + .map(|v| v.unwrap_or_default()) + .collect(), + data0_inner_bitmap, + ) + .boxed(), + data0_bitmap, + ) + .boxed() + } + }) + } + + #[allow(clippy::wildcard_imports)] + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.IncludedSpaceView#space_view_ids")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let offsets = (0..) + .step_by(16usize) + .zip((16usize..).step_by(16usize).take(arrow_data.len())); + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + arrow_data_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::UInt8; + let actual = arrow_data_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context( + "rerun.blueprint.components.IncludedSpaceView#space_view_ids", + )? + .into_iter() + .map(|opt| opt.copied()) + .collect::>() + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets, + arrow_data.validity(), + ) + .map(|elem| { + elem.map(|(start, end)| { + debug_assert!(end - start == 16usize); + if end as usize > arrow_data_inner.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_inner.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_inner.get_unchecked(start as usize..end as usize) }; + let data = data.iter().cloned().map(Option::unwrap_or_default); + let arr = array_init::from_iter(data).unwrap(); + Ok(arr) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt + .map(|res_or_opt| res_or_opt.map(|bytes| crate::datatypes::Uuid { bytes })) + }) + .collect::>>>()? + } + .into_iter() + } + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .map(|res| res.map(|v| Some(Self(v)))) + .collect::>>>() + .with_context("rerun.blueprint.components.IncludedSpaceView#space_view_ids") + .with_context("rerun.blueprint.components.IncludedSpaceView")?) + } + + #[allow(clippy::wildcard_imports)] + #[inline] + fn from_arrow(arrow_data: &dyn arrow2::array::Array) -> DeserializationResult> + where + Self: Sized, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + if let Some(validity) = arrow_data.validity() { + if validity.unset_bits() != 0 { + return Err(DeserializationError::missing_data()); + } + } + Ok({ + let slice = { + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.IncludedSpaceView#space_view_ids")?; + let arrow_data_inner = &**arrow_data.values(); + bytemuck::cast_slice::<_, [_; 16usize]>( + arrow_data_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::UInt8; + let actual = arrow_data_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context( + "rerun.blueprint.components.IncludedSpaceView#space_view_ids", + )? + .values() + .as_slice(), + ) + }; + { + slice + .iter() + .copied() + .map(|bytes| crate::datatypes::Uuid { bytes }) + .map(|v| Self(v)) + .collect::>() + } + }) + } +} diff --git a/crates/re_viewport/src/blueprint/components/included_space_views.rs b/crates/re_viewport/src/blueprint/components/included_space_views.rs deleted file mode 100644 index 816e514d14f0..000000000000 --- a/crates/re_viewport/src/blueprint/components/included_space_views.rs +++ /dev/null @@ -1,195 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs -// Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_views.fbs". - -#![allow(trivial_numeric_casts)] -#![allow(unused_imports)] -#![allow(unused_parens)] -#![allow(clippy::clone_on_copy)] -#![allow(clippy::iter_on_single_items)] -#![allow(clippy::map_flatten)] -#![allow(clippy::match_wildcard_for_single_variants)] -#![allow(clippy::needless_question_mark)] -#![allow(clippy::new_without_default)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::too_many_lines)] -#![allow(clippy::unnecessary_cast)] - -use ::re_types_core::external::arrow2; -use ::re_types_core::ComponentName; -use ::re_types_core::SerializationResult; -use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; -use ::re_types_core::{DeserializationError, DeserializationResult}; - -/// **Component**: The id of a `SpaceView`. -/// -/// Unstable. Used for the ongoing blueprint experimentations. -#[derive(Clone, Debug, Default)] -#[repr(transparent)] -pub struct IncludedSpaceViews(pub Vec); - -impl ::re_types_core::SizeBytes for IncludedSpaceViews { - #[inline] - fn heap_size_bytes(&self) -> u64 { - self.0.heap_size_bytes() - } - - #[inline] - fn is_pod() -> bool { - >::is_pod() - } -} - -impl, T: IntoIterator> From for IncludedSpaceViews { - fn from(v: T) -> Self { - Self(v.into_iter().map(|v| v.into()).collect()) - } -} - -::re_types_core::macros::impl_into_cow!(IncludedSpaceViews); - -impl ::re_types_core::Loggable for IncludedSpaceViews { - type Name = ::re_types_core::ComponentName; - - #[inline] - fn name() -> Self::Name { - "rerun.blueprint.components.IncludedSpaceViews".into() - } - - #[allow(clippy::wildcard_imports)] - #[inline] - fn arrow_datatype() -> arrow2::datatypes::DataType { - use arrow2::datatypes::*; - DataType::List(std::sync::Arc::new(Field::new( - "item", - ::arrow_datatype(), - false, - ))) - } - - #[allow(clippy::wildcard_imports)] - fn to_arrow_opt<'a>( - data: impl IntoIterator>>>, - ) -> SerializationResult> - where - Self: Clone + 'a, - { - use ::re_types_core::{Loggable as _, ResultExt as _}; - use arrow2::{array::*, datatypes::*}; - Ok({ - let (somes, data0): (Vec<_>, Vec<_>) = data - .into_iter() - .map(|datum| { - let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); - let datum = datum.map(|datum| { - let Self(data0) = datum.into_owned(); - data0 - }); - (datum.is_some(), datum) - }) - .unzip(); - let data0_bitmap: Option = { - let any_nones = somes.iter().any(|some| !*some); - any_nones.then(|| somes.into()) - }; - { - use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; - let data0_inner_data: Vec<_> = data0 - .iter() - .flatten() - .flatten() - .cloned() - .map(Some) - .collect(); - let data0_inner_bitmap: Option = None; - let offsets = arrow2::offset::Offsets::::try_from_lengths( - data0 - .iter() - .map(|opt| opt.as_ref().map(|datum| datum.len()).unwrap_or_default()), - ) - .unwrap() - .into(); - ListArray::new( - Self::arrow_datatype(), - offsets, - { - _ = data0_inner_bitmap; - crate::datatypes::Uuid::to_arrow_opt(data0_inner_data)? - }, - data0_bitmap, - ) - .boxed() - } - }) - } - - #[allow(clippy::wildcard_imports)] - fn from_arrow_opt( - arrow_data: &dyn arrow2::array::Array, - ) -> DeserializationResult>> - where - Self: Sized, - { - use ::re_types_core::{Loggable as _, ResultExt as _}; - use arrow2::{array::*, buffer::*, datatypes::*}; - Ok({ - let arrow_data = arrow_data - .as_any() - .downcast_ref::>() - .ok_or_else(|| { - let expected = Self::arrow_datatype(); - let actual = arrow_data.data_type().clone(); - DeserializationError::datatype_mismatch(expected, actual) - }) - .with_context("rerun.blueprint.components.IncludedSpaceViews#space_view_ids")?; - if arrow_data.is_empty() { - Vec::new() - } else { - let arrow_data_inner = { - let arrow_data_inner = &**arrow_data.values(); - crate::datatypes::Uuid::from_arrow_opt(arrow_data_inner) - .with_context( - "rerun.blueprint.components.IncludedSpaceViews#space_view_ids", - )? - .into_iter() - .collect::>() - }; - let offsets = arrow_data.offsets(); - arrow2::bitmap::utils::ZipValidity::new_with_validity( - offsets.iter().zip(offsets.lengths()), - arrow_data.validity(), - ) - .map(|elem| { - elem.map(|(start, len)| { - let start = *start as usize; - let end = start + len; - if end as usize > arrow_data_inner.len() { - return Err(DeserializationError::offset_slice_oob( - (start, end), - arrow_data_inner.len(), - )); - } - - #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] - let data = - unsafe { arrow_data_inner.get_unchecked(start as usize..end as usize) }; - let data = data - .iter() - .cloned() - .map(Option::unwrap_or_default) - .collect(); - Ok(data) - }) - .transpose() - }) - .collect::>>>()? - } - .into_iter() - } - .map(|v| v.ok_or_else(DeserializationError::missing_data)) - .map(|res| res.map(|v| Some(Self(v)))) - .collect::>>>() - .with_context("rerun.blueprint.components.IncludedSpaceViews#space_view_ids") - .with_context("rerun.blueprint.components.IncludedSpaceViews")?) - } -} diff --git a/crates/re_viewport/src/blueprint/components/mod.rs b/crates/re_viewport/src/blueprint/components/mod.rs index a044d8274eb2..7c0846e84dd5 100644 --- a/crates/re_viewport/src/blueprint/components/mod.rs +++ b/crates/re_viewport/src/blueprint/components/mod.rs @@ -6,7 +6,7 @@ mod auto_space_views; mod container_kind; mod container_kind_ext; mod grid_columns; -mod included_space_views; +mod included_space_view; mod root_container; mod space_view_maximized; mod space_view_maximized_ext; @@ -17,7 +17,7 @@ pub use self::auto_layout::AutoLayout; pub use self::auto_space_views::AutoSpaceViews; pub use self::container_kind::ContainerKind; pub use self::grid_columns::GridColumns; -pub use self::included_space_views::IncludedSpaceViews; +pub use self::included_space_view::IncludedSpaceView; pub use self::root_container::RootContainer; pub use self::space_view_maximized::SpaceViewMaximized; pub use self::viewport_layout::ViewportLayout; diff --git a/crates/re_viewport/src/blueprint/components/root_container.rs b/crates/re_viewport/src/blueprint/components/root_container.rs index d23e96fb9130..5f0edc646835 100644 --- a/crates/re_viewport/src/blueprint/components/root_container.rs +++ b/crates/re_viewport/src/blueprint/components/root_container.rs @@ -76,14 +76,10 @@ impl ::re_types_core::Loggable for RootContainer { #[inline] fn arrow_datatype() -> arrow2::datatypes::DataType { use arrow2::datatypes::*; - DataType::Struct(std::sync::Arc::new(vec![Field::new( - "bytes", - DataType::FixedSizeList( - std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), - 16usize, - ), - false, - )])) + DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ) } #[allow(clippy::wildcard_imports)] @@ -112,8 +108,43 @@ impl ::re_types_core::Loggable for RootContainer { any_nones.then(|| somes.into()) }; { - _ = data0_bitmap; - crate::datatypes::Uuid::to_arrow_opt(data0)? + use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; + let data0_inner_data: Vec<_> = data0 + .iter() + .map(|datum| { + datum + .map(|datum| { + let crate::datatypes::Uuid { bytes } = datum; + bytes + }) + .unwrap_or_default() + }) + .flatten() + .map(Some) + .collect(); + let data0_inner_bitmap: Option = + data0_bitmap.as_ref().map(|bitmap| { + bitmap + .iter() + .map(|i| std::iter::repeat(i).take(16usize)) + .flatten() + .collect::>() + .into() + }); + FixedSizeListArray::new( + Self::arrow_datatype(), + PrimitiveArray::new( + DataType::UInt8, + data0_inner_data + .into_iter() + .map(|v| v.unwrap_or_default()) + .collect(), + data0_inner_bitmap, + ) + .boxed(), + data0_bitmap, + ) + .boxed() } }) } @@ -127,13 +158,125 @@ impl ::re_types_core::Loggable for RootContainer { { use ::re_types_core::{Loggable as _, ResultExt as _}; use arrow2::{array::*, buffer::*, datatypes::*}; - Ok(crate::datatypes::Uuid::from_arrow_opt(arrow_data) - .with_context("rerun.blueprint.components.RootContainer#id")? + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.RootContainer#id")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let offsets = (0..) + .step_by(16usize) + .zip((16usize..).step_by(16usize).take(arrow_data.len())); + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + arrow_data_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::UInt8; + let actual = arrow_data_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.RootContainer#id")? + .into_iter() + .map(|opt| opt.copied()) + .collect::>() + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets, + arrow_data.validity(), + ) + .map(|elem| { + elem.map(|(start, end)| { + debug_assert!(end - start == 16usize); + if end as usize > arrow_data_inner.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_inner.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_inner.get_unchecked(start as usize..end as usize) }; + let data = data.iter().cloned().map(Option::unwrap_or_default); + let arr = array_init::from_iter(data).unwrap(); + Ok(arr) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt + .map(|res_or_opt| res_or_opt.map(|bytes| crate::datatypes::Uuid { bytes })) + }) + .collect::>>>()? + } .into_iter() - .map(|v| v.ok_or_else(DeserializationError::missing_data)) - .map(|res| res.map(|v| Some(Self(v)))) - .collect::>>>() - .with_context("rerun.blueprint.components.RootContainer#id") - .with_context("rerun.blueprint.components.RootContainer")?) + } + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .map(|res| res.map(|v| Some(Self(v)))) + .collect::>>>() + .with_context("rerun.blueprint.components.RootContainer#id") + .with_context("rerun.blueprint.components.RootContainer")?) + } + + #[allow(clippy::wildcard_imports)] + #[inline] + fn from_arrow(arrow_data: &dyn arrow2::array::Array) -> DeserializationResult> + where + Self: Sized, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + if let Some(validity) = arrow_data.validity() { + if validity.unset_bits() != 0 { + return Err(DeserializationError::missing_data()); + } + } + Ok({ + let slice = { + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.RootContainer#id")?; + let arrow_data_inner = &**arrow_data.values(); + bytemuck::cast_slice::<_, [_; 16usize]>( + arrow_data_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::UInt8; + let actual = arrow_data_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.RootContainer#id")? + .values() + .as_slice(), + ) + }; + { + slice + .iter() + .copied() + .map(|bytes| crate::datatypes::Uuid { bytes }) + .map(|v| Self(v)) + .collect::>() + } + }) } } diff --git a/crates/re_viewport/src/blueprint/components/space_view_maximized.rs b/crates/re_viewport/src/blueprint/components/space_view_maximized.rs index e366925657b0..1272674a2319 100644 --- a/crates/re_viewport/src/blueprint/components/space_view_maximized.rs +++ b/crates/re_viewport/src/blueprint/components/space_view_maximized.rs @@ -76,14 +76,10 @@ impl ::re_types_core::Loggable for SpaceViewMaximized { #[inline] fn arrow_datatype() -> arrow2::datatypes::DataType { use arrow2::datatypes::*; - DataType::Struct(std::sync::Arc::new(vec![Field::new( - "bytes", - DataType::FixedSizeList( - std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), - 16usize, - ), - false, - )])) + DataType::FixedSizeList( + std::sync::Arc::new(Field::new("item", DataType::UInt8, false)), + 16usize, + ) } #[allow(clippy::wildcard_imports)] @@ -114,8 +110,43 @@ impl ::re_types_core::Loggable for SpaceViewMaximized { any_nones.then(|| somes.into()) }; { - _ = data0_bitmap; - crate::datatypes::Uuid::to_arrow_opt(data0)? + use arrow2::{buffer::Buffer, offset::OffsetsBuffer}; + let data0_inner_data: Vec<_> = data0 + .iter() + .map(|datum| { + datum + .map(|datum| { + let crate::datatypes::Uuid { bytes } = datum; + bytes + }) + .unwrap_or_default() + }) + .flatten() + .map(Some) + .collect(); + let data0_inner_bitmap: Option = + data0_bitmap.as_ref().map(|bitmap| { + bitmap + .iter() + .map(|i| std::iter::repeat(i).take(16usize)) + .flatten() + .collect::>() + .into() + }); + FixedSizeListArray::new( + Self::arrow_datatype(), + PrimitiveArray::new( + DataType::UInt8, + data0_inner_data + .into_iter() + .map(|v| v.unwrap_or_default()) + .collect(), + data0_inner_bitmap, + ) + .boxed(), + data0_bitmap, + ) + .boxed() } }) } @@ -129,13 +160,74 @@ impl ::re_types_core::Loggable for SpaceViewMaximized { { use ::re_types_core::{Loggable as _, ResultExt as _}; use arrow2::{array::*, buffer::*, datatypes::*}; - Ok(crate::datatypes::Uuid::from_arrow_opt(arrow_data) - .with_context("rerun.blueprint.components.SpaceViewMaximized#space_view_id")? + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.SpaceViewMaximized#space_view_id")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let offsets = (0..) + .step_by(16usize) + .zip((16usize..).step_by(16usize).take(arrow_data.len())); + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + arrow_data_inner + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::UInt8; + let actual = arrow_data_inner.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context( + "rerun.blueprint.components.SpaceViewMaximized#space_view_id", + )? + .into_iter() + .map(|opt| opt.copied()) + .collect::>() + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + offsets, + arrow_data.validity(), + ) + .map(|elem| { + elem.map(|(start, end)| { + debug_assert!(end - start == 16usize); + if end as usize > arrow_data_inner.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_inner.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_inner.get_unchecked(start as usize..end as usize) }; + let data = data.iter().cloned().map(Option::unwrap_or_default); + let arr = array_init::from_iter(data).unwrap(); + Ok(arr) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt + .map(|res_or_opt| res_or_opt.map(|bytes| crate::datatypes::Uuid { bytes })) + }) + .collect::>>>()? + } .into_iter() - .map(Ok) - .map(|res| res.map(|v| Some(Self(v)))) - .collect::>>>() - .with_context("rerun.blueprint.components.SpaceViewMaximized#space_view_id") - .with_context("rerun.blueprint.components.SpaceViewMaximized")?) + } + .map(Ok) + .map(|res| res.map(|v| Some(Self(v)))) + .collect::>>>() + .with_context("rerun.blueprint.components.SpaceViewMaximized#space_view_id") + .with_context("rerun.blueprint.components.SpaceViewMaximized")?) } } diff --git a/crates/re_viewport/src/blueprint/data_ui.rs b/crates/re_viewport/src/blueprint/data_ui.rs index 8f21525361e6..920150635e5f 100644 --- a/crates/re_viewport/src/blueprint/data_ui.rs +++ b/crates/re_viewport/src/blueprint/data_ui.rs @@ -1,30 +1,20 @@ use re_data_ui::{add_to_registry, DataUi}; use re_viewer_context::{ComponentUiRegistry, SpaceViewId, UiVerbosity, ViewerContext}; -use super::components::{IncludedSpaceViews, SpaceViewMaximized, ViewportLayout}; +use super::components::{IncludedSpaceView, SpaceViewMaximized, ViewportLayout}; -impl DataUi for IncludedSpaceViews { +impl DataUi for IncludedSpaceView { #[allow(clippy::only_used_in_recursion)] fn data_ui( &self, - _ctx: &ViewerContext<'_>, + ctx: &ViewerContext<'_>, ui: &mut egui::Ui, verbosity: UiVerbosity, query: &re_data_store::LatestAtQuery, store: &re_data_store::DataStore, ) { - match verbosity { - UiVerbosity::Small => { - ui.label(format!("{} Space Views", self.0.len())); - } - UiVerbosity::Full | UiVerbosity::LimitHeight | UiVerbosity::Reduced => { - for space_view in &self.0 { - let space_view: SpaceViewId = (*space_view).into(); - space_view.data_ui(_ctx, ui, verbosity, query, store); - ui.end_row(); - } - } - } + let space_view: SpaceViewId = self.0.into(); + space_view.data_ui(ctx, ui, verbosity, query, store); } } @@ -74,7 +64,7 @@ impl DataUi for ViewportLayout { pub fn register_ui_components(registry: &mut ComponentUiRegistry) { re_tracing::profile_function!(); - add_to_registry::(registry); + add_to_registry::(registry); add_to_registry::(registry); add_to_registry::(registry); } diff --git a/crates/re_viewport/src/viewport_blueprint.rs b/crates/re_viewport/src/viewport_blueprint.rs index 9708249f4b8c..745fb75d6057 100644 --- a/crates/re_viewport/src/viewport_blueprint.rs +++ b/crates/re_viewport/src/viewport_blueprint.rs @@ -12,7 +12,7 @@ use re_viewer_context::{ContainerId, Item, SpaceViewClassIdentifier, SpaceViewId use crate::{ blueprint::components::{ - AutoLayout, AutoSpaceViews, IncludedSpaceViews, RootContainer, SpaceViewMaximized, + AutoLayout, AutoSpaceViews, IncludedSpaceView, RootContainer, SpaceViewMaximized, ViewportLayout, }, container::{blueprint_id_to_tile_id, ContainerBlueprint, Contents}, @@ -88,7 +88,7 @@ impl ViewportBlueprint { }; let space_view_ids: Vec = - arch.space_views.0.iter().map(|id| (*id).into()).collect(); + arch.space_views.iter().map(|id| id.0.into()).collect(); let space_views: BTreeMap = space_view_ids .into_iter() @@ -221,14 +221,12 @@ impl ViewportBlueprint { } // Filter the space-view from the included space-views - let component = IncludedSpaceViews( - self.space_views - .keys() - .filter(|id| id != &space_view_id) - .map(|id| (*id).into()) - .collect(), - ); - ctx.save_blueprint_component(&VIEWPORT_PATH.into(), component); + let components = self + .space_views + .keys() + .filter(|id| id != &space_view_id) + .map(|id| IncludedSpaceView((*id).into())); + ctx.save_blueprint_component_iter(&VIEWPORT_PATH.into(), components); } /// Duplicates a space view and its entity property overrides. @@ -294,8 +292,8 @@ impl ViewportBlueprint { /// if needed. /// /// NOTE: Calling this more than once per frame will result in lost data. - /// Each call to `add_space_views` emits an updated list of [`IncludedSpaceViews`] - /// Built by taking the list of [`IncludedSpaceViews`] from the current frame + /// Each call to `add_space_views` emits an updated list of [`IncludedSpaceView`]s + /// Built by taking the list of [`IncludedSpaceView`]s from the current frame /// and adding the new space views to it. Since this the edit is not applied until /// the end of frame the second call will see a stale version of the data. // TODO(jleibs): Better safety check here. @@ -327,12 +325,13 @@ impl ViewportBlueprint { )); } - let updated_ids: Vec<_> = self.space_views.keys().chain(new_ids.iter()).collect(); - - let component = - IncludedSpaceViews(updated_ids.into_iter().map(|id| (*id).into()).collect()); + let components = self + .space_views + .keys() + .chain(new_ids.iter()) + .map(|id| IncludedSpaceView((*id).into())); - ctx.save_blueprint_component(&VIEWPORT_PATH.into(), component); + ctx.save_blueprint_component_iter(&VIEWPORT_PATH.into(), components); } new_ids diff --git a/examples/python/raw_mesh/main.py b/examples/python/raw_mesh/main.py index 5bfd677919fa..5ffacf3c9560 100755 --- a/examples/python/raw_mesh/main.py +++ b/examples/python/raw_mesh/main.py @@ -51,7 +51,7 @@ def log_scene(scene: trimesh.Scene, node: str, path: str | None = None) -> None: # Log this node's mesh, if it has one. mesh = cast(trimesh.Trimesh, scene.geometry.get(node_data[1])) - if mesh: + if mesh is not None: vertex_colors = None vertex_texcoords = None mesh_material = None @@ -87,7 +87,7 @@ def log_scene(scene: trimesh.Scene, node: str, path: str | None = None) -> None: rr.Mesh3D( vertex_positions=mesh.vertices, vertex_colors=vertex_colors, - vertex_normals=mesh.vertex_normals, + vertex_normals=mesh.vertex_normals, # type: ignore[arg-type] vertex_texcoords=vertex_texcoords, albedo_texture=albedo_texture, indices=mesh.faces, diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/viewport_blueprint.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/viewport_blueprint.hpp index 09891556cc55..814983a13eea 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/viewport_blueprint.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/viewport_blueprint.hpp @@ -5,7 +5,7 @@ #include "../../blueprint/components/auto_layout.hpp" #include "../../blueprint/components/auto_space_views.hpp" -#include "../../blueprint/components/included_space_views.hpp" +#include "../../blueprint/components/included_space_view.hpp" #include "../../blueprint/components/root_container.hpp" #include "../../blueprint/components/space_view_maximized.hpp" #include "../../blueprint/components/viewport_layout.hpp" @@ -24,7 +24,7 @@ namespace rerun::blueprint::archetypes { /// **Archetype**: The top-level description of the Viewport. struct ViewportBlueprint { /// All of the space-views that belong to the viewport. - rerun::blueprint::components::IncludedSpaceViews space_views; + Collection space_views; /// The layout of the space-views std::optional layout; @@ -54,7 +54,9 @@ namespace rerun::blueprint::archetypes { ViewportBlueprint() = default; ViewportBlueprint(ViewportBlueprint&& other) = default; - explicit ViewportBlueprint(rerun::blueprint::components::IncludedSpaceViews _space_views) + explicit ViewportBlueprint( + Collection _space_views + ) : space_views(std::move(_space_views)) {} /// The layout of the space-views @@ -102,7 +104,7 @@ namespace rerun::blueprint::archetypes { /// Returns the number of primary instances of this archetype. size_t num_instances() const { - return 1; + return space_views.size(); } }; diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index 3cb9c70cdc95..cc5c39fc512d 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -13,7 +13,7 @@ #include "blueprint/components/grid_columns.hpp" #include "blueprint/components/included_contents.hpp" #include "blueprint/components/included_queries.hpp" -#include "blueprint/components/included_space_views.hpp" +#include "blueprint/components/included_space_view.hpp" #include "blueprint/components/lock_range_during_zoom.hpp" #include "blueprint/components/panel_view.hpp" #include "blueprint/components/query_expressions.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/components/.gitattributes b/rerun_cpp/src/rerun/blueprint/components/.gitattributes index 4aae17f930f1..ccee84c265a2 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -23,8 +23,8 @@ included_contents.cpp linguist-generated=true included_contents.hpp linguist-generated=true included_queries.cpp linguist-generated=true included_queries.hpp linguist-generated=true -included_space_views.cpp linguist-generated=true -included_space_views.hpp linguist-generated=true +included_space_view.cpp linguist-generated=true +included_space_view.hpp linguist-generated=true lock_range_during_zoom.cpp linguist-generated=true lock_range_during_zoom.hpp linguist-generated=true panel_view.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/components/included_queries.cpp b/rerun_cpp/src/rerun/blueprint/components/included_queries.cpp index 7fce7e983d63..b2d712fd45d4 100644 --- a/rerun_cpp/src/rerun/blueprint/components/included_queries.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/included_queries.cpp @@ -33,7 +33,7 @@ namespace rerun { ); } - auto value_builder = static_cast(builder->value_builder()); + auto value_builder = static_cast(builder->value_builder()); ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); ARROW_RETURN_NOT_OK(value_builder->Reserve(static_cast(num_elements * 2))); diff --git a/rerun_cpp/src/rerun/blueprint/components/included_space_view.cpp b/rerun_cpp/src/rerun/blueprint/components/included_space_view.cpp new file mode 100644 index 000000000000..5b36afd60486 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/included_space_view.cpp @@ -0,0 +1,58 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_view.fbs". + +#include "included_space_view.hpp" + +#include "../../datatypes/uuid.hpp" + +#include +#include + +namespace rerun::blueprint::components {} + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = Loggable::arrow_datatype(); + return datatype; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::FixedSizeListBuilder* builder, + const blueprint::components::IncludedSpaceView* elements, size_t num_elements + ) { + static_assert( + sizeof(rerun::datatypes::Uuid) == sizeof(blueprint::components::IncludedSpaceView) + ); + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + builder, + reinterpret_cast(elements), + num_elements + )); + + return Error::ok(); + } + + Result> + Loggable::to_arrow( + const blueprint::components::IncludedSpaceView* instances, size_t num_instances + ) { + // TODO(andreas): Allow configuring the memory pool. + arrow::MemoryPool* pool = arrow::default_memory_pool(); + auto datatype = arrow_datatype(); + + ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) + if (instances && num_instances > 0) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + ) + ); + } + std::shared_ptr array; + ARROW_RETURN_NOT_OK(builder->Finish(&array)); + return array; + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/included_space_views.hpp b/rerun_cpp/src/rerun/blueprint/components/included_space_view.hpp similarity index 51% rename from rerun_cpp/src/rerun/blueprint/components/included_space_views.hpp rename to rerun_cpp/src/rerun/blueprint/components/included_space_view.hpp index dbc92e5aba13..03fbeb2ee20d 100644 --- a/rerun_cpp/src/rerun/blueprint/components/included_space_views.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/included_space_view.hpp @@ -1,39 +1,50 @@ // DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_views.fbs". +// Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_view.fbs". #pragma once -#include "../../collection.hpp" #include "../../datatypes/uuid.hpp" #include "../../result.hpp" +#include #include #include -#include namespace arrow { class Array; class DataType; - class ListBuilder; + class FixedSizeListBuilder; } // namespace arrow namespace rerun::blueprint::components { /// **Component**: The id of a `SpaceView`. /// /// Unstable. Used for the ongoing blueprint experimentations. - struct IncludedSpaceViews { - rerun::Collection space_view_ids; + struct IncludedSpaceView { + rerun::datatypes::Uuid space_view_ids; public: - IncludedSpaceViews() = default; + IncludedSpaceView() = default; - IncludedSpaceViews(rerun::Collection space_view_ids_) - : space_view_ids(std::move(space_view_ids_)) {} + IncludedSpaceView(rerun::datatypes::Uuid space_view_ids_) + : space_view_ids(space_view_ids_) {} - IncludedSpaceViews& operator=(rerun::Collection space_view_ids_) { - space_view_ids = std::move(space_view_ids_); + IncludedSpaceView& operator=(rerun::datatypes::Uuid space_view_ids_) { + space_view_ids = space_view_ids_; return *this; } + + IncludedSpaceView(std::array bytes_) : space_view_ids(bytes_) {} + + IncludedSpaceView& operator=(std::array bytes_) { + space_view_ids = bytes_; + return *this; + } + + /// Cast to the underlying Uuid datatype + operator rerun::datatypes::Uuid() const { + return space_view_ids; + } }; } // namespace rerun::blueprint::components @@ -43,21 +54,21 @@ namespace rerun { /// \private template <> - struct Loggable { - static constexpr const char Name[] = "rerun.blueprint.components.IncludedSpaceViews"; + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.IncludedSpaceView"; /// Returns the arrow data type this type corresponds to. static const std::shared_ptr& arrow_datatype(); /// Fills an arrow array builder with an array of this type. static rerun::Error fill_arrow_array_builder( - arrow::ListBuilder* builder, const blueprint::components::IncludedSpaceViews* elements, - size_t num_elements + arrow::FixedSizeListBuilder* builder, + const blueprint::components::IncludedSpaceView* elements, size_t num_elements ); - /// Serializes an array of `rerun::blueprint:: components::IncludedSpaceViews` into an arrow array. + /// Serializes an array of `rerun::blueprint:: components::IncludedSpaceView` into an arrow array. static Result> to_arrow( - const blueprint::components::IncludedSpaceViews* instances, size_t num_instances + const blueprint::components::IncludedSpaceView* instances, size_t num_instances ); }; } // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/included_space_views.cpp b/rerun_cpp/src/rerun/blueprint/components/included_space_views.cpp deleted file mode 100644 index ce8a91627f68..000000000000 --- a/rerun_cpp/src/rerun/blueprint/components/included_space_views.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_views.fbs". - -#include "included_space_views.hpp" - -#include "../../datatypes/uuid.hpp" - -#include -#include - -namespace rerun::blueprint::components {} - -namespace rerun { - const std::shared_ptr& - Loggable::arrow_datatype() { - static const auto datatype = arrow::list( - arrow::field("item", Loggable::arrow_datatype(), false) - ); - return datatype; - } - - rerun::Error Loggable::fill_arrow_array_builder( - arrow::ListBuilder* builder, const blueprint::components::IncludedSpaceViews* elements, - size_t num_elements - ) { - if (builder == nullptr) { - return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); - } - if (elements == nullptr) { - return rerun::Error( - ErrorCode::UnexpectedNullArgument, - "Cannot serialize null pointer to arrow array." - ); - } - - auto value_builder = static_cast(builder->value_builder()); - ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); - ARROW_RETURN_NOT_OK(value_builder->Reserve(static_cast(num_elements * 2))); - - for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { - const auto& element = elements[elem_idx]; - ARROW_RETURN_NOT_OK(builder->Append()); - if (element.space_view_ids.data()) { - RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( - value_builder, - element.space_view_ids.data(), - element.space_view_ids.size() - )); - } - } - - return Error::ok(); - } - - Result> - Loggable::to_arrow( - const blueprint::components::IncludedSpaceViews* instances, size_t num_instances - ) { - // TODO(andreas): Allow configuring the memory pool. - arrow::MemoryPool* pool = arrow::default_memory_pool(); - auto datatype = arrow_datatype(); - - ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) - if (instances && num_instances > 0) { - RR_RETURN_NOT_OK( - Loggable::fill_arrow_array_builder( - static_cast(builder.get()), - instances, - num_instances - ) - ); - } - std::shared_ptr array; - ARROW_RETURN_NOT_OK(builder->Finish(&array)); - return array; - } -} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/root_container.cpp b/rerun_cpp/src/rerun/blueprint/components/root_container.cpp index b5be9ab7a995..b65f5a5a0bbc 100644 --- a/rerun_cpp/src/rerun/blueprint/components/root_container.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/root_container.cpp @@ -18,7 +18,7 @@ namespace rerun { } rerun::Error Loggable::fill_arrow_array_builder( - arrow::StructBuilder* builder, const blueprint::components::RootContainer* elements, + arrow::FixedSizeListBuilder* builder, const blueprint::components::RootContainer* elements, size_t num_elements ) { static_assert( @@ -44,7 +44,7 @@ namespace rerun { if (instances && num_instances > 0) { RR_RETURN_NOT_OK( Loggable::fill_arrow_array_builder( - static_cast(builder.get()), + static_cast(builder.get()), instances, num_instances ) diff --git a/rerun_cpp/src/rerun/blueprint/components/root_container.hpp b/rerun_cpp/src/rerun/blueprint/components/root_container.hpp index c1f0f7f3ae6d..737f64a5329b 100644 --- a/rerun_cpp/src/rerun/blueprint/components/root_container.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/root_container.hpp @@ -13,7 +13,7 @@ namespace arrow { class Array; class DataType; - class StructBuilder; + class FixedSizeListBuilder; } // namespace arrow namespace rerun::blueprint::components { @@ -60,8 +60,8 @@ namespace rerun { /// Fills an arrow array builder with an array of this type. static rerun::Error fill_arrow_array_builder( - arrow::StructBuilder* builder, const blueprint::components::RootContainer* elements, - size_t num_elements + arrow::FixedSizeListBuilder* builder, + const blueprint::components::RootContainer* elements, size_t num_elements ); /// Serializes an array of `rerun::blueprint:: components::RootContainer` into an arrow array. diff --git a/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.cpp b/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.cpp index f4a719c58772..8c5b43f1cc7e 100644 --- a/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.cpp @@ -18,8 +18,8 @@ namespace rerun { } rerun::Error Loggable::fill_arrow_array_builder( - arrow::StructBuilder* builder, const blueprint::components::SpaceViewMaximized* elements, - size_t num_elements + arrow::FixedSizeListBuilder* builder, + const blueprint::components::SpaceViewMaximized* elements, size_t num_elements ) { (void)builder; (void)elements; @@ -46,7 +46,7 @@ namespace rerun { if (instances && num_instances > 0) { RR_RETURN_NOT_OK( Loggable::fill_arrow_array_builder( - static_cast(builder.get()), + static_cast(builder.get()), instances, num_instances ) diff --git a/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.hpp b/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.hpp index df86de31d7c7..3a47a74e284e 100644 --- a/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/space_view_maximized.hpp @@ -14,7 +14,7 @@ namespace arrow { class Array; class DataType; - class StructBuilder; + class FixedSizeListBuilder; } // namespace arrow namespace rerun::blueprint::components { @@ -63,7 +63,7 @@ namespace rerun { /// Fills an arrow array builder with an array of this type. static rerun::Error fill_arrow_array_builder( - arrow::StructBuilder* builder, + arrow::FixedSizeListBuilder* builder, const blueprint::components::SpaceViewMaximized* elements, size_t num_elements ); diff --git a/rerun_cpp/src/rerun/datatypes/uuid.cpp b/rerun_cpp/src/rerun/datatypes/uuid.cpp index 44634d3764c3..5814dad69ae9 100644 --- a/rerun_cpp/src/rerun/datatypes/uuid.cpp +++ b/rerun_cpp/src/rerun/datatypes/uuid.cpp @@ -10,18 +10,13 @@ namespace rerun::datatypes {} namespace rerun { const std::shared_ptr& Loggable::arrow_datatype() { - static const auto datatype = arrow::struct_({ - arrow::field( - "bytes", - arrow::fixed_size_list(arrow::field("item", arrow::uint8(), false), 16), - false - ), - }); + static const auto datatype = + arrow::fixed_size_list(arrow::field("item", arrow::uint8(), false), 16); return datatype; } rerun::Error Loggable::fill_arrow_array_builder( - arrow::StructBuilder* builder, const datatypes::Uuid* elements, size_t num_elements + arrow::FixedSizeListBuilder* builder, const datatypes::Uuid* elements, size_t num_elements ) { if (builder == nullptr) { return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); @@ -33,20 +28,15 @@ namespace rerun { ); } - { - auto field_builder = - static_cast(builder->field_builder(0)); - auto value_builder = static_cast(field_builder->value_builder()); + auto value_builder = static_cast(builder->value_builder()); - ARROW_RETURN_NOT_OK(field_builder->AppendValues(static_cast(num_elements))); - static_assert(sizeof(elements[0].bytes) == sizeof(elements[0])); - ARROW_RETURN_NOT_OK(value_builder->AppendValues( - elements[0].bytes.data(), - static_cast(num_elements * 16), - nullptr - )); - } - ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast(num_elements), nullptr)); + ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast(num_elements))); + static_assert(sizeof(elements[0].bytes) == sizeof(elements[0])); + ARROW_RETURN_NOT_OK(value_builder->AppendValues( + elements[0].bytes.data(), + static_cast(num_elements * 16), + nullptr + )); return Error::ok(); } @@ -61,7 +51,7 @@ namespace rerun { ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) if (instances && num_instances > 0) { RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( - static_cast(builder.get()), + static_cast(builder.get()), instances, num_instances )); diff --git a/rerun_cpp/src/rerun/datatypes/uuid.hpp b/rerun_cpp/src/rerun/datatypes/uuid.hpp index ebf26236bfa7..0bbe56de8396 100644 --- a/rerun_cpp/src/rerun/datatypes/uuid.hpp +++ b/rerun_cpp/src/rerun/datatypes/uuid.hpp @@ -12,7 +12,7 @@ namespace arrow { class Array; class DataType; - class StructBuilder; + class FixedSizeListBuilder; } // namespace arrow namespace rerun::datatypes { @@ -46,7 +46,8 @@ namespace rerun { /// Fills an arrow array builder with an array of this type. static rerun::Error fill_arrow_array_builder( - arrow::StructBuilder* builder, const datatypes::Uuid* elements, size_t num_elements + arrow::FixedSizeListBuilder* builder, const datatypes::Uuid* elements, + size_t num_elements ); /// Serializes an array of `rerun::datatypes::Uuid` into an arrow array. diff --git a/rerun_py/rerun_sdk/rerun/_converters.py b/rerun_py/rerun_sdk/rerun/_converters.py index 120b1030a15c..a234006f322c 100644 --- a/rerun_py/rerun_sdk/rerun/_converters.py +++ b/rerun_py/rerun_sdk/rerun/_converters.py @@ -22,7 +22,7 @@ class ClassA: from __future__ import annotations -from typing import SupportsFloat, SupportsInt, overload +from typing import Sequence, SupportsFloat, SupportsInt, cast, overload import numpy as np import numpy.typing as npt @@ -111,7 +111,7 @@ def str_or_none(data: str | None) -> str | None: return str(data) -def to_np_uint8(data: npt.ArrayLike | bytes) -> npt.NDArray[np.uint8]: +def to_np_uint8(data: npt.ArrayLike | bytes | Sequence[bytes]) -> npt.NDArray[np.uint8]: """ Convert some data to a numpy uint8 array. @@ -120,6 +120,9 @@ def to_np_uint8(data: npt.ArrayLike | bytes) -> npt.NDArray[np.uint8]: if isinstance(data, bytes): return np.frombuffer(data, dtype=np.uint8) + elif isinstance(data, Sequence) and len(data) > 0 and isinstance(data[0], bytes): + data = cast(Sequence[bytes], data) + return np.frombuffer(b"".join(data), dtype=np.uint8) else: return np.asarray(data, dtype=np.uint8) diff --git a/rerun_py/rerun_sdk/rerun/_validators.py b/rerun_py/rerun_sdk/rerun/_validators.py index 960d3eb67475..e0c0c92326ef 100644 --- a/rerun_py/rerun_sdk/rerun/_validators.py +++ b/rerun_py/rerun_sdk/rerun/_validators.py @@ -50,6 +50,11 @@ def flat_np_float_array_from_array_like(data: Any, dimension: int) -> npt.NDArra """Converts to a flat float numpy array from an arbitrary vector, validating for an expected dimensionality.""" array = to_np_float32(data) + return flat_np_array_from_array_like(array, dimension) + + +def flat_np_array_from_array_like(array: npt.NDArray[Any], dimension: int) -> npt.NDArray[Any]: + """Converts to a flat numpy array from an arbitrary vector, validating for an expected dimensionality.""" valid = True if len(array.shape) == 1: diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/viewport_blueprint.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/viewport_blueprint.py index f26b7cc08904..d97ecf8a3c13 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/viewport_blueprint.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/viewport_blueprint.py @@ -23,7 +23,7 @@ class ViewportBlueprint(Archetype): def __init__( self: Any, - space_views: blueprint_components.IncludedSpaceViewsLike, + space_views: datatypes.UuidArrayLike, *, layout: blueprint_components.ViewportLayoutLike | None = None, root_container: datatypes.UuidLike | None = None, @@ -84,9 +84,9 @@ def _clear(cls) -> ViewportBlueprint: inst.__attrs_clear__() return inst - space_views: blueprint_components.IncludedSpaceViewsBatch = field( + space_views: blueprint_components.IncludedSpaceViewBatch = field( metadata={"component": "required"}, - converter=blueprint_components.IncludedSpaceViewsBatch._required, # type: ignore[misc] + converter=blueprint_components.IncludedSpaceViewBatch._required, # type: ignore[misc] ) # All of the space-views that belong to the viewport. # diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index ae90fcffcf4c..c34e9e9fb8c9 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -13,7 +13,7 @@ entity_properties_component.py linguist-generated=true grid_columns.py linguist-generated=true included_contents.py linguist-generated=true included_queries.py linguist-generated=true -included_space_views.py linguist-generated=true +included_space_view.py linguist-generated=true lock_range_during_zoom.py linguist-generated=true panel_view.py linguist-generated=true query_expressions.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py index 229c8c6cb757..c6d5974556d7 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -49,13 +49,7 @@ IncludedQueriesLike, IncludedQueriesType, ) -from .included_space_views import ( - IncludedSpaceViews, - IncludedSpaceViewsArrayLike, - IncludedSpaceViewsBatch, - IncludedSpaceViewsLike, - IncludedSpaceViewsType, -) +from .included_space_view import IncludedSpaceView, IncludedSpaceViewBatch, IncludedSpaceViewType from .lock_range_during_zoom import ( LockRangeDuringZoom, LockRangeDuringZoomArrayLike, @@ -145,11 +139,9 @@ "IncludedQueriesBatch", "IncludedQueriesLike", "IncludedQueriesType", - "IncludedSpaceViews", - "IncludedSpaceViewsArrayLike", - "IncludedSpaceViewsBatch", - "IncludedSpaceViewsLike", - "IncludedSpaceViewsType", + "IncludedSpaceView", + "IncludedSpaceViewBatch", + "IncludedSpaceViewType", "LockRangeDuringZoom", "LockRangeDuringZoomArrayLike", "LockRangeDuringZoomBatch", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/included_queries.py b/rerun_py/rerun_sdk/rerun/blueprint/components/included_queries.py index 63c28f68cbc2..02282866b80c 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/included_queries.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/included_queries.py @@ -55,16 +55,7 @@ def __init__(self) -> None: pa.list_( pa.field( "item", - pa.struct( - [ - pa.field( - "bytes", - pa.list_(pa.field("item", pa.uint8(), nullable=False, metadata={}), 16), - nullable=False, - metadata={}, - ) - ] - ), + pa.list_(pa.field("item", pa.uint8(), nullable=False, metadata={}), 16), nullable=False, metadata={}, ) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/included_space_view.py b/rerun_py/rerun_sdk/rerun/blueprint/components/included_space_view.py new file mode 100644 index 000000000000..1f77f44fa770 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/included_space_view.py @@ -0,0 +1,32 @@ +# DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_view.fbs". + +# You can extend this class by creating a "IncludedSpaceViewExt" class in "included_space_view_ext.py". + +from __future__ import annotations + +from ... import datatypes +from ..._baseclasses import ComponentBatchMixin + +__all__ = ["IncludedSpaceView", "IncludedSpaceViewBatch", "IncludedSpaceViewType"] + + +class IncludedSpaceView(datatypes.Uuid): + """ + **Component**: The id of a `SpaceView`. + + Unstable. Used for the ongoing blueprint experimentations. + """ + + # You can define your own __init__ function as a member of IncludedSpaceViewExt in included_space_view_ext.py + + # Note: there are no fields here because IncludedSpaceView delegates to datatypes.Uuid + pass + + +class IncludedSpaceViewType(datatypes.UuidType): + _TYPE_NAME: str = "rerun.blueprint.components.IncludedSpaceView" + + +class IncludedSpaceViewBatch(datatypes.UuidBatch, ComponentBatchMixin): + _ARROW_TYPE = IncludedSpaceViewType() diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/included_space_views.py b/rerun_py/rerun_sdk/rerun/blueprint/components/included_space_views.py deleted file mode 100644 index 92a825da4d52..000000000000 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/included_space_views.py +++ /dev/null @@ -1,81 +0,0 @@ -# DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/python/mod.rs -# Based on "crates/re_types/definitions/rerun/blueprint/components/included_space_views.fbs". - -# You can extend this class by creating a "IncludedSpaceViewsExt" class in "included_space_views_ext.py". - -from __future__ import annotations - -from typing import Any, Sequence, Union - -import pyarrow as pa -from attrs import define, field - -from ... import datatypes -from ..._baseclasses import BaseBatch, BaseExtensionType, ComponentBatchMixin - -__all__ = [ - "IncludedSpaceViews", - "IncludedSpaceViewsArrayLike", - "IncludedSpaceViewsBatch", - "IncludedSpaceViewsLike", - "IncludedSpaceViewsType", -] - - -@define(init=False) -class IncludedSpaceViews: - """ - **Component**: The id of a `SpaceView`. - - Unstable. Used for the ongoing blueprint experimentations. - """ - - def __init__(self: Any, space_view_ids: IncludedSpaceViewsLike): - """Create a new instance of the IncludedSpaceViews component.""" - - # You can define your own __init__ function as a member of IncludedSpaceViewsExt in included_space_views_ext.py - self.__attrs_init__(space_view_ids=space_view_ids) - - space_view_ids: list[datatypes.Uuid] = field() - - -IncludedSpaceViewsLike = IncludedSpaceViews -IncludedSpaceViewsArrayLike = Union[ - IncludedSpaceViews, - Sequence[IncludedSpaceViewsLike], -] - - -class IncludedSpaceViewsType(BaseExtensionType): - _TYPE_NAME: str = "rerun.blueprint.components.IncludedSpaceViews" - - def __init__(self) -> None: - pa.ExtensionType.__init__( - self, - pa.list_( - pa.field( - "item", - pa.struct( - [ - pa.field( - "bytes", - pa.list_(pa.field("item", pa.uint8(), nullable=False, metadata={}), 16), - nullable=False, - metadata={}, - ) - ] - ), - nullable=False, - metadata={}, - ) - ), - self._TYPE_NAME, - ) - - -class IncludedSpaceViewsBatch(BaseBatch[IncludedSpaceViewsArrayLike], ComponentBatchMixin): - _ARROW_TYPE = IncludedSpaceViewsType() - - @staticmethod - def _native_to_pa_array(data: IncludedSpaceViewsArrayLike, data_type: pa.DataType) -> pa.Array: - raise NotImplementedError # You need to implement native_to_pa_array_override in included_space_views_ext.py diff --git a/rerun_py/rerun_sdk/rerun/datatypes/uuid.py b/rerun_py/rerun_sdk/rerun/datatypes/uuid.py index 69e73ef171ab..401259e36d95 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/uuid.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/uuid.py @@ -5,7 +5,7 @@ from __future__ import annotations -from typing import Any, Sequence, Union +from typing import TYPE_CHECKING, Any, Sequence, Union import numpy as np import numpy.typing as npt @@ -16,12 +16,13 @@ from .._converters import ( to_np_uint8, ) +from .uuid_ext import UuidExt __all__ = ["Uuid", "UuidArrayLike", "UuidBatch", "UuidLike", "UuidType"] @define(init=False) -class Uuid: +class Uuid(UuidExt): """**Datatype**: A 16-byte uuid.""" def __init__(self: Any, bytes: UuidLike): @@ -37,10 +38,13 @@ def __array__(self, dtype: npt.DTypeLike = None) -> npt.NDArray[Any]: return np.asarray(self.bytes, dtype=dtype) -UuidLike = Uuid +if TYPE_CHECKING: + UuidLike = Union[Uuid, npt.NDArray[Any], npt.ArrayLike, Sequence[int], bytes] +else: + UuidLike = Any + UuidArrayLike = Union[ - Uuid, - Sequence[UuidLike], + Uuid, Sequence[UuidLike], npt.NDArray[Any], npt.ArrayLike, Sequence[Sequence[int]], Sequence[int], Sequence[bytes] ] @@ -49,18 +53,7 @@ class UuidType(BaseExtensionType): def __init__(self) -> None: pa.ExtensionType.__init__( - self, - pa.struct( - [ - pa.field( - "bytes", - pa.list_(pa.field("item", pa.uint8(), nullable=False, metadata={}), 16), - nullable=False, - metadata={}, - ) - ] - ), - self._TYPE_NAME, + self, pa.list_(pa.field("item", pa.uint8(), nullable=False, metadata={}), 16), self._TYPE_NAME ) @@ -69,4 +62,4 @@ class UuidBatch(BaseBatch[UuidArrayLike]): @staticmethod def _native_to_pa_array(data: UuidArrayLike, data_type: pa.DataType) -> pa.Array: - raise NotImplementedError # You need to implement native_to_pa_array_override in uuid_ext.py + return UuidExt.native_to_pa_array_override(data, data_type) diff --git a/rerun_py/rerun_sdk/rerun/datatypes/uuid_ext.py b/rerun_py/rerun_sdk/rerun/datatypes/uuid_ext.py new file mode 100644 index 000000000000..7b65228d39f1 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/datatypes/uuid_ext.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Sequence + +import numpy as np +import pyarrow as pa + +from .._converters import to_np_uint8 +from .._validators import flat_np_array_from_array_like + +if TYPE_CHECKING: + from . import UuidArrayLike + +NUMPY_VERSION = tuple(map(int, np.version.version.split(".")[:2])) + + +class UuidExt: + """Extension for [Uuid][rerun.datatypes.Uuid].""" + + @staticmethod + def native_to_pa_array_override(data: UuidArrayLike, data_type: pa.DataType) -> pa.Array: + # TODO(ab): get rid of this once we drop support for Python 3.8. Make sure to pin numpy>=1.25. + if NUMPY_VERSION < (1, 25): + # Older numpy doesn't seem to support `data` in the form of [Point3D(1, 2), Point3D(3, 4)] + # this happens for python 3.8 (1.25 supports 3.9+) + from . import Uuid + + if isinstance(data, Sequence): + data = [np.array(p.bytes) if isinstance(p, Uuid) else p for p in data] + + uuids = to_np_uint8(data) # type: ignore[arg-type] # Any array like works and Uuid has an __array__ method. + uuids = flat_np_array_from_array_like(uuids, 16) + return pa.FixedSizeListArray.from_arrays(uuids, type=data_type) diff --git a/rerun_py/tests/unit/common_arrays.py b/rerun_py/tests/unit/common_arrays.py index d2762cfe7190..bc24eda2781f 100644 --- a/rerun_py/tests/unit/common_arrays.py +++ b/rerun_py/tests/unit/common_arrays.py @@ -30,6 +30,8 @@ RotationAxisAngle, Utf8, Utf8ArrayLike, + Uuid, + UuidArrayLike, Vec2D, Vec2DArrayLike, Vec2DBatch, @@ -451,3 +453,22 @@ def keypoint_ids_expected(obj: Any) -> Any: def instance_keys_expected(obj: Any) -> Any: expected = none_empty_or_value(obj, [U64_MAX_MINUS_1, U64_MAX]) return InstanceKeyBatch._optional(expected) + + +uuid_bytes0 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] +uuid_bytes1 = [16, 17, 127, 3, 4, 255, 6, 7, 21, 9, 10, 11, 12, 0, 14, 15] + +uuids_arrays: list[UuidArrayLike] = [ + [], + np.array([]), + # UuidArrayLike: Sequence[UuidLike]: Sequence[int] + [uuid_bytes0, uuid_bytes1], + # UuidArrayLike: Sequence[UuidLike]: npt.NDArray[np.uint8] + np.array([uuid_bytes0, uuid_bytes1], dtype=np.uint8), + # UuidArrayLike: Sequence[UuidLike]: npt.NDArray[np.uint32] + np.array([uuid_bytes0, uuid_bytes1], dtype=np.uint32), + # UuidArrayLike: Sequence[UuidLike]: Uuid + [Uuid(uuid_bytes0), Uuid(uuid_bytes1)], + # UuidArrayLike: Sequence[UuidLike]: Bytes + [bytes(uuid_bytes0), bytes(uuid_bytes1)], +] diff --git a/rerun_py/tests/unit/test_uuid.py b/rerun_py/tests/unit/test_uuid.py new file mode 100644 index 000000000000..61166704b1b2 --- /dev/null +++ b/rerun_py/tests/unit/test_uuid.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from typing import Any + +import numpy as np +import rerun as rr +from rerun.datatypes.uuid import UuidBatch + +from .common_arrays import none_empty_or_value, uuid_bytes0, uuids_arrays + + +def uuids_expected(obj: Any) -> Any: + expected = none_empty_or_value(obj, uuids_arrays[-1]) + return UuidBatch._optional(expected) + + +def test_uuid() -> None: + # Single uuid. + uuids = [uuid_bytes0, np.array(uuid_bytes0, dtype=np.uint8), np.array(uuid_bytes0, dtype=np.uint32)] + expected = rr.datatypes.UuidBatch([uuid_bytes0]).as_arrow_array() + for uuid in uuids: + assert rr.datatypes.UuidBatch([uuid]).as_arrow_array() == expected # type: ignore[arg-type] + + # Several uuids. + for uuids in uuids_arrays: # type: ignore[assignment] + expected = uuids_expected(uuids) + assert rr.datatypes.UuidBatch(uuids).as_arrow_array() == expected.as_arrow_array() # type: ignore[arg-type] diff --git a/rerun_py/tests/unit/test_viewport_blueprint.py b/rerun_py/tests/unit/test_viewport_blueprint.py new file mode 100644 index 000000000000..64555900f142 --- /dev/null +++ b/rerun_py/tests/unit/test_viewport_blueprint.py @@ -0,0 +1,56 @@ +from __future__ import annotations + +import itertools + +from rerun.blueprint.archetypes.viewport_blueprint import ViewportBlueprint +from rerun.blueprint.components.included_space_view import IncludedSpaceViewBatch + +from .common_arrays import none_empty_or_value, uuids_arrays + +# TODO(andreas): We're obviously nowhere near done with this. + + +def test_viewport_blueprint() -> None: + space_views_arrays = uuids_arrays + # layout_arrays = [] + # root_container_arrays = [] + # maximized_arrays = [] + # auto_layout_arrays = [] + # auto_space_views_arrays = [] + + all_arrays = itertools.zip_longest( + space_views_arrays, + # layout_arrays, + # root_container_arrays, + # maximized_arrays, + # auto_layout_arrays, + # auto_space_views_arrays, + ) + + # for space_views, layout, root_container, maximized, auto_layout, auto_space_views in all_arrays: + for (space_views,) in all_arrays: + # space_views = space_views if space_views is not None else space_views_arrays[-1] + + print( + "rr.ViewportBlueprint(\n", + f" space_views={space_views!r}\n", + # f" layout={layout!r}\n", + # f" root_container={root_container!r}\n", + # f" maximized={maximized!r}\n", + # f" auto_layout={auto_layout!r}\n", + # f" auto_space_views={auto_space_views!r}\n", + ")", + ) + arch = ViewportBlueprint( + space_views, + # layout=layout, + # root_container=root_container, + # maximized=maximized, + # auto_layout=auto_layout, + # auto_space_views=auto_space_views, + ) + print(f"{arch}\n") + + assert arch.space_views == IncludedSpaceViewBatch._optional( + none_empty_or_value(arch.space_views, uuids_arrays[-1]) + )