From 2c2004082f375171896cd8523ba38de8d7c0d430 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 23 May 2024 13:03:35 +0200 Subject: [PATCH] Generate archetype field info (opt-in for a single type so far) and use it in blueprint property ui (#6413) ### What * Part of #6237 * I think the "only" part left now is to use this for all blueprint properties * the tricky bit here is that this is dependent on #4194 This creates an tight nit & generic coupling from our type definitions to the ui! This is to be used in all blueprint properties, so far used on `PlotLegend` only. image Drawbacks: * lower snake case because that's what our fields look like - we could change that easily but there's some value to that because that's what all SDKs use as field names. Very much open for discussion! * some parts of the doc strings might be weird outside of the context of the ui, but I can live with that Future stuff: * we could very very easily now also add reference doc links in there via some linking mechanism (viewer could choose depending on preference or source sdk) ### 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 examples from latest `main` build: [rerun.io/viewer](https://rerun.io/viewer/pr/6413?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [rerun.io/viewer](https://rerun.io/viewer/pr/6413?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/6413) - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) To run all checks from `main`, comment on the PR with `@rerun-bot full-check`. --- Cargo.lock | 1 + crates/re_log_types/src/example_components.rs | 4 + crates/re_space_view/Cargo.toml | 1 + crates/re_space_view/src/view_property_ui.rs | 54 ++-- .../blueprint/archetypes/plot_legend.fbs | 1 + .../re_types/definitions/rust/attributes.fbs | 3 + .../src/archetypes/annotation_context.rs | 5 + crates/re_types/src/archetypes/arrows2d.rs | 5 + crates/re_types/src/archetypes/arrows3d.rs | 5 + crates/re_types/src/archetypes/asset3d.rs | 5 + crates/re_types/src/archetypes/bar_chart.rs | 5 + crates/re_types/src/archetypes/boxes2d.rs | 5 + crates/re_types/src/archetypes/boxes3d.rs | 5 + crates/re_types/src/archetypes/depth_image.rs | 5 + .../src/archetypes/disconnected_space.rs | 5 + crates/re_types/src/archetypes/image.rs | 5 + .../re_types/src/archetypes/line_strips2d.rs | 5 + .../re_types/src/archetypes/line_strips3d.rs | 5 + crates/re_types/src/archetypes/mesh3d.rs | 5 + crates/re_types/src/archetypes/pinhole.rs | 5 + crates/re_types/src/archetypes/points2d.rs | 5 + crates/re_types/src/archetypes/points3d.rs | 5 + crates/re_types/src/archetypes/scalar.rs | 5 + .../src/archetypes/segmentation_image.rs | 5 + crates/re_types/src/archetypes/series_line.rs | 5 + .../re_types/src/archetypes/series_point.rs | 5 + crates/re_types/src/archetypes/tensor.rs | 5 + .../re_types/src/archetypes/text_document.rs | 5 + crates/re_types/src/archetypes/text_log.rs | 5 + crates/re_types/src/archetypes/transform3d.rs | 5 + .../src/archetypes/view_coordinates.rs | 5 + .../src/blueprint/archetypes/background.rs | 5 + .../src/blueprint/archetypes/plot_legend.rs | 27 ++ .../src/blueprint/archetypes/scalar_axis.rs | 5 + .../archetypes/space_view_blueprint.rs | 5 + .../archetypes/space_view_contents.rs | 5 + .../archetypes/visible_time_ranges.rs | 5 + .../blueprint/archetypes/visual_bounds2d.rs | 5 + .../src/testing/archetypes/affix_fuzzer1.rs | 5 + .../src/testing/archetypes/affix_fuzzer2.rs | 5 + .../src/testing/archetypes/affix_fuzzer3.rs | 5 + .../src/testing/archetypes/affix_fuzzer4.rs | 5 + .../archetypes/container_blueprint.rs | 5 + .../blueprint/archetypes/panel_blueprint.rs | 5 + .../archetypes/viewport_blueprint.rs | 5 + crates/re_types_builder/src/casing.rs | 250 ++++++++++++++++++ .../re_types_builder/src/codegen/rust/api.rs | 52 +++- .../re_types_builder/src/codegen/rust/util.rs | 18 +- crates/re_types_builder/src/lib.rs | 171 +----------- crates/re_types_core/src/archetype.rs | 25 ++ crates/re_types_core/src/archetypes/clear.rs | 5 + crates/re_types_core/src/lib.rs | 3 +- crates/re_viewport_blueprint/src/lib.rs | 2 +- .../src/space_view_contents.rs | 7 +- .../src/view_properties.rs | 4 +- .../color_coordinates_visualizer_system.rs | 4 + 56 files changed, 618 insertions(+), 204 deletions(-) create mode 100644 crates/re_types_builder/src/casing.rs diff --git a/Cargo.lock b/Cargo.lock index f20f9252e633..fc168c6f75dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4643,6 +4643,7 @@ dependencies = [ name = "re_space_view" version = "0.17.0-alpha.2" dependencies = [ + "ahash", "egui", "re_data_store", "re_entity_db", diff --git a/crates/re_log_types/src/example_components.rs b/crates/re_log_types/src/example_components.rs index ba9c26b685c3..e47c0edc46c5 100644 --- a/crates/re_log_types/src/example_components.rs +++ b/crates/re_log_types/src/example_components.rs @@ -20,6 +20,10 @@ impl re_types_core::Archetype for MyPoints { "example.MyPoints".into() } + fn display_name() -> &'static str { + "MyPoints" + } + fn required_components() -> ::std::borrow::Cow<'static, [re_types_core::ComponentName]> { vec![MyPoint::name()].into() } diff --git a/crates/re_space_view/Cargo.toml b/crates/re_space_view/Cargo.toml index a54759094ef5..23538deb1168 100644 --- a/crates/re_space_view/Cargo.toml +++ b/crates/re_space_view/Cargo.toml @@ -31,4 +31,5 @@ re_ui.workspace = true re_viewer_context.workspace = true re_viewport_blueprint.workspace = true +ahash.workspace = true egui.workspace = true diff --git a/crates/re_space_view/src/view_property_ui.rs b/crates/re_space_view/src/view_property_ui.rs index b11e5fea970b..5801147cccf5 100644 --- a/crates/re_space_view/src/view_property_ui.rs +++ b/crates/re_space_view/src/view_property_ui.rs @@ -1,3 +1,4 @@ +use ahash::HashMap; use re_types_core::Archetype; use re_ui::list_item; use re_viewer_context::{SpaceViewId, ViewerContext}; @@ -22,34 +23,49 @@ pub fn view_property_ui( component_names.iter().copied(), ); + let field_info_per_component: HashMap<_, _> = A::field_infos() + .map(|field_infos| { + field_infos + .iter() + .cloned() + .map(|field_info| (field_info.component_name, field_info)) + .collect() + }) + .unwrap_or_default(); + let sub_prop_ui = |re_ui: &re_ui::ReUi, ui: &mut egui::Ui| { for component_name in component_names.as_ref() { if component_name.is_indicator_component() { continue; } - list_item::ListItem::new(re_ui) + let field_info = field_info_per_component.get(component_name); + let display_name = + field_info.map_or_else(|| component_name.short_name(), |info| info.display_name); + + let list_item_response = list_item::ListItem::new(re_ui) .interactive(false) .show_flat( ui, - // TODO(andreas): Note that we loose the archetype's field name here, instead we label the item with the component name. - list_item::PropertyContent::new(component_name.short_name()).value_fn( - |_, ui, _| { - ctx.component_ui_registry.edit_ui( - ctx, - ui, - re_viewer_context::UiLayout::List, - blueprint_query, - blueprint_db, - &blueprint_path, - &blueprint_path, - component_results.get_or_empty(*component_name), - component_name, - &0.into(), - ); - }, - ), + list_item::PropertyContent::new(display_name).value_fn(|_, ui, _| { + ctx.component_ui_registry.edit_ui( + ctx, + ui, + re_viewer_context::UiLayout::List, + blueprint_query, + blueprint_db, + &blueprint_path, + &blueprint_path, + component_results.get_or_empty(*component_name), + component_name, + &0.into(), + ); + }), ); + + if let Some(tooltip) = field_info.map(|info| info.documentation) { + list_item_response.on_hover_text(tooltip); + } } }; @@ -59,7 +75,7 @@ pub fn view_property_ui( ui, A::name().full_name(), true, - list_item::LabelContent::new(A::name().short_name()), + list_item::LabelContent::new(A::display_name()), sub_prop_ui, ); } diff --git a/crates/re_types/definitions/rerun/blueprint/archetypes/plot_legend.fbs b/crates/re_types/definitions/rerun/blueprint/archetypes/plot_legend.fbs index 0ddfb7164c67..3d1c43c90b78 100644 --- a/crates/re_types/definitions/rerun/blueprint/archetypes/plot_legend.fbs +++ b/crates/re_types/definitions/rerun/blueprint/archetypes/plot_legend.fbs @@ -14,6 +14,7 @@ namespace rerun.blueprint.archetypes; table PlotLegend ( "attr.rerun.scope": "blueprint", "attr.rust.derive": "Default", + "attr.rust.generate_field_info", "attr.python.aliases": "blueprint_components.Corner2D" ) { // --- Optional --- diff --git a/crates/re_types/definitions/rust/attributes.fbs b/crates/re_types/definitions/rust/attributes.fbs index 889e9aa5f017..74d0493bfc5f 100644 --- a/crates/re_types/definitions/rust/attributes.fbs +++ b/crates/re_types/definitions/rust/attributes.fbs @@ -49,3 +49,6 @@ attribute "attr.rust.override_crate"; /// an object of kind `Blueprint` with `attr.rust.override_crate=re_viewport`, the final /// object will be generated in `crates/re_viewport/src/blueprint`. attribute "attr.rust.serde_type"; + +/// Specify on an archetype to opt-in into generating `ArchetypeFieldInfo` for all fields. +attribute "attr.rust.generate_field_info"; diff --git a/crates/re_types/src/archetypes/annotation_context.rs b/crates/re_types/src/archetypes/annotation_context.rs index 2b45d9ce51c5..6b6ad987375a 100644 --- a/crates/re_types/src/archetypes/annotation_context.rs +++ b/crates/re_types/src/archetypes/annotation_context.rs @@ -124,6 +124,11 @@ impl ::re_types_core::Archetype for AnnotationContext { "rerun.archetypes.AnnotationContext".into() } + #[inline] + fn display_name() -> &'static str { + "Annotation context" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: AnnotationContextIndicator = AnnotationContextIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/arrows2d.rs b/crates/re_types/src/archetypes/arrows2d.rs index 78a6eb25629c..49039e88ee94 100644 --- a/crates/re_types/src/archetypes/arrows2d.rs +++ b/crates/re_types/src/archetypes/arrows2d.rs @@ -152,6 +152,11 @@ impl ::re_types_core::Archetype for Arrows2D { "rerun.archetypes.Arrows2D".into() } + #[inline] + fn display_name() -> &'static str { + "Arrows 2D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Arrows2DIndicator = Arrows2DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/arrows3d.rs b/crates/re_types/src/archetypes/arrows3d.rs index 183826d278cc..35527f55d331 100644 --- a/crates/re_types/src/archetypes/arrows3d.rs +++ b/crates/re_types/src/archetypes/arrows3d.rs @@ -165,6 +165,11 @@ impl ::re_types_core::Archetype for Arrows3D { "rerun.archetypes.Arrows3D".into() } + #[inline] + fn display_name() -> &'static str { + "Arrows 3D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Arrows3DIndicator = Arrows3DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/asset3d.rs b/crates/re_types/src/archetypes/asset3d.rs index 2f5bcd75ffd5..bf13713a3edd 100644 --- a/crates/re_types/src/archetypes/asset3d.rs +++ b/crates/re_types/src/archetypes/asset3d.rs @@ -134,6 +134,11 @@ impl ::re_types_core::Archetype for Asset3D { "rerun.archetypes.Asset3D".into() } + #[inline] + fn display_name() -> &'static str { + "Asset 3D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Asset3DIndicator = Asset3DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/bar_chart.rs b/crates/re_types/src/archetypes/bar_chart.rs index eff2f19f67a1..41b7e2f984e8 100644 --- a/crates/re_types/src/archetypes/bar_chart.rs +++ b/crates/re_types/src/archetypes/bar_chart.rs @@ -105,6 +105,11 @@ impl ::re_types_core::Archetype for BarChart { "rerun.archetypes.BarChart".into() } + #[inline] + fn display_name() -> &'static str { + "Bar chart" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: BarChartIndicator = BarChartIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/boxes2d.rs b/crates/re_types/src/archetypes/boxes2d.rs index 1779da88b05c..d283fd979c78 100644 --- a/crates/re_types/src/archetypes/boxes2d.rs +++ b/crates/re_types/src/archetypes/boxes2d.rs @@ -154,6 +154,11 @@ impl ::re_types_core::Archetype for Boxes2D { "rerun.archetypes.Boxes2D".into() } + #[inline] + fn display_name() -> &'static str { + "Boxes 2D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Boxes2DIndicator = Boxes2DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/boxes3d.rs b/crates/re_types/src/archetypes/boxes3d.rs index 317e50f6ebc9..38cc30cf83c7 100644 --- a/crates/re_types/src/archetypes/boxes3d.rs +++ b/crates/re_types/src/archetypes/boxes3d.rs @@ -165,6 +165,11 @@ impl ::re_types_core::Archetype for Boxes3D { "rerun.archetypes.Boxes3D".into() } + #[inline] + fn display_name() -> &'static str { + "Boxes 3D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Boxes3DIndicator = Boxes3DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/depth_image.rs b/crates/re_types/src/archetypes/depth_image.rs index 9237e478ff24..e746275419b6 100644 --- a/crates/re_types/src/archetypes/depth_image.rs +++ b/crates/re_types/src/archetypes/depth_image.rs @@ -138,6 +138,11 @@ impl ::re_types_core::Archetype for DepthImage { "rerun.archetypes.DepthImage".into() } + #[inline] + fn display_name() -> &'static str { + "Depth image" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: DepthImageIndicator = DepthImageIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/disconnected_space.rs b/crates/re_types/src/archetypes/disconnected_space.rs index 250af687e884..539e0fd8e09a 100644 --- a/crates/re_types/src/archetypes/disconnected_space.rs +++ b/crates/re_types/src/archetypes/disconnected_space.rs @@ -116,6 +116,11 @@ impl ::re_types_core::Archetype for DisconnectedSpace { "rerun.archetypes.DisconnectedSpace".into() } + #[inline] + fn display_name() -> &'static str { + "Disconnected space" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: DisconnectedSpaceIndicator = DisconnectedSpaceIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/image.rs b/crates/re_types/src/archetypes/image.rs index 27a19377dc33..5b41f5d563ef 100644 --- a/crates/re_types/src/archetypes/image.rs +++ b/crates/re_types/src/archetypes/image.rs @@ -126,6 +126,11 @@ impl ::re_types_core::Archetype for Image { "rerun.archetypes.Image".into() } + #[inline] + fn display_name() -> &'static str { + "Image" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: ImageIndicator = ImageIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/line_strips2d.rs b/crates/re_types/src/archetypes/line_strips2d.rs index fa1854bc559c..8c19f00982ea 100644 --- a/crates/re_types/src/archetypes/line_strips2d.rs +++ b/crates/re_types/src/archetypes/line_strips2d.rs @@ -153,6 +153,11 @@ impl ::re_types_core::Archetype for LineStrips2D { "rerun.archetypes.LineStrips2D".into() } + #[inline] + fn display_name() -> &'static str { + "Line strips 2D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: LineStrips2DIndicator = LineStrips2DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/line_strips3d.rs b/crates/re_types/src/archetypes/line_strips3d.rs index b4a3d968db67..cd432819c91b 100644 --- a/crates/re_types/src/archetypes/line_strips3d.rs +++ b/crates/re_types/src/archetypes/line_strips3d.rs @@ -150,6 +150,11 @@ impl ::re_types_core::Archetype for LineStrips3D { "rerun.archetypes.LineStrips3D".into() } + #[inline] + fn display_name() -> &'static str { + "Line strips 3D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: LineStrips3DIndicator = LineStrips3DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/mesh3d.rs b/crates/re_types/src/archetypes/mesh3d.rs index 5e6dcc5dedf9..c0cc43b86608 100644 --- a/crates/re_types/src/archetypes/mesh3d.rs +++ b/crates/re_types/src/archetypes/mesh3d.rs @@ -168,6 +168,11 @@ impl ::re_types_core::Archetype for Mesh3D { "rerun.archetypes.Mesh3D".into() } + #[inline] + fn display_name() -> &'static str { + "Mesh 3D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Mesh3DIndicator = Mesh3DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/pinhole.rs b/crates/re_types/src/archetypes/pinhole.rs index 33372ec6d244..292e354e4fe3 100644 --- a/crates/re_types/src/archetypes/pinhole.rs +++ b/crates/re_types/src/archetypes/pinhole.rs @@ -186,6 +186,11 @@ impl ::re_types_core::Archetype for Pinhole { "rerun.archetypes.Pinhole".into() } + #[inline] + fn display_name() -> &'static str { + "Pinhole" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: PinholeIndicator = PinholeIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/points2d.rs b/crates/re_types/src/archetypes/points2d.rs index a2b4df20574e..2087ed0f3338 100644 --- a/crates/re_types/src/archetypes/points2d.rs +++ b/crates/re_types/src/archetypes/points2d.rs @@ -168,6 +168,11 @@ impl ::re_types_core::Archetype for Points2D { "rerun.archetypes.Points2D".into() } + #[inline] + fn display_name() -> &'static str { + "Points 2D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Points2DIndicator = Points2DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/points3d.rs b/crates/re_types/src/archetypes/points3d.rs index 559e608de088..0ad9a86f67da 100644 --- a/crates/re_types/src/archetypes/points3d.rs +++ b/crates/re_types/src/archetypes/points3d.rs @@ -159,6 +159,11 @@ impl ::re_types_core::Archetype for Points3D { "rerun.archetypes.Points3D".into() } + #[inline] + fn display_name() -> &'static str { + "Points 3D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Points3DIndicator = Points3DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/scalar.rs b/crates/re_types/src/archetypes/scalar.rs index e66d402c1f1e..543942c7a749 100644 --- a/crates/re_types/src/archetypes/scalar.rs +++ b/crates/re_types/src/archetypes/scalar.rs @@ -110,6 +110,11 @@ impl ::re_types_core::Archetype for Scalar { "rerun.archetypes.Scalar".into() } + #[inline] + fn display_name() -> &'static str { + "Scalar" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: ScalarIndicator = ScalarIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/segmentation_image.rs b/crates/re_types/src/archetypes/segmentation_image.rs index 1eddd44df7cd..140b00d05c42 100644 --- a/crates/re_types/src/archetypes/segmentation_image.rs +++ b/crates/re_types/src/archetypes/segmentation_image.rs @@ -130,6 +130,11 @@ impl ::re_types_core::Archetype for SegmentationImage { "rerun.archetypes.SegmentationImage".into() } + #[inline] + fn display_name() -> &'static str { + "Segmentation image" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: SegmentationImageIndicator = SegmentationImageIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/series_line.rs b/crates/re_types/src/archetypes/series_line.rs index cac01e6ad150..556c4b230eae 100644 --- a/crates/re_types/src/archetypes/series_line.rs +++ b/crates/re_types/src/archetypes/series_line.rs @@ -144,6 +144,11 @@ impl ::re_types_core::Archetype for SeriesLine { "rerun.archetypes.SeriesLine".into() } + #[inline] + fn display_name() -> &'static str { + "Series line" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: SeriesLineIndicator = SeriesLineIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/series_point.rs b/crates/re_types/src/archetypes/series_point.rs index 2ad90cc31382..5480d0c9ae18 100644 --- a/crates/re_types/src/archetypes/series_point.rs +++ b/crates/re_types/src/archetypes/series_point.rs @@ -155,6 +155,11 @@ impl ::re_types_core::Archetype for SeriesPoint { "rerun.archetypes.SeriesPoint".into() } + #[inline] + fn display_name() -> &'static str { + "Series point" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: SeriesPointIndicator = SeriesPointIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/tensor.rs b/crates/re_types/src/archetypes/tensor.rs index d667aae4c300..a402853825a7 100644 --- a/crates/re_types/src/archetypes/tensor.rs +++ b/crates/re_types/src/archetypes/tensor.rs @@ -103,6 +103,11 @@ impl ::re_types_core::Archetype for Tensor { "rerun.archetypes.Tensor".into() } + #[inline] + fn display_name() -> &'static str { + "Tensor" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: TensorIndicator = TensorIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/text_document.rs b/crates/re_types/src/archetypes/text_document.rs index e83498516276..22457fe65070 100644 --- a/crates/re_types/src/archetypes/text_document.rs +++ b/crates/re_types/src/archetypes/text_document.rs @@ -152,6 +152,11 @@ impl ::re_types_core::Archetype for TextDocument { "rerun.archetypes.TextDocument".into() } + #[inline] + fn display_name() -> &'static str { + "Text document" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: TextDocumentIndicator = TextDocumentIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/text_log.rs b/crates/re_types/src/archetypes/text_log.rs index 1ce368311b13..bd39d00e1e50 100644 --- a/crates/re_types/src/archetypes/text_log.rs +++ b/crates/re_types/src/archetypes/text_log.rs @@ -130,6 +130,11 @@ impl ::re_types_core::Archetype for TextLog { "rerun.archetypes.TextLog".into() } + #[inline] + fn display_name() -> &'static str { + "Text log" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: TextLogIndicator = TextLogIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/transform3d.rs b/crates/re_types/src/archetypes/transform3d.rs index 0f32a3481740..ccd39f3022aa 100644 --- a/crates/re_types/src/archetypes/transform3d.rs +++ b/crates/re_types/src/archetypes/transform3d.rs @@ -117,6 +117,11 @@ impl ::re_types_core::Archetype for Transform3D { "rerun.archetypes.Transform3D".into() } + #[inline] + fn display_name() -> &'static str { + "Transform 3D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: Transform3DIndicator = Transform3DIndicator::DEFAULT; diff --git a/crates/re_types/src/archetypes/view_coordinates.rs b/crates/re_types/src/archetypes/view_coordinates.rs index 0ec5526a9ec0..161ff9f8b650 100644 --- a/crates/re_types/src/archetypes/view_coordinates.rs +++ b/crates/re_types/src/archetypes/view_coordinates.rs @@ -111,6 +111,11 @@ impl ::re_types_core::Archetype for ViewCoordinates { "rerun.archetypes.ViewCoordinates".into() } + #[inline] + fn display_name() -> &'static str { + "View coordinates" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: ViewCoordinatesIndicator = ViewCoordinatesIndicator::DEFAULT; diff --git a/crates/re_types/src/blueprint/archetypes/background.rs b/crates/re_types/src/blueprint/archetypes/background.rs index e7f56fed6497..f8f3c30beef6 100644 --- a/crates/re_types/src/blueprint/archetypes/background.rs +++ b/crates/re_types/src/blueprint/archetypes/background.rs @@ -81,6 +81,11 @@ impl ::re_types_core::Archetype for Background { "rerun.blueprint.archetypes.Background".into() } + #[inline] + fn display_name() -> &'static str { + "Background" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: BackgroundIndicator = BackgroundIndicator::DEFAULT; diff --git a/crates/re_types/src/blueprint/archetypes/plot_legend.rs b/crates/re_types/src/blueprint/archetypes/plot_legend.rs index bce489f8ff2e..d17a959dd25c 100644 --- a/crates/re_types/src/blueprint/archetypes/plot_legend.rs +++ b/crates/re_types/src/blueprint/archetypes/plot_legend.rs @@ -72,6 +72,23 @@ static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = ] }); +static FIELD_INFOS: once_cell::sync::Lazy<[::re_types_core::ArchetypeFieldInfo; 2usize]> = + once_cell::sync::Lazy::new(|| { + [ + ::re_types_core::ArchetypeFieldInfo { + display_name: "Corner", + documentation: + "To what corner the legend is aligned.\n\nDefaults to the right bottom corner.", + component_name: "rerun.blueprint.components.Corner2D".into(), + }, + ::re_types_core::ArchetypeFieldInfo { + display_name: "Visible", + documentation: "Whether the legend is shown at all.\n\nTrue by default.", + component_name: "rerun.blueprint.components.Visible".into(), + }, + ] + }); + impl PlotLegend { /// The total number of components in the archetype: 0 required, 1 recommended, 2 optional pub const NUM_COMPONENTS: usize = 3usize; @@ -88,6 +105,11 @@ impl ::re_types_core::Archetype for PlotLegend { "rerun.blueprint.archetypes.PlotLegend".into() } + #[inline] + fn display_name() -> &'static str { + "Plot legend" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: PlotLegendIndicator = PlotLegendIndicator::DEFAULT; @@ -114,6 +136,11 @@ impl ::re_types_core::Archetype for PlotLegend { ALL_COMPONENTS.as_slice().into() } + #[inline] + fn field_infos() -> Option<::std::borrow::Cow<'static, [::re_types_core::ArchetypeFieldInfo]>> { + Some(FIELD_INFOS.as_slice().into()) + } + #[inline] fn from_arrow_components( arrow_data: impl IntoIterator)>, diff --git a/crates/re_types/src/blueprint/archetypes/scalar_axis.rs b/crates/re_types/src/blueprint/archetypes/scalar_axis.rs index 06f4cf279c94..d7e2f8f2a790 100644 --- a/crates/re_types/src/blueprint/archetypes/scalar_axis.rs +++ b/crates/re_types/src/blueprint/archetypes/scalar_axis.rs @@ -86,6 +86,11 @@ impl ::re_types_core::Archetype for ScalarAxis { "rerun.blueprint.archetypes.ScalarAxis".into() } + #[inline] + fn display_name() -> &'static str { + "Scalar axis" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: ScalarAxisIndicator = ScalarAxisIndicator::DEFAULT; diff --git a/crates/re_types/src/blueprint/archetypes/space_view_blueprint.rs b/crates/re_types/src/blueprint/archetypes/space_view_blueprint.rs index 3f5164b7e109..155c066b3ac7 100644 --- a/crates/re_types/src/blueprint/archetypes/space_view_blueprint.rs +++ b/crates/re_types/src/blueprint/archetypes/space_view_blueprint.rs @@ -109,6 +109,11 @@ impl ::re_types_core::Archetype for SpaceViewBlueprint { "rerun.blueprint.archetypes.SpaceViewBlueprint".into() } + #[inline] + fn display_name() -> &'static str { + "Space view blueprint" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: SpaceViewBlueprintIndicator = SpaceViewBlueprintIndicator::DEFAULT; diff --git a/crates/re_types/src/blueprint/archetypes/space_view_contents.rs b/crates/re_types/src/blueprint/archetypes/space_view_contents.rs index b1020fe1ac28..dc6be347641e 100644 --- a/crates/re_types/src/blueprint/archetypes/space_view_contents.rs +++ b/crates/re_types/src/blueprint/archetypes/space_view_contents.rs @@ -113,6 +113,11 @@ impl ::re_types_core::Archetype for SpaceViewContents { "rerun.blueprint.archetypes.SpaceViewContents".into() } + #[inline] + fn display_name() -> &'static str { + "Space view contents" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: SpaceViewContentsIndicator = SpaceViewContentsIndicator::DEFAULT; diff --git a/crates/re_types/src/blueprint/archetypes/visible_time_ranges.rs b/crates/re_types/src/blueprint/archetypes/visible_time_ranges.rs index 014d2a0c694a..14d9d4a6d9ed 100644 --- a/crates/re_types/src/blueprint/archetypes/visible_time_ranges.rs +++ b/crates/re_types/src/blueprint/archetypes/visible_time_ranges.rs @@ -84,6 +84,11 @@ impl ::re_types_core::Archetype for VisibleTimeRanges { "rerun.blueprint.archetypes.VisibleTimeRanges".into() } + #[inline] + fn display_name() -> &'static str { + "Visible time ranges" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: VisibleTimeRangesIndicator = VisibleTimeRangesIndicator::DEFAULT; diff --git a/crates/re_types/src/blueprint/archetypes/visual_bounds2d.rs b/crates/re_types/src/blueprint/archetypes/visual_bounds2d.rs index 9beedf88dc7d..fe1b74ab1b9a 100644 --- a/crates/re_types/src/blueprint/archetypes/visual_bounds2d.rs +++ b/crates/re_types/src/blueprint/archetypes/visual_bounds2d.rs @@ -82,6 +82,11 @@ impl ::re_types_core::Archetype for VisualBounds2D { "rerun.blueprint.archetypes.VisualBounds2D".into() } + #[inline] + fn display_name() -> &'static str { + "Visual bounds 2D" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: VisualBounds2DIndicator = VisualBounds2DIndicator::DEFAULT; diff --git a/crates/re_types/src/testing/archetypes/affix_fuzzer1.rs b/crates/re_types/src/testing/archetypes/affix_fuzzer1.rs index 7d2c57801e37..a2a0a4e1f852 100644 --- a/crates/re_types/src/testing/archetypes/affix_fuzzer1.rs +++ b/crates/re_types/src/testing/archetypes/affix_fuzzer1.rs @@ -181,6 +181,11 @@ impl ::re_types_core::Archetype for AffixFuzzer1 { "rerun.testing.archetypes.AffixFuzzer1".into() } + #[inline] + fn display_name() -> &'static str { + "Affix fuzzer 1" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: AffixFuzzer1Indicator = AffixFuzzer1Indicator::DEFAULT; diff --git a/crates/re_types/src/testing/archetypes/affix_fuzzer2.rs b/crates/re_types/src/testing/archetypes/affix_fuzzer2.rs index 51a49dce8e96..fd17a4fee100 100644 --- a/crates/re_types/src/testing/archetypes/affix_fuzzer2.rs +++ b/crates/re_types/src/testing/archetypes/affix_fuzzer2.rs @@ -166,6 +166,11 @@ impl ::re_types_core::Archetype for AffixFuzzer2 { "rerun.testing.archetypes.AffixFuzzer2".into() } + #[inline] + fn display_name() -> &'static str { + "Affix fuzzer 2" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: AffixFuzzer2Indicator = AffixFuzzer2Indicator::DEFAULT; diff --git a/crates/re_types/src/testing/archetypes/affix_fuzzer3.rs b/crates/re_types/src/testing/archetypes/affix_fuzzer3.rs index 9d4dc47431f5..d87072295634 100644 --- a/crates/re_types/src/testing/archetypes/affix_fuzzer3.rs +++ b/crates/re_types/src/testing/archetypes/affix_fuzzer3.rs @@ -161,6 +161,11 @@ impl ::re_types_core::Archetype for AffixFuzzer3 { "rerun.testing.archetypes.AffixFuzzer3".into() } + #[inline] + fn display_name() -> &'static str { + "Affix fuzzer 3" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: AffixFuzzer3Indicator = AffixFuzzer3Indicator::DEFAULT; diff --git a/crates/re_types/src/testing/archetypes/affix_fuzzer4.rs b/crates/re_types/src/testing/archetypes/affix_fuzzer4.rs index 14056381ef2d..ca1236a65cf4 100644 --- a/crates/re_types/src/testing/archetypes/affix_fuzzer4.rs +++ b/crates/re_types/src/testing/archetypes/affix_fuzzer4.rs @@ -161,6 +161,11 @@ impl ::re_types_core::Archetype for AffixFuzzer4 { "rerun.testing.archetypes.AffixFuzzer4".into() } + #[inline] + fn display_name() -> &'static str { + "Affix fuzzer 4" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: AffixFuzzer4Indicator = AffixFuzzer4Indicator::DEFAULT; diff --git a/crates/re_types_blueprint/src/blueprint/archetypes/container_blueprint.rs b/crates/re_types_blueprint/src/blueprint/archetypes/container_blueprint.rs index 7fefd874f484..9938fad09be4 100644 --- a/crates/re_types_blueprint/src/blueprint/archetypes/container_blueprint.rs +++ b/crates/re_types_blueprint/src/blueprint/archetypes/container_blueprint.rs @@ -145,6 +145,11 @@ impl ::re_types_core::Archetype for ContainerBlueprint { "rerun.blueprint.archetypes.ContainerBlueprint".into() } + #[inline] + fn display_name() -> &'static str { + "Container blueprint" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: ContainerBlueprintIndicator = ContainerBlueprintIndicator::DEFAULT; diff --git a/crates/re_types_blueprint/src/blueprint/archetypes/panel_blueprint.rs b/crates/re_types_blueprint/src/blueprint/archetypes/panel_blueprint.rs index 45871049dc8e..1c11d1c1590a 100644 --- a/crates/re_types_blueprint/src/blueprint/archetypes/panel_blueprint.rs +++ b/crates/re_types_blueprint/src/blueprint/archetypes/panel_blueprint.rs @@ -73,6 +73,11 @@ impl ::re_types_core::Archetype for PanelBlueprint { "rerun.blueprint.archetypes.PanelBlueprint".into() } + #[inline] + fn display_name() -> &'static str { + "Panel blueprint" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: PanelBlueprintIndicator = PanelBlueprintIndicator::DEFAULT; diff --git a/crates/re_types_blueprint/src/blueprint/archetypes/viewport_blueprint.rs b/crates/re_types_blueprint/src/blueprint/archetypes/viewport_blueprint.rs index a8c267ddf018..70e5662a63b6 100644 --- a/crates/re_types_blueprint/src/blueprint/archetypes/viewport_blueprint.rs +++ b/crates/re_types_blueprint/src/blueprint/archetypes/viewport_blueprint.rs @@ -119,6 +119,11 @@ impl ::re_types_core::Archetype for ViewportBlueprint { "rerun.blueprint.archetypes.ViewportBlueprint".into() } + #[inline] + fn display_name() -> &'static str { + "Viewport blueprint" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: ViewportBlueprintIndicator = ViewportBlueprintIndicator::DEFAULT; diff --git a/crates/re_types_builder/src/casing.rs b/crates/re_types_builder/src/casing.rs new file mode 100644 index 000000000000..b0074bccdb3a --- /dev/null +++ b/crates/re_types_builder/src/casing.rs @@ -0,0 +1,250 @@ +// --- + +/// Converts a snake or pascal case input into a snake case output. +/// +/// If the input contains multiple parts separated by dots, only the last part is converted. +pub fn to_snake_case(s: &str) -> String { + use convert_case::{Boundary, Converter, Pattern}; + + let rerun_snake = Converter::new() + .set_boundaries(&[ + Boundary::Hyphen, + Boundary::Space, + Boundary::Underscore, + Boundary::Acronym, + Boundary::LowerUpper, + ]) + .set_pattern(Pattern::Lowercase) + .set_delim("_"); + + let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect(); + if let Some(last) = parts.last_mut() { + *last = last.replace("UVec", "uvec").replace("UInt", "uint"); + *last = rerun_snake.convert(&last); + } + parts.join(".") +} + +#[test] +fn test_to_snake_case() { + assert_eq!( + to_snake_case("rerun.components.Position2D"), + "rerun.components.position2d" + ); + assert_eq!( + to_snake_case("rerun.components.position2d"), + "rerun.components.position2d" + ); + + assert_eq!( + to_snake_case("rerun.datatypes.Utf8"), + "rerun.datatypes.utf8" + ); + assert_eq!( + to_snake_case("rerun.datatypes.utf8"), + "rerun.datatypes.utf8" + ); + + assert_eq!( + to_snake_case("rerun.datatypes.UVec2D"), + "rerun.datatypes.uvec2d" + ); + assert_eq!( + to_snake_case("rerun.datatypes.uvec2d"), + "rerun.datatypes.uvec2d" + ); + + assert_eq!( + to_snake_case("rerun.datatypes.UInt32"), + "rerun.datatypes.uint32" + ); + assert_eq!( + to_snake_case("rerun.datatypes.uint32"), + "rerun.datatypes.uint32" + ); + + assert_eq!( + to_snake_case("rerun.archetypes.Points2DIndicator"), + "rerun.archetypes.points2d_indicator" + ); + assert_eq!( + to_snake_case("rerun.archetypes.points2d_indicator"), + "rerun.archetypes.points2d_indicator" + ); + + assert_eq!( + to_snake_case("rerun.components.TranslationAndMat3x3"), + "rerun.components.translation_and_mat3x3" + ); + assert_eq!( + to_snake_case("rerun.components.translation_and_mat3x3"), + "rerun.components.translation_and_mat3x3" + ); + + assert_eq!( + to_snake_case("rerun.components.AnnotationContext"), + "rerun.components.annotation_context" + ); +} + +/// Converts a snake or pascal case input into a pascal case output. +/// +/// If the input contains multiple parts separated by dots, only the last part is converted. +pub fn to_pascal_case(s: &str) -> String { + use convert_case::{Boundary, Converter, Pattern}; + + let rerun_pascal = Converter::new() + .set_boundaries(&[ + Boundary::Hyphen, + Boundary::Space, + Boundary::Underscore, + Boundary::DigitUpper, + Boundary::Acronym, + Boundary::LowerUpper, + ]) + .set_pattern(Pattern::Capital); + + let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect(); + if let Some(last) = parts.last_mut() { + *last = last + .replace("uvec", "UVec") + .replace("uint", "UInt") + .replace("2d", "2D") // NOLINT + .replace("3d", "3D") // NOLINT + .replace("4d", "4D"); + *last = rerun_pascal.convert(&last); + } + parts.join(".") +} + +#[test] +fn test_to_pascal_case() { + assert_eq!( + to_pascal_case("rerun.components.position2d"), + "rerun.components.Position2D" + ); + assert_eq!( + to_pascal_case("rerun.components.Position2D"), + "rerun.components.Position2D" + ); + + assert_eq!( + to_pascal_case("rerun.datatypes.uvec2d"), + "rerun.datatypes.UVec2D" + ); + assert_eq!( + to_pascal_case("rerun.datatypes.UVec2D"), + "rerun.datatypes.UVec2D" + ); + + assert_eq!( + to_pascal_case("rerun.datatypes.uint32"), + "rerun.datatypes.UInt32" + ); + assert_eq!( + to_pascal_case("rerun.datatypes.UInt32"), + "rerun.datatypes.UInt32" + ); + + assert_eq!( + to_pascal_case("rerun.archetypes.points2d_indicator"), + "rerun.archetypes.Points2DIndicator" + ); + assert_eq!( + to_pascal_case("rerun.archetypes.Points2DIndicator"), + "rerun.archetypes.Points2DIndicator" + ); + + assert_eq!( + to_pascal_case("rerun.components.translation_and_mat3x3"), + "rerun.components.TranslationAndMat3x3" + ); + assert_eq!( + to_pascal_case("rerun.components.TranslationAndMat3x3"), + "rerun.components.TranslationAndMat3x3" + ); +} + +/// Converts a snake or pascal case input into "human case" output, i.e. start with upper case and continue with lower case. +/// +/// If the input contains multiple parts separated by dots, only the last part is converted. +pub fn to_human_case(s: &str) -> String { + use convert_case::{Boundary, Converter, Pattern}; + + let rerun_human = Converter::new() + .set_boundaries(&[ + Boundary::Hyphen, + Boundary::Space, + Boundary::Underscore, + Boundary::LowerDigit, + Boundary::Acronym, + Boundary::LowerUpper, + ]) + .set_pattern(Pattern::Sentence) + .set_delim(" "); + + let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect(); + if let Some(last) = parts.last_mut() { + *last = rerun_human.convert(&last); + *last = last + .replace("Uvec", "UVec") + .replace("Uint", "UInt") + .replace("U vec", "UVec") + .replace("U int", "UInt") + .replace("Int 32", "Int32") + .replace("mat 3x 3", "mat3x3") + .replace("mat 4x 4", "mat4x4") + .replace("2d", "2D") // NOLINT + .replace("3d", "3D") // NOLINT + .replace("4d", "4D"); + } + parts.join(".") +} + +#[test] +fn test_to_human_case() { + assert_eq!( + to_human_case("rerun.components.position2d"), + "rerun.components.Position 2D" + ); + assert_eq!( + to_human_case("rerun.components.Position2D"), + "rerun.components.Position 2D" + ); + + assert_eq!( + to_human_case("rerun.datatypes.uvec2d"), + "rerun.datatypes.UVec 2D" + ); + assert_eq!( + to_human_case("rerun.datatypes.UVec2D"), + "rerun.datatypes.UVec 2D" + ); + + assert_eq!( + to_human_case("rerun.datatypes.uint32"), + "rerun.datatypes.UInt32" + ); + assert_eq!( + to_human_case("rerun.datatypes.UInt32"), + "rerun.datatypes.UInt32" + ); + + assert_eq!( + to_human_case("rerun.archetypes.points2d_indicator"), + "rerun.archetypes.Points 2D indicator" + ); + assert_eq!( + to_human_case("rerun.archetypes.Points2DIndicator"), + "rerun.archetypes.Points 2D indicator" + ); + + assert_eq!( + to_human_case("rerun.components.translation_and_mat3x3"), + "rerun.components.Translation and mat3x3" + ); + assert_eq!( + to_human_case("rerun.components.TranslationAndMat3x3"), + "rerun.components.Translation and mat3x3" + ); +} diff --git a/crates/re_types_builder/src/codegen/rust/api.rs b/crates/re_types_builder/src/codegen/rust/api.rs index a67f267bb939..7615a570fe8c 100644 --- a/crates/re_types_builder/src/codegen/rust/api.rs +++ b/crates/re_types_builder/src/codegen/rust/api.rs @@ -26,7 +26,8 @@ use crate::{ ArrowRegistry, CodeGenerator, Docs, ElementType, Object, ObjectField, ObjectKind, Objects, Reporter, Type, ATTR_DEFAULT, ATTR_RERUN_COMPONENT_OPTIONAL, ATTR_RERUN_COMPONENT_RECOMMENDED, ATTR_RERUN_COMPONENT_REQUIRED, ATTR_RERUN_VIEW_IDENTIFIER, ATTR_RUST_CUSTOM_CLAUSE, - ATTR_RUST_DERIVE, ATTR_RUST_DERIVE_ONLY, ATTR_RUST_NEW_PUB_CRATE, ATTR_RUST_REPR, + ATTR_RUST_DERIVE, ATTR_RUST_DERIVE_ONLY, ATTR_RUST_GENERATE_FIELD_INFO, + ATTR_RUST_NEW_PUB_CRATE, ATTR_RUST_REPR, }; use super::{ @@ -1019,6 +1020,7 @@ fn quote_trait_impls_from_obj( fqname, name, kind, .. } = obj; + let display_name = crate::to_human_case(name); let name = format_ident!("{name}"); match kind { @@ -1277,6 +1279,45 @@ fn quote_trait_impls_from_obj( }) }; + let (field_info_array, field_info_getter) = if obj + .is_attr_set(ATTR_RUST_GENERATE_FIELD_INFO) + { + let field_infos = obj.fields.iter().map(|field| { + let display_name = crate::to_human_case(&field.name); + let documentation = field + .docs + .lines_with_tag_matching(|tag| tag.is_empty()) + .join("\n"); + let Some(component_name) = field.typ.fqname() else { + panic!("archetype field must be an object/union or an array/vector of such") + }; + + quote! { + ::re_types_core::ArchetypeFieldInfo { + display_name: #display_name, + documentation: #documentation, + component_name: #component_name.into(), + } + } + }).collect_vec(); + let num_field_infos = field_infos.len(); + + let field_info_array = quote! { + static FIELD_INFOS: once_cell::sync::Lazy<[::re_types_core::ArchetypeFieldInfo; #num_field_infos]> = + once_cell::sync::Lazy::new(|| {[#(#field_infos,)*]}); + }; + let field_info_getter = quote! { + #[inline] + fn field_infos() -> Option<::std::borrow::Cow<'static, [::re_types_core::ArchetypeFieldInfo]>> { + Some(FIELD_INFOS.as_slice().into()) + } + }; + + (field_info_array, field_info_getter) + } else { + (quote!(), quote!()) + }; + quote! { static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; #num_required]> = once_cell::sync::Lazy::new(|| {[#required]}); @@ -1290,6 +1331,8 @@ fn quote_trait_impls_from_obj( static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; #num_all]> = once_cell::sync::Lazy::new(|| {[#required #recommended #optional]}); + #field_info_array + impl #name { #num_components_docstring pub const NUM_COMPONENTS: usize = #num_all; @@ -1306,6 +1349,11 @@ fn quote_trait_impls_from_obj( #fqname.into() } + #[inline] + fn display_name() -> &'static str { + #display_name + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: #quoted_indicator_name = #quoted_indicator_name::DEFAULT; @@ -1333,6 +1381,8 @@ fn quote_trait_impls_from_obj( ALL_COMPONENTS.as_slice().into() } + #field_info_getter + #[inline] fn from_arrow_components( arrow_data: impl IntoIterator( requirement_attr_value: &'static str, ) -> impl Iterator + 'a { assert_eq!(ObjectKind::Archetype, obj.kind); + obj.fields.iter().filter_map(move |field| { field .try_get_attr::(requirement_attr_value) - .map(|_| match &field.typ { - Type::Object(fqname) => fqname.clone(), - Type::Vector { elem_type } => match elem_type { - ElementType::Object(fqname) => fqname.clone(), - _ => { - panic!("archetype field must be an object/union or an array/vector of such") - } - }, - _ => panic!("archetype field must be an object/union or an array/vector of such"), + .map(|_| { + if let Some(fqname) = field.typ.fqname() { + fqname.to_owned() + } else { + panic!("Archetype field must be an object/union or an array/vector of such") + } }) }) } diff --git a/crates/re_types_builder/src/lib.rs b/crates/re_types_builder/src/lib.rs index cd3c688e741a..f8347f6657c6 100644 --- a/crates/re_types_builder/src/lib.rs +++ b/crates/re_types_builder/src/lib.rs @@ -104,6 +104,7 @@ #![allow(clippy::unwrap_used)] // NOTE: Official generated code from flatbuffers; ignore _everything_. +mod casing; #[allow( warnings, unused, @@ -116,6 +117,8 @@ )] mod reflection; +use casing::{to_human_case, to_pascal_case, to_snake_case}; + use std::collections::{BTreeMap, BTreeSet}; use anyhow::Context as _; @@ -194,6 +197,7 @@ pub const ATTR_RUST_OVERRIDE_CRATE: &str = "attr.rust.override_crate"; pub const ATTR_RUST_REPR: &str = "attr.rust.repr"; pub const ATTR_RUST_SERDE_TYPE: &str = "attr.rust.serde_type"; pub const ATTR_RUST_TUPLE_STRUCT: &str = "attr.rust.tuple_struct"; +pub const ATTR_RUST_GENERATE_FIELD_INFO: &str = "attr.rust.generate_field_info"; pub const ATTR_CPP_NO_FIELD_CTORS: &str = "attr.cpp.no_field_ctors"; @@ -591,174 +595,7 @@ pub(crate) fn rerun_workspace_path() -> camino::Utf8PathBuf { workspace_root.canonicalize_utf8().unwrap() } -// --- - -/// Converts a snake or pascal case input into a snake case output. -/// -/// If the input contains multiple parts separated by dots, only the last part is converted. -pub(crate) fn to_snake_case(s: &str) -> String { - use convert_case::{Boundary, Converter, Pattern}; - - let rerun_snake = Converter::new() - .set_boundaries(&[ - Boundary::Hyphen, - Boundary::Space, - Boundary::Underscore, - Boundary::Acronym, - Boundary::LowerUpper, - ]) - .set_pattern(Pattern::Lowercase) - .set_delim("_"); - - let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect(); - if let Some(last) = parts.last_mut() { - *last = last.replace("UVec", "uvec").replace("UInt", "uint"); - *last = rerun_snake.convert(&last); - } - parts.join(".") -} - -#[test] -fn test_to_snake_case() { - assert_eq!( - to_snake_case("rerun.components.Position2D"), - "rerun.components.position2d" - ); - assert_eq!( - to_snake_case("rerun.components.position2d"), - "rerun.components.position2d" - ); - - assert_eq!( - to_snake_case("rerun.datatypes.Utf8"), - "rerun.datatypes.utf8" - ); - assert_eq!( - to_snake_case("rerun.datatypes.utf8"), - "rerun.datatypes.utf8" - ); - - assert_eq!( - to_snake_case("rerun.datatypes.UVec2D"), - "rerun.datatypes.uvec2d" - ); - assert_eq!( - to_snake_case("rerun.datatypes.uvec2d"), - "rerun.datatypes.uvec2d" - ); - - assert_eq!( - to_snake_case("rerun.datatypes.UInt32"), - "rerun.datatypes.uint32" - ); - assert_eq!( - to_snake_case("rerun.datatypes.uint32"), - "rerun.datatypes.uint32" - ); - - assert_eq!( - to_snake_case("rerun.archetypes.Points2DIndicator"), - "rerun.archetypes.points2d_indicator" - ); - assert_eq!( - to_snake_case("rerun.archetypes.points2d_indicator"), - "rerun.archetypes.points2d_indicator" - ); - - assert_eq!( - to_snake_case("rerun.components.TranslationAndMat3x3"), - "rerun.components.translation_and_mat3x3" - ); - assert_eq!( - to_snake_case("rerun.components.translation_and_mat3x3"), - "rerun.components.translation_and_mat3x3" - ); - - assert_eq!( - to_snake_case("rerun.components.AnnotationContext"), - "rerun.components.annotation_context" - ); -} - -/// Converts a snake or pascal case input into a pascal case output. -/// -/// If the input contains multiple parts separated by dots, only the last part is converted. -pub(crate) fn to_pascal_case(s: &str) -> String { - use convert_case::{Boundary, Converter, Pattern}; - - let rerun_snake = Converter::new() - .set_boundaries(&[ - Boundary::Hyphen, - Boundary::Space, - Boundary::Underscore, - Boundary::DigitUpper, - Boundary::Acronym, - Boundary::LowerUpper, - ]) - .set_pattern(Pattern::Capital); - - let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect(); - if let Some(last) = parts.last_mut() { - *last = last - .replace("uvec", "UVec") - .replace("uint", "UInt") - .replace("2d", "2D") // NOLINT - .replace("3d", "3D") // NOLINT - .replace("4d", "4D"); - *last = rerun_snake.convert(&last); - } - parts.join(".") -} - /// Format the path with forward slashes, even on Windows. pub(crate) fn format_path(path: impl AsRef) -> String { path.as_ref().as_str().replace('\\', "/") } - -#[test] -fn test_to_pascal_case() { - assert_eq!( - to_pascal_case("rerun.components.position2d"), - "rerun.components.Position2D" - ); - assert_eq!( - to_pascal_case("rerun.components.Position2D"), - "rerun.components.Position2D" - ); - - assert_eq!( - to_pascal_case("rerun.datatypes.uvec2d"), - "rerun.datatypes.UVec2D" - ); - assert_eq!( - to_pascal_case("rerun.datatypes.UVec2D"), - "rerun.datatypes.UVec2D" - ); - - assert_eq!( - to_pascal_case("rerun.datatypes.uint32"), - "rerun.datatypes.UInt32" - ); - assert_eq!( - to_pascal_case("rerun.datatypes.UInt32"), - "rerun.datatypes.UInt32" - ); - - assert_eq!( - to_pascal_case("rerun.archetypes.points2d_indicator"), - "rerun.archetypes.Points2DIndicator" - ); - assert_eq!( - to_pascal_case("rerun.archetypes.Points2DIndicator"), - "rerun.archetypes.Points2DIndicator" - ); - - assert_eq!( - to_pascal_case("rerun.components.translation_and_mat3x3"), - "rerun.components.TranslationAndMat3x3" - ); - assert_eq!( - to_pascal_case("rerun.components.TranslationAndMat3x3"), - "rerun.components.TranslationAndMat3x3" - ); -} diff --git a/crates/re_types_core/src/archetype.rs b/crates/re_types_core/src/archetype.rs index 23c2337d9b0a..504e30a5e8ed 100644 --- a/crates/re_types_core/src/archetype.rs +++ b/crates/re_types_core/src/archetype.rs @@ -10,6 +10,19 @@ use crate::{Component, Loggable, LoggableBatch}; // --- +/// Additional information about an archetype's field. +#[derive(Debug, Clone)] +pub struct ArchetypeFieldInfo { + /// The name of the field in human case. + pub display_name: &'static str, + + /// Documentation string for the field (not the component type). + pub documentation: &'static str, + + /// The component name of the field's type. + pub component_name: ComponentName, +} + /// An archetype is a high-level construct that represents a set of [`Component`]s that usually /// play well with each other (i.e. they compose nicely). /// @@ -42,6 +55,9 @@ pub trait Archetype { /// The fully-qualified name of this archetype, e.g. `rerun.archetypes.Points2D`. fn name() -> ArchetypeName; + /// Readable name for displaying in ui. + fn display_name() -> &'static str; + // --- // TODO(cmc): Should we also generate and return static IntSets? @@ -93,6 +109,15 @@ pub trait Archetype { .into() } + /// Returns information about the archetype's fields. + ///s + /// This is optional and not implemented by all archetypes. + /// If present, it can be used to display additional information in the viewer. + #[inline] + fn field_infos() -> Option<::std::borrow::Cow<'static, [ArchetypeFieldInfo]>> { + None + } + // --- /// Given an iterator of Arrow arrays and their respective field metadata, deserializes them diff --git a/crates/re_types_core/src/archetypes/clear.rs b/crates/re_types_core/src/archetypes/clear.rs index 9c26eeb918c2..5445e2a34d53 100644 --- a/crates/re_types_core/src/archetypes/clear.rs +++ b/crates/re_types_core/src/archetypes/clear.rs @@ -127,6 +127,11 @@ impl crate::Archetype for Clear { "rerun.archetypes.Clear".into() } + #[inline] + fn display_name() -> &'static str { + "Clear" + } + #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { static INDICATOR: ClearIndicator = ClearIndicator::DEFAULT; diff --git a/crates/re_types_core/src/lib.rs b/crates/re_types_core/src/lib.rs index f9a84bdcafc4..d47cea4abb95 100644 --- a/crates/re_types_core/src/lib.rs +++ b/crates/re_types_core/src/lib.rs @@ -83,7 +83,8 @@ mod tuid; mod view; pub use self::archetype::{ - Archetype, ArchetypeName, GenericIndicatorComponent, NamedIndicatorComponent, + Archetype, ArchetypeFieldInfo, ArchetypeName, GenericIndicatorComponent, + NamedIndicatorComponent, }; pub use self::loggable::{ Component, ComponentName, ComponentNameSet, Datatype, DatatypeName, Loggable, diff --git a/crates/re_viewport_blueprint/src/lib.rs b/crates/re_viewport_blueprint/src/lib.rs index 22b8ae18cfab..66ec113ae9b1 100644 --- a/crates/re_viewport_blueprint/src/lib.rs +++ b/crates/re_viewport_blueprint/src/lib.rs @@ -6,7 +6,7 @@ mod container; mod space_view; mod space_view_contents; mod tree_actions; -mod view_properties; // TODO(andreas): better name before `sub_archetype` sticks around? +mod view_properties; mod viewport_blueprint; pub use container::ContainerBlueprint; diff --git a/crates/re_viewport_blueprint/src/space_view_contents.rs b/crates/re_viewport_blueprint/src/space_view_contents.rs index 1d2816df9e09..7b172d86cd64 100644 --- a/crates/re_viewport_blueprint/src/space_view_contents.rs +++ b/crates/re_viewport_blueprint/src/space_view_contents.rs @@ -20,7 +20,7 @@ use re_viewer_context::{ SpaceViewClassRegistry, SpaceViewId, ViewerContext, VisualizableEntities, }; -use crate::{query_view_property, SpaceViewBlueprint}; +use crate::SpaceViewBlueprint; pub struct EntityOverrideContext<'a> { pub legacy_space_view_properties: EntityProperties, @@ -108,8 +108,9 @@ impl SpaceViewContents { space_view_class_identifier: SpaceViewClassIdentifier, space_env: &EntityPathSubs, ) -> Self { - let (contents, blueprint_entity_path) = - query_view_property::(id, blueprint_db, query); + let (contents, blueprint_entity_path) = crate::query_view_property::< + blueprint_archetypes::SpaceViewContents, + >(id, blueprint_db, query); let blueprint_archetypes::SpaceViewContents { query } = match contents { PromiseResult::Pending => { diff --git a/crates/re_viewport_blueprint/src/view_properties.rs b/crates/re_viewport_blueprint/src/view_properties.rs index 6ed3e6fdae17..9a137a3688f1 100644 --- a/crates/re_viewport_blueprint/src/view_properties.rs +++ b/crates/re_viewport_blueprint/src/view_properties.rs @@ -1,11 +1,11 @@ use re_data_store::LatestAtQuery; use re_entity_db::{ external::re_query::{LatestAtResults, PromiseResult, ToArchetype}, - EntityDb, EntityTree, + EntityDb, }; use re_log_types::EntityPath; use re_types::Archetype; -use re_viewer_context::{SpaceViewId, ViewerContext}; +use re_viewer_context::{external::re_entity_db::EntityTree, SpaceViewId, ViewerContext}; pub fn entity_path_for_view_property( space_view_id: SpaceViewId, diff --git a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs index 01f85e2f2faa..dbe217a2944e 100644 --- a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs +++ b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs @@ -29,6 +29,10 @@ impl re_types::Archetype for ColorArchetype { "InstanceColor".into() } + fn display_name() -> &'static str { + "Instance Color" + } + fn required_components() -> ::std::borrow::Cow<'static, [ComponentName]> { vec![re_types::components::Color::name()].into() }