From 27cb69f8d95da5268fa971d7e9f03e97bcab2034 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler <49431240+abey79@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:19:11 +0200 Subject: [PATCH] Query editor for the dataframe view (#7071) ### What - Fixes https://github.com/rerun-io/rerun/issues/7065 - Supersedes #6961 This PR introduce a new blueprint archetype and related bespoke UI to configure the query underlying a dataframe view. As a consequence of this new scheme, Visible Time Range is no longer shown in dataframe view selection panel. image ### 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/7071?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/7071?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)! * [x] If have noted any breaking changes to the log API in `CHANGELOG.md` and the migration guide - [PR Build Summary](https://build.rerun.io/pr/7071) - [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 | 2 +- crates/store/re_types/Cargo.toml | 1 + .../rerun/blueprint/archetypes.fbs | 2 +- .../blueprint/archetypes/dataframe_query.fbs | 52 +++ .../archetypes/dataframe_view_mode.fbs | 14 - .../rerun/blueprint/components.fbs | 5 +- .../components/dataframe_view_mode.fbs | 21 -- .../components/latest_at_queries.fbs | 14 + .../rerun/blueprint/components/query_kind.fbs | 16 + .../components/time_range_queries.fbs | 14 + .../blueprint/components/timeline_name.fbs | 14 + .../definitions/rerun/blueprint/datatypes.fbs | 2 + .../blueprint/datatypes/latest_at_query.fbs | 15 + .../blueprint/datatypes/time_range_query.fbs | 18 + .../src/blueprint/archetypes/.gitattributes | 2 +- .../blueprint/archetypes/dataframe_query.rs | 275 ++++++++++++++ .../archetypes/dataframe_view_mode.rs | 163 --------- .../re_types/src/blueprint/archetypes/mod.rs | 4 +- .../src/blueprint/components/.gitattributes | 5 +- .../blueprint/components/latest_at_queries.rs | 183 ++++++++++ .../components/latest_at_queries_ext.rs | 22 ++ .../re_types/src/blueprint/components/mod.rs | 13 +- .../{dataframe_view_mode.rs => query_kind.rs} | 39 +- .../components/time_range_queries.rs | 183 ++++++++++ .../components/time_range_queries_ext.rs | 22 ++ .../src/blueprint/components/timeline_name.rs | 105 ++++++ .../blueprint/components/timeline_name_ext.rs | 22 ++ .../src/blueprint/datatypes/.gitattributes | 2 + .../blueprint/datatypes/latest_at_query.rs | 284 +++++++++++++++ .../datatypes/latest_at_query_ext.rs | 12 + .../re_types/src/blueprint/datatypes/mod.rs | 6 + .../blueprint/datatypes/time_range_query.rs | 343 ++++++++++++++++++ .../datatypes/time_range_query_ext.rs | 12 + crates/viewer/re_edit_ui/src/lib.rs | 8 +- crates/viewer/re_edit_ui/src/timeline.rs | 38 ++ crates/viewer/re_selection_panel/Cargo.toml | 1 - .../src/visible_time_range_ui.rs | 2 - .../src/latest_at_table.rs | 20 +- .../viewer/re_space_view_dataframe/src/lib.rs | 2 + .../src/query_kind_ui.rs | 214 +++++++++++ .../src/space_view_class.rs | 139 +++---- .../src/time_range_table.rs | 49 ++- .../re_space_view_dataframe/src/utils.rs | 2 +- .../re_space_view_dataframe/src/view_query.rs | 287 +++++++++++++++ .../src/blueprint/validation_gen/mod.rs | 10 +- crates/viewer/re_viewer/src/reflection/mod.rs | 58 ++- .../re_viewer_context/src/time_drag_value.rs | 2 +- .../src/view_properties.rs | 10 +- rerun_cpp/src/rerun/blueprint/archetypes.hpp | 2 +- .../rerun/blueprint/archetypes/.gitattributes | 4 +- .../blueprint/archetypes/dataframe_query.cpp | 49 +++ .../blueprint/archetypes/dataframe_query.hpp | 107 ++++++ .../archetypes/dataframe_view_mode.cpp | 34 -- .../archetypes/dataframe_view_mode.hpp | 58 --- rerun_cpp/src/rerun/blueprint/components.hpp | 5 +- .../rerun/blueprint/components/.gitattributes | 9 +- .../components/latest_at_queries.cpp | 81 +++++ .../components/latest_at_queries.hpp | 65 ++++ ...dataframe_view_mode.cpp => query_kind.cpp} | 29 +- ...dataframe_view_mode.hpp => query_kind.hpp} | 25 +- .../components/time_range_queries.cpp | 81 +++++ .../components/time_range_queries.hpp | 65 ++++ .../blueprint/components/timeline_name.hpp | 63 ++++ rerun_cpp/src/rerun/blueprint/datatypes.hpp | 2 + .../rerun/blueprint/datatypes/.gitattributes | 4 + .../blueprint/datatypes/latest_at_query.cpp | 86 +++++ .../blueprint/datatypes/latest_at_query.hpp | 56 +++ .../blueprint/datatypes/time_range_query.cpp | 98 +++++ .../blueprint/datatypes/time_range_query.hpp | 59 +++ .../rerun/blueprint/archetypes/.gitattributes | 2 +- .../rerun/blueprint/archetypes/__init__.py | 4 +- .../blueprint/archetypes/dataframe_query.py | 123 +++++++ .../archetypes/dataframe_view_mode.py | 65 ---- .../rerun/blueprint/components/.gitattributes | 5 +- .../rerun/blueprint/components/__init__.py | 46 ++- .../components/dataframe_view_mode.py | 90 ----- .../blueprint/components/latest_at_queries.py | 88 +++++ .../rerun/blueprint/components/query_kind.py | 75 ++++ .../components/time_range_queries.py | 89 +++++ .../blueprint/components/timeline_name.py | 36 ++ .../rerun/blueprint/datatypes/.gitattributes | 2 + .../rerun/blueprint/datatypes/__init__.py | 24 ++ .../blueprint/datatypes/latest_at_query.py | 100 +++++ .../datatypes/latest_at_query_ext.py | 17 + .../blueprint/datatypes/time_range_query.py | 117 ++++++ .../datatypes/time_range_query_ext.py | 24 ++ 86 files changed, 3941 insertions(+), 677 deletions(-) create mode 100644 crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs delete mode 100644 crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs delete mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs create mode 100644 crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs delete mode 100644 crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs create mode 100644 crates/store/re_types/src/blueprint/components/latest_at_queries.rs create mode 100644 crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs rename crates/store/re_types/src/blueprint/components/{dataframe_view_mode.rs => query_kind.rs} (71%) create mode 100644 crates/store/re_types/src/blueprint/components/time_range_queries.rs create mode 100644 crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs create mode 100644 crates/store/re_types/src/blueprint/components/timeline_name.rs create mode 100644 crates/store/re_types/src/blueprint/components/timeline_name_ext.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/time_range_query.rs create mode 100644 crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs create mode 100644 crates/viewer/re_edit_ui/src/timeline.rs create mode 100644 crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs create mode 100644 crates/viewer/re_space_view_dataframe/src/view_query.rs create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp delete mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp delete mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp rename rerun_cpp/src/rerun/blueprint/components/{dataframe_view_mode.cpp => query_kind.cpp} (67%) rename rerun_cpp/src/rerun/blueprint/components/{dataframe_view_mode.hpp => query_kind.hpp} (59%) create mode 100644 rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/timeline_name.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py delete mode 100644 rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py delete mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py diff --git a/Cargo.lock b/Cargo.lock index ef203d614ee1..2b4650374dd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4858,7 +4858,6 @@ dependencies = [ "re_log", "re_log_types", "re_space_view", - "re_space_view_dataframe", "re_space_view_spatial", "re_space_view_time_series", "re_tracing", @@ -5154,6 +5153,7 @@ dependencies = [ "re_build_tools", "re_format", "re_log", + "re_log_types", "re_tracing", "re_types_builder", "re_types_core", diff --git a/crates/store/re_types/Cargo.toml b/crates/store/re_types/Cargo.toml index 3ba68c8b578b..74bb2546817f 100644 --- a/crates/store/re_types/Cargo.toml +++ b/crates/store/re_types/Cargo.toml @@ -51,6 +51,7 @@ testing = [] # Rerun re_format.workspace = true re_log.workspace = true +re_log_types.workspace = true re_tracing.workspace = true re_types_core.workspace = true diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs index b5fefe42a8c6..f6e6710b96b3 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes.fbs @@ -2,7 +2,7 @@ include "./archetypes/background.fbs"; include "./archetypes/container_blueprint.fbs"; -include "./archetypes/dataframe_view_mode.fbs"; +include "./archetypes/dataframe_query.fbs"; include "./archetypes/panel_blueprint.fbs"; include "./archetypes/plot_legend.fbs"; include "./archetypes/scalar_axis.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs new file mode 100644 index 000000000000..537da475465f --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs @@ -0,0 +1,52 @@ +namespace rerun.blueprint.archetypes; + + +// Rationale behind the present data modelling: +// - Avoid using `union` at all cost. +// - An explicit "mode" enum maps well with a UI toggle and API parameter, and enabled a hard disambiguation when +// settings are present for both the latest at and range modes. +// - Timestamps are hard-invalidated by a change of timeline. So we keep them on a per-timeline basis. + +// TODO(#7067): add visible components (maybe in another archetype?) +// TODO(#7072): add (optional) PoV components +// Note: component list should be modelled as: +// component PovComponents { +// datatype ComponentNames { +// value: [string]; +// } +// } +// +// Motivation: +// - Chances are high that the user prefers to have their pov components _not_ invalidated by a changeof timeline. +// - That is even though a component might _technically_ be soft-invalidated by a change of timeline (e.g. if it was +// not logged on that particular timeline). But we have to deal regardless with potentially invalid component, so this +// doesn't change the story much. + +// -- + +/// The query for the dataframe view. +table DataframeQuery ( + "attr.rerun.scope": "blueprint", + "attr.rust.generate_field_info" +) { + // --- Optional --- + + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + timeline: rerun.blueprint.components.TimelineName ("attr.rerun.component_optional", nullable, order: 100); + + /// Kind of query: latest-at or range. + kind: rerun.blueprint.components.QueryKind ("attr.rerun.component_optional", nullable,order: 200); + + /// Configuration for latest-at queries. + /// + /// Note: configuration as saved on a per-timeline basis. + latest_at_queries: rerun.blueprint.components.LatestAtQueries ("attr.rerun.component_optional", nullable,order: 400); + + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. + time_range_queries: rerun.blueprint.components.TimeRangeQueries ("attr.rerun.component_optional", nullable,order: 500); +} + diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs deleted file mode 100644 index 86dba394426f..000000000000 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs +++ /dev/null @@ -1,14 +0,0 @@ -namespace rerun.blueprint.archetypes; - - -/// Configuration for the dataframe view -table DataframeViewMode ( - "attr.rerun.scope": "blueprint", - "attr.rust.derive": "Copy", - "attr.rust.generate_field_info" -) { - // --- Optional --- - - /// The kind of table to display - mode: rerun.blueprint.components.DataframeViewMode ("attr.rerun.component_optional", nullable, order: 1000); -} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components.fbs b/crates/store/re_types/definitions/rerun/blueprint/components.fbs index 1c1fb76aa8fc..95262a56a7e0 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components.fbs @@ -7,14 +7,15 @@ include "./components/background_kind.fbs"; include "./components/column_share.fbs"; include "./components/container_kind.fbs"; include "./components/corner_2d.fbs"; -include "./components/dataframe_view_mode.fbs"; include "./components/grid_columns.fbs"; include "./components/included_content.fbs"; include "./components/included_space_view.fbs"; include "./components/interactive.fbs"; +include "./components/latest_at_queries.fbs"; include "./components/lock_range_during_zoom.fbs"; include "./components/panel_state.fbs"; include "./components/query_expression.fbs"; +include "./components/query_kind.fbs"; include "./components/root_container.fbs"; include "./components/row_share.fbs"; include "./components/sort_key.fbs"; @@ -23,6 +24,8 @@ include "./components/space_view_class.fbs"; include "./components/space_view_maximized.fbs"; include "./components/space_view_origin.fbs"; include "./components/tensor_dimension_index_slider.fbs"; +include "./components/time_range_queries.fbs"; +include "./components/timeline_name.fbs"; include "./components/view_fit.fbs"; include "./components/viewer_recommendation_hash.fbs"; include "./components/visible.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs deleted file mode 100644 index 10b48a1258b0..000000000000 --- a/crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs +++ /dev/null @@ -1,21 +0,0 @@ -namespace rerun.blueprint.components; - - -/// The kind of table displayed by the dataframe view -enum DataframeViewMode: ubyte ( - "attr.rerun.scope": "blueprint" -) { - /// Invalid value. Won't show up in generated types. - Invalid = 0, - - /// Display the entity values at the current time. - /// - /// In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. - LatestAt (default), - - /// Display a temporal table of entity values. - /// - /// In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - /// timestamp shown are determined by each view entity's visible time range setting. - TimeRange, -} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs new file mode 100644 index 000000000000..2ae62a030694 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs @@ -0,0 +1,14 @@ + +namespace rerun.blueprint.components; + +/// Configuration for latest at queries. +/// +/// Note: configuration as saved on a per-timeline basis. +table LatestAtQueries ( + "attr.arrow.transparent", + "attr.rust.derive": "Default, PartialEq, Eq", + "attr.rust.repr": "transparent", + "attr.rerun.scope": "blueprint" +) { + queries: [rerun.blueprint.datatypes.LatestAtQuery] (order: 100); +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs new file mode 100644 index 000000000000..b4c91f52601a --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs @@ -0,0 +1,16 @@ +namespace rerun.blueprint.components; + + +/// The kind of query displayed by the dataframe view +enum QueryKind: ubyte ( + "attr.rerun.scope": "blueprint" +) { + /// Invalid value. Won't show up in generated types. + Invalid = 0, + + /// Query + LatestAt (default), + + /// Time range query. + TimeRange, +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs new file mode 100644 index 000000000000..cfa60cd84d57 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs @@ -0,0 +1,14 @@ + +namespace rerun.blueprint.components; + +/// Configuration for time range queries. +/// +/// Note: configuration as saved on a per-timeline basis. +table TimeRangeQueries ( + "attr.arrow.transparent", + "attr.rust.derive": "Default, PartialEq, Eq", + "attr.rust.repr": "transparent", + "attr.rerun.scope": "blueprint" +) { + queries: [rerun.blueprint.datatypes.TimeRangeQuery] (order: 100); +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs new file mode 100644 index 000000000000..ef03400d2a92 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs @@ -0,0 +1,14 @@ + +namespace rerun.blueprint.components; + +/// A timeline identified by its name. +table TimelineName ( + "attr.arrow.transparent", + "attr.python.aliases": "str", + "attr.python.array_aliases": "str, Sequence[str]", + "attr.rust.derive": "PartialEq, Eq, PartialOrd, Ord", + "attr.rust.repr": "transparent", + "attr.rerun.scope": "blueprint" +) { + value: rerun.datatypes.Utf8 (order: 100); +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs index 5aaad0c14271..27ed9388ebd5 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes.fbs @@ -1,4 +1,6 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/fbs/mod.rs +include "./datatypes/latest_at_query.fbs"; include "./datatypes/tensor_dimension_index_slider.fbs"; +include "./datatypes/time_range_query.fbs"; include "./datatypes/utf8_list.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs new file mode 100644 index 000000000000..eb03f3361352 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs @@ -0,0 +1,15 @@ +namespace rerun.blueprint.datatypes; + + +/// Latest at query configuration for a specific timeline. +// Has to be a table because flatbuffer doesn't support strings in structs. +table LatestAtQuery ( + "attr.rust.derive": "PartialEq, Eq", + "attr.rerun.scope": "blueprint" +) { + /// Name of the timeline this applies to. + timeline: rerun.datatypes.Utf8 (order: 100); + + /// Time value to use for this query. + time: rerun.datatypes.TimeInt (order: 200); +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs new file mode 100644 index 000000000000..6b467209e580 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs @@ -0,0 +1,18 @@ +namespace rerun.blueprint.datatypes; + + +/// Time range query configuration for a specific timeline. +// Has to be a table because flatbuffer doesn't support strings in structs. +table TimeRangeQuery ( + "attr.rust.derive": "PartialEq, Eq", + "attr.rerun.scope": "blueprint" +) { + /// Name of the timeline this applies to. + timeline: rerun.datatypes.Utf8 (order: 100); + + /// Beginning of the time range. + start: rerun.datatypes.TimeInt (order: 200); + + /// End of the time range (inclusive). + end: rerun.datatypes.TimeInt (order: 300); +} diff --git a/crates/store/re_types/src/blueprint/archetypes/.gitattributes b/crates/store/re_types/src/blueprint/archetypes/.gitattributes index d91f6e760346..51fc7263ee37 100644 --- a/crates/store/re_types/src/blueprint/archetypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/archetypes/.gitattributes @@ -2,7 +2,7 @@ .gitattributes linguist-generated=true background.rs linguist-generated=true -dataframe_view_mode.rs linguist-generated=true +dataframe_query.rs linguist-generated=true mod.rs linguist-generated=true plot_legend.rs linguist-generated=true scalar_axis.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs new file mode 100644 index 000000000000..635e3ee6992d --- /dev/null +++ b/crates/store/re_types/src/blueprint/archetypes/dataframe_query.rs @@ -0,0 +1,275 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +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}; + +/// **Archetype**: The query for the dataframe view. +#[derive(Clone, Debug)] +pub struct DataframeQuery { + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + pub timeline: Option, + + /// Kind of query: latest-at or range. + pub kind: Option, + + /// Configuration for latest-at queries. + /// + /// Note: configuration as saved on a per-timeline basis. + pub latest_at_queries: Option, + + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. + pub time_range_queries: Option, +} + +impl ::re_types_core::SizeBytes for DataframeQuery { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.timeline.heap_size_bytes() + + self.kind.heap_size_bytes() + + self.latest_at_queries.heap_size_bytes() + + self.time_range_queries.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + && >::is_pod() + && >::is_pod() + && >::is_pod() + } +} + +static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = + once_cell::sync::Lazy::new(|| []); + +static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.DataframeQueryIndicator".into()]); + +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.blueprint.components.TimelineName".into(), + "rerun.blueprint.components.QueryKind".into(), + "rerun.blueprint.components.LatestAtQueries".into(), + "rerun.blueprint.components.TimeRangeQueries".into(), + ] + }); + +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 5usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.blueprint.components.DataframeQueryIndicator".into(), + "rerun.blueprint.components.TimelineName".into(), + "rerun.blueprint.components.QueryKind".into(), + "rerun.blueprint.components.LatestAtQueries".into(), + "rerun.blueprint.components.TimeRangeQueries".into(), + ] + }); + +impl DataframeQuery { + /// The total number of components in the archetype: 0 required, 1 recommended, 4 optional + pub const NUM_COMPONENTS: usize = 5usize; +} + +/// Indicator component for the [`DataframeQuery`] [`::re_types_core::Archetype`] +pub type DataframeQueryIndicator = ::re_types_core::GenericIndicatorComponent; + +impl ::re_types_core::Archetype for DataframeQuery { + type Indicator = DataframeQueryIndicator; + + #[inline] + fn name() -> ::re_types_core::ArchetypeName { + "rerun.blueprint.archetypes.DataframeQuery".into() + } + + #[inline] + fn display_name() -> &'static str { + "Dataframe query" + } + + #[inline] + fn indicator() -> MaybeOwnedComponentBatch<'static> { + static INDICATOR: DataframeQueryIndicator = DataframeQueryIndicator::DEFAULT; + MaybeOwnedComponentBatch::Ref(&INDICATOR) + } + + #[inline] + fn required_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + REQUIRED_COMPONENTS.as_slice().into() + } + + #[inline] + fn recommended_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + RECOMMENDED_COMPONENTS.as_slice().into() + } + + #[inline] + fn optional_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + OPTIONAL_COMPONENTS.as_slice().into() + } + + #[inline] + fn all_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + ALL_COMPONENTS.as_slice().into() + } + + #[inline] + fn from_arrow_components( + arrow_data: impl IntoIterator)>, + ) -> DeserializationResult { + re_tracing::profile_function!(); + use ::re_types_core::{Loggable as _, ResultExt as _}; + let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data + .into_iter() + .map(|(name, array)| (name.full_name(), array)) + .collect(); + let timeline = + if let Some(array) = arrays_by_name.get("rerun.blueprint.components.TimelineName") { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#timeline")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let kind = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.QueryKind") { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#kind")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let latest_at_queries = + if let Some(array) = arrays_by_name.get("rerun.blueprint.components.LatestAtQueries") { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#latest_at_queries")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let time_range_queries = if let Some(array) = + arrays_by_name.get("rerun.blueprint.components.TimeRangeQueries") + { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.DataframeQuery#time_range_queries")? + .into_iter() + .next() + .flatten() + } else { + None + }; + Ok(Self { + timeline, + kind, + latest_at_queries, + time_range_queries, + }) + } +} + +impl ::re_types_core::AsComponents for DataframeQuery { + fn as_component_batches(&self) -> Vec> { + re_tracing::profile_function!(); + use ::re_types_core::Archetype as _; + [ + Some(Self::indicator()), + self.timeline + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.kind + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.latest_at_queries + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.time_range_queries + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + ] + .into_iter() + .flatten() + .collect() + } +} + +impl ::re_types_core::ArchetypeReflectionMarker for DataframeQuery {} + +impl DataframeQuery { + /// Create a new `DataframeQuery`. + #[inline] + pub fn new() -> Self { + Self { + timeline: None, + kind: None, + latest_at_queries: None, + time_range_queries: None, + } + } + + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + #[inline] + pub fn with_timeline( + mut self, + timeline: impl Into, + ) -> Self { + self.timeline = Some(timeline.into()); + self + } + + /// Kind of query: latest-at or range. + #[inline] + pub fn with_kind(mut self, kind: impl Into) -> Self { + self.kind = Some(kind.into()); + self + } + + /// Configuration for latest-at queries. + /// + /// Note: configuration as saved on a per-timeline basis. + #[inline] + pub fn with_latest_at_queries( + mut self, + latest_at_queries: impl Into, + ) -> Self { + self.latest_at_queries = Some(latest_at_queries.into()); + self + } + + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. + #[inline] + pub fn with_time_range_queries( + mut self, + time_range_queries: impl Into, + ) -> Self { + self.time_range_queries = Some(time_range_queries.into()); + self + } +} diff --git a/crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs b/crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs deleted file mode 100644 index ec2fb4e9f008..000000000000 --- a/crates/store/re_types/src/blueprint/archetypes/dataframe_view_mode.rs +++ /dev/null @@ -1,163 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -#![allow(unused_imports)] -#![allow(unused_parens)] -#![allow(clippy::clone_on_copy)] -#![allow(clippy::cloned_instead_of_copied)] -#![allow(clippy::map_flatten)] -#![allow(clippy::needless_question_mark)] -#![allow(clippy::new_without_default)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::too_many_lines)] - -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}; - -/// **Archetype**: Configuration for the dataframe view -#[derive(Clone, Debug, Copy)] -pub struct DataframeViewMode { - /// The kind of table to display - pub mode: Option, -} - -impl ::re_types_core::SizeBytes for DataframeViewMode { - #[inline] - fn heap_size_bytes(&self) -> u64 { - self.mode.heap_size_bytes() - } - - #[inline] - fn is_pod() -> bool { - >::is_pod() - } -} - -static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = - once_cell::sync::Lazy::new(|| []); - -static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = - once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.DataframeViewModeIndicator".into()]); - -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = - once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.DataframeViewMode".into()]); - -static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = - once_cell::sync::Lazy::new(|| { - [ - "rerun.blueprint.components.DataframeViewModeIndicator".into(), - "rerun.blueprint.components.DataframeViewMode".into(), - ] - }); - -impl DataframeViewMode { - /// The total number of components in the archetype: 0 required, 1 recommended, 1 optional - pub const NUM_COMPONENTS: usize = 2usize; -} - -/// Indicator component for the [`DataframeViewMode`] [`::re_types_core::Archetype`] -pub type DataframeViewModeIndicator = ::re_types_core::GenericIndicatorComponent; - -impl ::re_types_core::Archetype for DataframeViewMode { - type Indicator = DataframeViewModeIndicator; - - #[inline] - fn name() -> ::re_types_core::ArchetypeName { - "rerun.blueprint.archetypes.DataframeViewMode".into() - } - - #[inline] - fn display_name() -> &'static str { - "Dataframe view mode" - } - - #[inline] - fn indicator() -> MaybeOwnedComponentBatch<'static> { - static INDICATOR: DataframeViewModeIndicator = DataframeViewModeIndicator::DEFAULT; - MaybeOwnedComponentBatch::Ref(&INDICATOR) - } - - #[inline] - fn required_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - REQUIRED_COMPONENTS.as_slice().into() - } - - #[inline] - fn recommended_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - RECOMMENDED_COMPONENTS.as_slice().into() - } - - #[inline] - fn optional_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - OPTIONAL_COMPONENTS.as_slice().into() - } - - #[inline] - fn all_components() -> ::std::borrow::Cow<'static, [ComponentName]> { - ALL_COMPONENTS.as_slice().into() - } - - #[inline] - fn from_arrow_components( - arrow_data: impl IntoIterator)>, - ) -> DeserializationResult { - re_tracing::profile_function!(); - use ::re_types_core::{Loggable as _, ResultExt as _}; - let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data - .into_iter() - .map(|(name, array)| (name.full_name(), array)) - .collect(); - let mode = if let Some(array) = - arrays_by_name.get("rerun.blueprint.components.DataframeViewMode") - { - ::from_arrow_opt(&**array) - .with_context("rerun.blueprint.archetypes.DataframeViewMode#mode")? - .into_iter() - .next() - .flatten() - } else { - None - }; - Ok(Self { mode }) - } -} - -impl ::re_types_core::AsComponents for DataframeViewMode { - fn as_component_batches(&self) -> Vec> { - re_tracing::profile_function!(); - use ::re_types_core::Archetype as _; - [ - Some(Self::indicator()), - self.mode - .as_ref() - .map(|comp| (comp as &dyn ComponentBatch).into()), - ] - .into_iter() - .flatten() - .collect() - } -} - -impl ::re_types_core::ArchetypeReflectionMarker for DataframeViewMode {} - -impl DataframeViewMode { - /// Create a new `DataframeViewMode`. - #[inline] - pub fn new() -> Self { - Self { mode: None } - } - - /// The kind of table to display - #[inline] - pub fn with_mode( - mut self, - mode: impl Into, - ) -> Self { - self.mode = Some(mode.into()); - self - } -} diff --git a/crates/store/re_types/src/blueprint/archetypes/mod.rs b/crates/store/re_types/src/blueprint/archetypes/mod.rs index 59809a82d174..e0616353c032 100644 --- a/crates/store/re_types/src/blueprint/archetypes/mod.rs +++ b/crates/store/re_types/src/blueprint/archetypes/mod.rs @@ -1,7 +1,7 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs mod background; -mod dataframe_view_mode; +mod dataframe_query; mod plot_legend; mod scalar_axis; mod space_view_blueprint; @@ -15,7 +15,7 @@ mod visible_time_ranges_ext; mod visual_bounds2d; pub use self::background::Background; -pub use self::dataframe_view_mode::DataframeViewMode; +pub use self::dataframe_query::DataframeQuery; pub use self::plot_legend::PlotLegend; pub use self::scalar_axis::ScalarAxis; pub use self::space_view_blueprint::SpaceViewBlueprint; diff --git a/crates/store/re_types/src/blueprint/components/.gitattributes b/crates/store/re_types/src/blueprint/components/.gitattributes index 072eb67ff413..93f783652817 100644 --- a/crates/store/re_types/src/blueprint/components/.gitattributes +++ b/crates/store/re_types/src/blueprint/components/.gitattributes @@ -5,19 +5,22 @@ active_tab.rs linguist-generated=true background_kind.rs linguist-generated=true column_share.rs linguist-generated=true corner2d.rs linguist-generated=true -dataframe_view_mode.rs linguist-generated=true included_content.rs linguist-generated=true interactive.rs linguist-generated=true +latest_at_queries.rs linguist-generated=true lock_range_during_zoom.rs linguist-generated=true mod.rs linguist-generated=true panel_state.rs linguist-generated=true query_expression.rs linguist-generated=true +query_kind.rs linguist-generated=true row_share.rs linguist-generated=true sort_key.rs linguist-generated=true sort_order.rs linguist-generated=true space_view_class.rs linguist-generated=true space_view_origin.rs linguist-generated=true tensor_dimension_index_slider.rs linguist-generated=true +time_range_queries.rs linguist-generated=true +timeline_name.rs linguist-generated=true view_fit.rs linguist-generated=true viewer_recommendation_hash.rs linguist-generated=true visible.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/components/latest_at_queries.rs b/crates/store/re_types/src/blueprint/components/latest_at_queries.rs new file mode 100644 index 000000000000..50c87e763ba0 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/latest_at_queries.rs @@ -0,0 +1,183 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +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**: Configuration for latest at queries. +/// +/// Note: configuration as saved on a per-timeline basis. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[repr(transparent)] +pub struct LatestAtQueries(pub Vec); + +impl ::re_types_core::SizeBytes for LatestAtQueries { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + } +} + +impl, T: IntoIterator> From + for LatestAtQueries +{ + fn from(v: T) -> Self { + Self(v.into_iter().map(|v| v.into()).collect()) + } +} + +::re_types_core::macros::impl_into_cow!(LatestAtQueries); + +impl ::re_types_core::Loggable for LatestAtQueries { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.LatestAtQueries".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::List(std::sync::Arc::new(Field::new( + "item", + ::arrow_datatype(), + false, + ))) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + 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| datum.into_owned().0); + (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 offsets = arrow2::offset::Offsets::::try_from_lengths( + data0 + .iter() + .map(|opt| opt.as_ref().map_or(0, |datum| datum.len())), + )? + .into(); + let data0_inner_data: Vec<_> = data0.into_iter().flatten().flatten().collect(); + let data0_inner_bitmap: Option = None; + ListArray::try_new( + Self::arrow_datatype(), + offsets, + { + _ = data0_inner_bitmap; + crate::blueprint::datatypes::LatestAtQuery::to_arrow_opt( + data0_inner_data.into_iter().map(Some), + )? + }, + data0_bitmap, + )? + .boxed() + } + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + 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.LatestAtQueries#queries")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + crate::blueprint::datatypes::LatestAtQuery::from_arrow_opt(arrow_data_inner) + .with_context("rerun.blueprint.components.LatestAtQueries#queries")? + .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 > 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..end) }; + 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.LatestAtQueries#queries") + .with_context("rerun.blueprint.components.LatestAtQueries")?) + } +} diff --git a/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs new file mode 100644 index 000000000000..f5804cb488ab --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/latest_at_queries_ext.rs @@ -0,0 +1,22 @@ +use re_log_types::TimelineName; + +use super::LatestAtQueries; +use crate::blueprint::datatypes::LatestAtQuery; + +impl LatestAtQueries { + /// Retrieves the query for a given timeline. + pub fn query_for_timeline(&self, timeline_name: &TimelineName) -> Option<&LatestAtQuery> { + self.0 + .iter() + .find(|query| query.timeline.as_str() == timeline_name.as_str()) + } + + /// Sets the query for a given timeline. + pub fn set_query_for_timeline(&mut self, query: LatestAtQuery) { + if let Some(existing_query) = self.0.iter_mut().find(|q| q.timeline == query.timeline) { + *existing_query = query; + } else { + self.0.push(query); + } + } +} diff --git a/crates/store/re_types/src/blueprint/components/mod.rs b/crates/store/re_types/src/blueprint/components/mod.rs index ad247e647a88..a54028c22654 100644 --- a/crates/store/re_types/src/blueprint/components/mod.rs +++ b/crates/store/re_types/src/blueprint/components/mod.rs @@ -5,14 +5,16 @@ mod background_kind; mod column_share; mod corner2d; mod corner2d_ext; -mod dataframe_view_mode; mod included_content; mod interactive; mod interactive_ext; +mod latest_at_queries; +mod latest_at_queries_ext; mod lock_range_during_zoom; mod panel_state; mod panel_state_ext; mod query_expression; +mod query_kind; mod row_share; mod sort_key; mod sort_order; @@ -22,6 +24,10 @@ mod space_view_origin; mod space_view_origin_ext; mod tensor_dimension_index_slider; mod tensor_dimension_index_slider_ext; +mod time_range_queries; +mod time_range_queries_ext; +mod timeline_name; +mod timeline_name_ext; mod view_fit; mod viewer_recommendation_hash; mod viewer_recommendation_hash_ext; @@ -35,18 +41,21 @@ pub use self::active_tab::ActiveTab; pub use self::background_kind::BackgroundKind; pub use self::column_share::ColumnShare; pub use self::corner2d::Corner2D; -pub use self::dataframe_view_mode::DataframeViewMode; pub use self::included_content::IncludedContent; pub use self::interactive::Interactive; +pub use self::latest_at_queries::LatestAtQueries; pub use self::lock_range_during_zoom::LockRangeDuringZoom; pub use self::panel_state::PanelState; pub use self::query_expression::QueryExpression; +pub use self::query_kind::QueryKind; pub use self::row_share::RowShare; pub use self::sort_key::SortKey; pub use self::sort_order::SortOrder; pub use self::space_view_class::SpaceViewClass; pub use self::space_view_origin::SpaceViewOrigin; pub use self::tensor_dimension_index_slider::TensorDimensionIndexSlider; +pub use self::time_range_queries::TimeRangeQueries; +pub use self::timeline_name::TimelineName; pub use self::view_fit::ViewFit; pub use self::viewer_recommendation_hash::ViewerRecommendationHash; pub use self::visible::Visible; diff --git a/crates/store/re_types/src/blueprint/components/dataframe_view_mode.rs b/crates/store/re_types/src/blueprint/components/query_kind.rs similarity index 71% rename from crates/store/re_types/src/blueprint/components/dataframe_view_mode.rs rename to crates/store/re_types/src/blueprint/components/query_kind.rs index 9a38e47cddff..e473b5a5fbaf 100644 --- a/crates/store/re_types/src/blueprint/components/dataframe_view_mode.rs +++ b/crates/store/re_types/src/blueprint/components/query_kind.rs @@ -1,5 +1,5 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". #![allow(unused_imports)] #![allow(unused_parens)] @@ -18,24 +18,19 @@ use ::re_types_core::SerializationResult; use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; use ::re_types_core::{DeserializationError, DeserializationResult}; -/// **Component**: The kind of table displayed by the dataframe view +/// **Component**: The kind of query displayed by the dataframe view #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] #[repr(u8)] -pub enum DataframeViewMode { - /// Display the entity values at the current time. - /// - /// In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. +pub enum QueryKind { + /// Query #[default] LatestAt = 1, - /// Display a temporal table of entity values. - /// - /// In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - /// timestamp shown are determined by each view entity's visible time range setting. + /// Time range query. TimeRange = 2, } -impl ::re_types_core::reflection::Enum for DataframeViewMode { +impl ::re_types_core::reflection::Enum for QueryKind { #[inline] fn variants() -> &'static [Self] { &[Self::LatestAt, Self::TimeRange] @@ -44,17 +39,13 @@ impl ::re_types_core::reflection::Enum for DataframeViewMode { #[inline] fn docstring_md(self) -> &'static str { match self { - Self::LatestAt => { - "Display the entity values at the current time.\n\nIn this mode, rows are entity instances, and columns are components. The visible time range setting is ignored." - } - Self::TimeRange => { - "Display a temporal table of entity values.\n\nIn this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The\ntimestamp shown are determined by each view entity's visible time range setting." - } + Self::LatestAt => "Query", + Self::TimeRange => "Time range query.", } } } -impl ::re_types_core::SizeBytes for DataframeViewMode { +impl ::re_types_core::SizeBytes for QueryKind { #[inline] fn heap_size_bytes(&self) -> u64 { 0 @@ -66,7 +57,7 @@ impl ::re_types_core::SizeBytes for DataframeViewMode { } } -impl std::fmt::Display for DataframeViewMode { +impl std::fmt::Display for QueryKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::LatestAt => write!(f, "LatestAt"), @@ -75,14 +66,14 @@ impl std::fmt::Display for DataframeViewMode { } } -::re_types_core::macros::impl_into_cow!(DataframeViewMode); +::re_types_core::macros::impl_into_cow!(QueryKind); -impl ::re_types_core::Loggable for DataframeViewMode { +impl ::re_types_core::Loggable for QueryKind { type Name = ::re_types_core::ComponentName; #[inline] fn name() -> Self::Name { - "rerun.blueprint.components.DataframeViewMode".into() + "rerun.blueprint.components.QueryKind".into() } #[inline] @@ -140,7 +131,7 @@ impl ::re_types_core::Loggable for DataframeViewMode { let actual = arrow_data.data_type().clone(); DeserializationError::datatype_mismatch(expected, actual) }) - .with_context("rerun.blueprint.components.DataframeViewMode#enum")? + .with_context("rerun.blueprint.components.QueryKind#enum")? .into_iter() .map(|opt| opt.copied()) .map(|typ| match typ { @@ -154,6 +145,6 @@ impl ::re_types_core::Loggable for DataframeViewMode { )), }) .collect::>>>() - .with_context("rerun.blueprint.components.DataframeViewMode")?) + .with_context("rerun.blueprint.components.QueryKind")?) } } diff --git a/crates/store/re_types/src/blueprint/components/time_range_queries.rs b/crates/store/re_types/src/blueprint/components/time_range_queries.rs new file mode 100644 index 000000000000..34eecb5613e5 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/time_range_queries.rs @@ -0,0 +1,183 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +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**: Configuration for time range queries. +/// +/// Note: configuration as saved on a per-timeline basis. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[repr(transparent)] +pub struct TimeRangeQueries(pub Vec); + +impl ::re_types_core::SizeBytes for TimeRangeQueries { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + } +} + +impl, T: IntoIterator> From + for TimeRangeQueries +{ + fn from(v: T) -> Self { + Self(v.into_iter().map(|v| v.into()).collect()) + } +} + +::re_types_core::macros::impl_into_cow!(TimeRangeQueries); + +impl ::re_types_core::Loggable for TimeRangeQueries { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.TimeRangeQueries".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::List(std::sync::Arc::new(Field::new( + "item", + ::arrow_datatype(), + false, + ))) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + 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| datum.into_owned().0); + (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 offsets = arrow2::offset::Offsets::::try_from_lengths( + data0 + .iter() + .map(|opt| opt.as_ref().map_or(0, |datum| datum.len())), + )? + .into(); + let data0_inner_data: Vec<_> = data0.into_iter().flatten().flatten().collect(); + let data0_inner_bitmap: Option = None; + ListArray::try_new( + Self::arrow_datatype(), + offsets, + { + _ = data0_inner_bitmap; + crate::blueprint::datatypes::TimeRangeQuery::to_arrow_opt( + data0_inner_data.into_iter().map(Some), + )? + }, + data0_bitmap, + )? + .boxed() + } + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + 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.TimeRangeQueries#queries")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let arrow_data_inner = { + let arrow_data_inner = &**arrow_data.values(); + crate::blueprint::datatypes::TimeRangeQuery::from_arrow_opt(arrow_data_inner) + .with_context("rerun.blueprint.components.TimeRangeQueries#queries")? + .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 > 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..end) }; + 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.TimeRangeQueries#queries") + .with_context("rerun.blueprint.components.TimeRangeQueries")?) + } +} diff --git a/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs new file mode 100644 index 000000000000..5e43fea06fd8 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/time_range_queries_ext.rs @@ -0,0 +1,22 @@ +use re_log_types::TimelineName; + +use super::TimeRangeQueries; +use crate::blueprint::datatypes::TimeRangeQuery; + +impl TimeRangeQueries { + /// Retrieves the query for a given timeline. + pub fn query_for_timeline(&self, timeline_name: &TimelineName) -> Option<&TimeRangeQuery> { + self.0 + .iter() + .find(|query| query.timeline.as_str() == timeline_name.as_str()) + } + + /// Sets the query for a given timeline. + pub fn set_query_for_timeline(&mut self, query: TimeRangeQuery) { + if let Some(existing_query) = self.0.iter_mut().find(|q| q.timeline == query.timeline) { + *existing_query = query; + } else { + self.0.push(query); + } + } +} diff --git a/crates/store/re_types/src/blueprint/components/timeline_name.rs b/crates/store/re_types/src/blueprint/components/timeline_name.rs new file mode 100644 index 000000000000..f4cfbd0bdf33 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/timeline_name.rs @@ -0,0 +1,105 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +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**: A timeline identified by its name. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct TimelineName(pub crate::datatypes::Utf8); + +impl ::re_types_core::SizeBytes for TimelineName { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +impl> From for TimelineName { + fn from(v: T) -> Self { + Self(v.into()) + } +} + +impl std::borrow::Borrow for TimelineName { + #[inline] + fn borrow(&self) -> &crate::datatypes::Utf8 { + &self.0 + } +} + +impl std::ops::Deref for TimelineName { + type Target = crate::datatypes::Utf8; + + #[inline] + fn deref(&self) -> &crate::datatypes::Utf8 { + &self.0 + } +} + +impl std::ops::DerefMut for TimelineName { + #[inline] + fn deref_mut(&mut self) -> &mut crate::datatypes::Utf8 { + &mut self.0 + } +} + +::re_types_core::macros::impl_into_cow!(TimelineName); + +impl ::re_types_core::Loggable for TimelineName { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.TimelineName".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + crate::datatypes::Utf8::arrow_datatype() + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + crate::datatypes::Utf8::to_arrow_opt(data.into_iter().map(|datum| { + datum.map(|datum| match datum.into() { + ::std::borrow::Cow::Borrowed(datum) => ::std::borrow::Cow::Borrowed(&datum.0), + ::std::borrow::Cow::Owned(datum) => ::std::borrow::Cow::Owned(datum.0), + }) + })) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + crate::datatypes::Utf8::from_arrow_opt(arrow_data) + .map(|v| v.into_iter().map(|v| v.map(Self)).collect()) + } +} diff --git a/crates/store/re_types/src/blueprint/components/timeline_name_ext.rs b/crates/store/re_types/src/blueprint/components/timeline_name_ext.rs new file mode 100644 index 000000000000..6ef93e92c4f1 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/timeline_name_ext.rs @@ -0,0 +1,22 @@ +use super::TimelineName; + +// Not needed as there is a blanket implementation for impl Into +// impl From for TimelineName {} + +impl From for re_log_types::TimelineName { + fn from(value: TimelineName) -> Self { + Self::from(value.as_str()) + } +} + +impl From<&TimelineName> for re_log_types::TimelineName { + fn from(value: &TimelineName) -> Self { + Self::from(value.as_str()) + } +} + +impl Default for TimelineName { + fn default() -> Self { + Self::from("log_time") + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/.gitattributes b/crates/store/re_types/src/blueprint/datatypes/.gitattributes index f4557edfa342..0f6ee351e568 100644 --- a/crates/store/re_types/src/blueprint/datatypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/datatypes/.gitattributes @@ -1,5 +1,7 @@ # DO NOT EDIT! This file is generated by crates/build/re_types_builder/src/lib.rs .gitattributes linguist-generated=true +latest_at_query.rs linguist-generated=true mod.rs linguist-generated=true tensor_dimension_index_slider.rs linguist-generated=true +time_range_query.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs b/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs new file mode 100644 index 000000000000..e8a888f13f63 --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/latest_at_query.rs @@ -0,0 +1,284 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +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}; + +/// **Datatype**: Latest at query configuration for a specific timeline. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LatestAtQuery { + /// Name of the timeline this applies to. + pub timeline: crate::datatypes::Utf8, + + /// Time value to use for this query. + pub time: crate::datatypes::TimeInt, +} + +impl ::re_types_core::SizeBytes for LatestAtQuery { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.timeline.heap_size_bytes() + self.time.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() && ::is_pod() + } +} + +::re_types_core::macros::impl_into_cow!(LatestAtQuery); + +impl ::re_types_core::Loggable for LatestAtQuery { + type Name = ::re_types_core::DatatypeName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.datatypes.LatestAtQuery".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::Struct(std::sync::Arc::new(vec![ + Field::new( + "timeline", + ::arrow_datatype(), + false, + ), + Field::new("time", ::arrow_datatype(), false), + ])) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + (datum.is_some(), datum) + }) + .unzip(); + let bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + StructArray::new( + Self::arrow_datatype(), + vec![ + { + let (somes, timeline): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.timeline.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let timeline_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + let offsets = arrow2::offset::Offsets::::try_from_lengths( + timeline.iter().map(|opt| { + opt.as_ref().map(|datum| datum.0.len()).unwrap_or_default() + }), + )? + .into(); + let inner_data: arrow2::buffer::Buffer = timeline + .into_iter() + .flatten() + .flat_map(|datum| datum.0 .0) + .collect(); + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + unsafe { + Utf8Array::::new_unchecked( + DataType::Utf8, + offsets, + inner_data, + timeline_bitmap, + ) + } + .boxed() + } + }, + { + let (somes, time): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.time.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let time_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + DataType::Int64, + time.into_iter() + .map(|datum| datum.map(|datum| datum.0).unwrap_or_default()) + .collect(), + time_bitmap, + ) + .boxed() + }, + ], + bitmap, + ) + .boxed() + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + 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.datatypes.LatestAtQuery")?; + 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 timeline = { + if !arrays_by_name.contains_key("timeline") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "timeline", + )) + .with_context("rerun.blueprint.datatypes.LatestAtQuery"); + } + let arrow_data = &**arrays_by_name["timeline"]; + { + let arrow_data = arrow_data + .as_any() + .downcast_ref::>() + .ok_or_else(|| { + let expected = DataType::Utf8; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#timeline")?; + let arrow_data_buf = arrow_data.values(); + 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 > arrow_data_buf.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_buf.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_buf.clone().sliced_unchecked(start, len) }; + Ok(data) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt.map(|res_or_opt| { + res_or_opt.map(|v| { + crate::datatypes::Utf8(::re_types_core::ArrowString(v)) + }) + }) + }) + .collect::>>>() + .with_context("rerun.blueprint.datatypes.LatestAtQuery#timeline")? + .into_iter() + } + }; + let time = { + if !arrays_by_name.contains_key("time") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "time", + )) + .with_context("rerun.blueprint.datatypes.LatestAtQuery"); + } + let arrow_data = &**arrays_by_name["time"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::Int64; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#time")? + .into_iter() + .map(|opt| opt.copied()) + .map(|res_or_opt| res_or_opt.map(crate::datatypes::TimeInt)) + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + ::itertools::izip!(timeline, time), + arrow_data.validity(), + ) + .map(|opt| { + opt.map(|(timeline, time)| { + Ok(Self { + timeline: timeline + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#timeline")?, + time: time + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.LatestAtQuery#time")?, + }) + }) + .transpose() + }) + .collect::>>() + .with_context("rerun.blueprint.datatypes.LatestAtQuery")? + } + }) + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs b/crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs new file mode 100644 index 000000000000..5b2c1ad2138e --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/latest_at_query_ext.rs @@ -0,0 +1,12 @@ +use re_types_core::datatypes::{TimeInt, Utf8}; + +use super::LatestAtQuery; + +impl Default for LatestAtQuery { + fn default() -> Self { + Self { + timeline: Utf8::from("log_time"), + time: TimeInt::MAX, + } + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/mod.rs b/crates/store/re_types/src/blueprint/datatypes/mod.rs index d0dadbc2b6d8..9a8d6aef70dd 100644 --- a/crates/store/re_types/src/blueprint/datatypes/mod.rs +++ b/crates/store/re_types/src/blueprint/datatypes/mod.rs @@ -1,5 +1,11 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +mod latest_at_query; +mod latest_at_query_ext; mod tensor_dimension_index_slider; +mod time_range_query; +mod time_range_query_ext; +pub use self::latest_at_query::LatestAtQuery; pub use self::tensor_dimension_index_slider::TensorDimensionIndexSlider; +pub use self::time_range_query::TimeRangeQuery; diff --git a/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs new file mode 100644 index 000000000000..59e581545bd7 --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/time_range_query.rs @@ -0,0 +1,343 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +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}; + +/// **Datatype**: Time range query configuration for a specific timeline. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TimeRangeQuery { + /// Name of the timeline this applies to. + pub timeline: crate::datatypes::Utf8, + + /// Beginning of the time range. + pub start: crate::datatypes::TimeInt, + + /// End of the time range (inclusive). + pub end: crate::datatypes::TimeInt, +} + +impl ::re_types_core::SizeBytes for TimeRangeQuery { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.timeline.heap_size_bytes() + self.start.heap_size_bytes() + self.end.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + && ::is_pod() + && ::is_pod() + } +} + +::re_types_core::macros::impl_into_cow!(TimeRangeQuery); + +impl ::re_types_core::Loggable for TimeRangeQuery { + type Name = ::re_types_core::DatatypeName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.datatypes.TimeRangeQuery".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::Struct(std::sync::Arc::new(vec![ + Field::new( + "timeline", + ::arrow_datatype(), + false, + ), + Field::new( + "start", + ::arrow_datatype(), + false, + ), + Field::new("end", ::arrow_datatype(), false), + ])) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + (datum.is_some(), datum) + }) + .unzip(); + let bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + StructArray::new( + Self::arrow_datatype(), + vec![ + { + let (somes, timeline): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.timeline.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let timeline_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + let offsets = arrow2::offset::Offsets::::try_from_lengths( + timeline.iter().map(|opt| { + opt.as_ref().map(|datum| datum.0.len()).unwrap_or_default() + }), + )? + .into(); + let inner_data: arrow2::buffer::Buffer = timeline + .into_iter() + .flatten() + .flat_map(|datum| datum.0 .0) + .collect(); + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + unsafe { + Utf8Array::::new_unchecked( + DataType::Utf8, + offsets, + inner_data, + timeline_bitmap, + ) + } + .boxed() + } + }, + { + let (somes, start): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.start.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let start_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + DataType::Int64, + start + .into_iter() + .map(|datum| datum.map(|datum| datum.0).unwrap_or_default()) + .collect(), + start_bitmap, + ) + .boxed() + }, + { + let (somes, end): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| datum.end.clone()); + (datum.is_some(), datum) + }) + .unzip(); + let end_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + DataType::Int64, + end.into_iter() + .map(|datum| datum.map(|datum| datum.0).unwrap_or_default()) + .collect(), + end_bitmap, + ) + .boxed() + }, + ], + bitmap, + ) + .boxed() + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + 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.datatypes.TimeRangeQuery")?; + 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 timeline = { + if !arrays_by_name.contains_key("timeline") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "timeline", + )) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery"); + } + let arrow_data = &**arrays_by_name["timeline"]; + { + let arrow_data = arrow_data + .as_any() + .downcast_ref::>() + .ok_or_else(|| { + let expected = DataType::Utf8; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#timeline")?; + let arrow_data_buf = arrow_data.values(); + 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 > arrow_data_buf.len() { + return Err(DeserializationError::offset_slice_oob( + (start, end), + arrow_data_buf.len(), + )); + } + + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let data = + unsafe { arrow_data_buf.clone().sliced_unchecked(start, len) }; + Ok(data) + }) + .transpose() + }) + .map(|res_or_opt| { + res_or_opt.map(|res_or_opt| { + res_or_opt.map(|v| { + crate::datatypes::Utf8(::re_types_core::ArrowString(v)) + }) + }) + }) + .collect::>>>() + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#timeline")? + .into_iter() + } + }; + let start = { + if !arrays_by_name.contains_key("start") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "start", + )) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery"); + } + let arrow_data = &**arrays_by_name["start"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::Int64; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#start")? + .into_iter() + .map(|opt| opt.copied()) + .map(|res_or_opt| res_or_opt.map(crate::datatypes::TimeInt)) + }; + let end = { + if !arrays_by_name.contains_key("end") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "end", + )) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery"); + } + let arrow_data = &**arrays_by_name["end"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = DataType::Int64; + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#end")? + .into_iter() + .map(|opt| opt.copied()) + .map(|res_or_opt| res_or_opt.map(crate::datatypes::TimeInt)) + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + ::itertools::izip!(timeline, start, end), + arrow_data.validity(), + ) + .map(|opt| { + opt.map(|(timeline, start, end)| { + Ok(Self { + timeline: timeline + .ok_or_else(DeserializationError::missing_data) + .with_context( + "rerun.blueprint.datatypes.TimeRangeQuery#timeline", + )?, + start: start + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#start")?, + end: end + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.TimeRangeQuery#end")?, + }) + }) + .transpose() + }) + .collect::>>() + .with_context("rerun.blueprint.datatypes.TimeRangeQuery")? + } + }) + } +} diff --git a/crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs b/crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs new file mode 100644 index 000000000000..d8d54d875aeb --- /dev/null +++ b/crates/store/re_types/src/blueprint/datatypes/time_range_query_ext.rs @@ -0,0 +1,12 @@ +use super::TimeRangeQuery; +use re_types_core::datatypes::{TimeInt, Utf8}; + +impl Default for TimeRangeQuery { + fn default() -> Self { + Self { + timeline: Utf8::from("log_time"), + start: TimeInt::MIN, + end: TimeInt::MAX, + } + } +} diff --git a/crates/viewer/re_edit_ui/src/lib.rs b/crates/viewer/re_edit_ui/src/lib.rs index 01f94b9b6b95..2d6fe01a28c6 100644 --- a/crates/viewer/re_edit_ui/src/lib.rs +++ b/crates/viewer/re_edit_ui/src/lib.rs @@ -9,6 +9,7 @@ mod marker_shape; mod radius; mod range1d; mod response_utils; +mod timeline; mod transforms; mod visual_bounds2d; @@ -19,8 +20,8 @@ use datatype_editors::{ }; use re_types::{ blueprint::components::{ - BackgroundKind, Corner2D, DataframeViewMode, LockRangeDuringZoom, SortKey, SortOrder, - ViewFit, Visible, + BackgroundKind, Corner2D, LockRangeDuringZoom, SortKey, SortOrder, TimelineName, ViewFit, + Visible, }, components::{ AggregationPolicy, AlbedoFactor, AxisLength, Color, Colormap, DepthMeter, DrawOrder, @@ -60,6 +61,8 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { registry.add_singleline_edit_or_view::(edit_bool); registry.add_singleline_edit_or_view::(edit_bool); + registry.add_singleline_edit_or_view::(timeline::edit_timeline_name); + registry.add_display_ui(Text::name(), Box::new(display_text_ui)); registry.add_singleline_edit_or_view::(edit_singleline_string); registry.add_multiline_edit_or_view::(edit_multiline_string); @@ -72,7 +75,6 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); - registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); registry.add_singleline_edit_or_view::(edit_view_enum); diff --git a/crates/viewer/re_edit_ui/src/timeline.rs b/crates/viewer/re_edit_ui/src/timeline.rs new file mode 100644 index 000000000000..f64cee9435e8 --- /dev/null +++ b/crates/viewer/re_edit_ui/src/timeline.rs @@ -0,0 +1,38 @@ +use re_types::blueprint::components; +use re_types_core::LoggableBatch as _; +use re_viewer_context::external::re_log_types::TimelineName; +use re_viewer_context::{MaybeMutRef, ViewerContext}; + +pub(crate) fn edit_timeline_name( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + value: &mut MaybeMutRef<'_, components::TimelineName>, +) -> egui::Response { + if let Some(value) = value.as_mut() { + let mut current_value: TimelineName = (&*value).into(); + let id_source = value.name(); + let mut changed = false; + let mut combobox_response = egui::ComboBox::from_id_source(id_source) + .selected_text(current_value.as_str()) + .show_ui(ui, |ui| { + for timeline in ctx.recording().timelines() { + let response = ui.selectable_value( + &mut current_value, + *timeline.name(), + timeline.name().as_str(), + ); + + changed |= response.changed(); + } + }); + + if changed { + *value = current_value.as_str().into(); + combobox_response.response.mark_changed(); + } + + combobox_response.response + } else { + ui.label(value.as_str()) + } +} diff --git a/crates/viewer/re_selection_panel/Cargo.toml b/crates/viewer/re_selection_panel/Cargo.toml index 1f03685f7f58..e67bfccc46ea 100644 --- a/crates/viewer/re_selection_panel/Cargo.toml +++ b/crates/viewer/re_selection_panel/Cargo.toml @@ -26,7 +26,6 @@ re_data_ui.workspace = true re_entity_db.workspace = true re_log_types.workspace = true re_log.workspace = true -re_space_view_dataframe.workspace = true re_space_view_spatial.workspace = true re_space_view_time_series.workspace = true re_space_view.workspace = true diff --git a/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs b/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs index 10ee88a60a2b..0fbb6afc57da 100644 --- a/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs +++ b/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs @@ -3,7 +3,6 @@ use std::collections::HashSet; use egui::{NumExt as _, Ui}; use re_log_types::{EntityPath, ResolvedTimeRange, TimeType, TimelineName}; -use re_space_view_dataframe::DataframeSpaceView; use re_space_view_spatial::{SpatialSpaceView2D, SpatialSpaceView3D}; use re_space_view_time_series::TimeSeriesSpaceView; use re_types::{ @@ -23,7 +22,6 @@ static VISIBLE_HISTORY_SUPPORTED_SPACE_VIEWS: once_cell::sync::Lazy< SpatialSpaceView3D::identifier(), SpatialSpaceView2D::identifier(), TimeSeriesSpaceView::identifier(), - DataframeSpaceView::identifier(), ] .map(Into::into) .into() diff --git a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs index 6eccb88c94f4..6c8c57dfcc3f 100644 --- a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs @@ -1,5 +1,6 @@ use std::collections::BTreeSet; +use re_chunk_store::LatestAtQuery; use re_data_ui::item_ui::instance_path_button; use re_entity_db::InstancePath; use re_log_types::Instance; @@ -18,6 +19,7 @@ pub(crate) fn latest_at_table_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, query: &ViewQuery<'_>, + latest_at_query: &LatestAtQuery, ) { re_tracing::profile_function!(); @@ -27,7 +29,6 @@ pub(crate) fn latest_at_table_ui( // These are the entity paths whose content we must display. let sorted_entity_paths = sorted_visible_entity_path(ctx, query); - let latest_at_query = query.latest_at_query(); let sorted_instance_paths: Vec<_>; let sorted_components: BTreeSet<_>; @@ -51,8 +52,8 @@ pub(crate) fn latest_at_table_ui( sorted_instance_paths_for( entity_path, ctx.recording_store(), - &query.timeline, - &latest_at_query, + &latest_at_query.timeline(), + latest_at_query, ) }) .collect(); @@ -63,7 +64,7 @@ pub(crate) fn latest_at_table_ui( .iter() .flat_map(|entity_path| { ctx.recording_store() - .all_components_on_timeline(&query.timeline, entity_path) + .all_components_on_timeline(&latest_at_query.timeline(), entity_path) .unwrap_or_default() }) // TODO(#4466): make showing/hiding indicators components an explicit optional @@ -133,7 +134,7 @@ pub(crate) fn latest_at_table_ui( row.col(|ui| { instance_path_button( ctx, - &latest_at_query, + latest_at_query, ctx.recording(), ui, Some(query.space_view_id), @@ -150,17 +151,18 @@ pub(crate) fn latest_at_table_ui( let result = ctx .recording_store() .latest_at_relevant_chunks( - &latest_at_query, + latest_at_query, &instance_path.entity_path, *component_name, ) .into_iter() .filter_map(|chunk| { let (index, unit) = chunk - .latest_at(&latest_at_query, *component_name) + .latest_at(latest_at_query, *component_name) .into_unit() .and_then(|unit| { - unit.index(&query.timeline).map(|index| (index, unit)) + unit.index(&latest_at_query.timeline()) + .map(|index| (index, unit)) })?; unit.component_batch_raw(component_name) @@ -184,7 +186,7 @@ pub(crate) fn latest_at_table_ui( ctx, ui, UiLayout::List, - &latest_at_query, + latest_at_query, ctx.recording(), &instance_path.entity_path, *component_name, diff --git a/crates/viewer/re_space_view_dataframe/src/lib.rs b/crates/viewer/re_space_view_dataframe/src/lib.rs index b3d8a9436846..b036b03577b4 100644 --- a/crates/viewer/re_space_view_dataframe/src/lib.rs +++ b/crates/viewer/re_space_view_dataframe/src/lib.rs @@ -3,10 +3,12 @@ //! A Space View that shows the data contained in entities in a table. mod latest_at_table; +mod query_kind_ui; mod space_view_class; mod table_ui; mod time_range_table; mod utils; +mod view_query; mod visualizer_system; pub use space_view_class::DataframeSpaceView; diff --git a/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs b/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs new file mode 100644 index 000000000000..b02f7f18f025 --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/query_kind_ui.rs @@ -0,0 +1,214 @@ +use re_log_types::{ResolvedTimeRange, TimeInt, TimeType, TimelineName}; +use re_ui::{list_item, UiExt}; +use re_viewer_context::{TimeDragValue, ViewerContext}; + +use crate::view_query::QueryKind; + +/// Helper to handle the UI for the various query kinds are they are shown to the user. +/// +/// This struct is the "UI equivalent" of the [`QueryKind`] enum. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum UiQueryKind { + LatestAt { time: TimeInt }, + TimeRangeAll, + TimeRange { from: TimeInt, to: TimeInt }, +} + +impl UiQueryKind { + /// Show the UI for the query kind selector. + pub(crate) fn ui( + &mut self, + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + time_drag_value: &TimeDragValue, + timeline_name: &TimelineName, + time_type: TimeType, + ) -> bool { + let orig_self = *self; + + ui.vertical(|ui| { + // + // LATEST AT + // + + ui.horizontal(|ui| { + let mut is_latest_at = matches!(self, Self::LatestAt { .. }); + + let mut changed = ui + .re_radio_value(&mut is_latest_at, true, "Latest at") + .changed(); + + if is_latest_at { + let mut time = if let Self::LatestAt { time } = self { + *time + } else { + TimeInt::MAX + } + .into(); + + changed |= match time_type { + TimeType::Time => time_drag_value + .temporal_drag_value_ui( + ui, + &mut time, + true, + None, + ctx.app_options.time_zone, + ) + .0 + .changed(), + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut time, true, None) + .changed(), + }; + + if changed { + *self = Self::LatestAt { time: time.into() }; + } + } + }); + + // + // TIME RANGE ALL + // + + ui.horizontal(|ui| { + let mut is_time_range_all = matches!(self, Self::TimeRangeAll); + if ui + .re_radio_value(&mut is_time_range_all, true, "From –∞ to +∞") + .changed() + && is_time_range_all + { + *self = Self::TimeRangeAll; + } + }); + + // + // TIME RANGE CUSTOM + // + + ui.vertical(|ui| { + let mut is_time_range_custom = matches!(self, Self::TimeRange { .. }); + let mut changed = ui + .re_radio_value(&mut is_time_range_custom, true, "Define time range") + .changed(); + + let mut should_display_time_range = false; + + if is_time_range_custom { + ui.spacing_mut().indent = ui.spacing().icon_width + ui.spacing().icon_spacing; + ui.indent("time_range_custom", |ui| { + ui.add_space(-4.0); + + let mut from = if let Self::TimeRange { from, .. } = self { + (*from).into() + } else { + (*time_drag_value.range.start()).into() + }; + + let mut to = if let Self::TimeRange { to, .. } = self { + (*to).into() + } else { + (*time_drag_value.range.end()).into() + }; + + list_item::list_item_scope(ui, "time_range_custom_scope", |ui| { + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("Start").value_fn(|ui, _| { + let response = match time_type { + TimeType::Time => { + time_drag_value + .temporal_drag_value_ui( + ui, + &mut from, + true, + None, + ctx.app_options.time_zone, + ) + .0 + } + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut from, true, None), + }; + + changed |= response.changed(); + should_display_time_range |= response.hovered() + || response.dragged() + || response.has_focus(); + }), + ); + + ui.list_item_flat_noninteractive( + list_item::PropertyContent::new("End").value_fn(|ui, _| { + let response = match time_type { + TimeType::Time => { + time_drag_value + .temporal_drag_value_ui( + ui, + &mut to, + true, + Some(from), + ctx.app_options.time_zone, + ) + .0 + } + TimeType::Sequence => time_drag_value + .sequence_drag_value_ui(ui, &mut to, true, Some(from)), + }; + + changed |= response.changed(); + should_display_time_range |= response.hovered() + || response.dragged() + || response.has_focus(); + }), + ); + }); + + if changed { + *self = Self::TimeRange { + from: from.into(), + to: to.into(), + }; + } + + if should_display_time_range { + let mut time_ctrl = ctx.rec_cfg.time_ctrl.write(); + if time_ctrl.timeline().name() == timeline_name { + time_ctrl.highlighted_range = + Some(ResolvedTimeRange::new(from, to)); + } + } + }); + } + }); + }); + + *self != orig_self + } +} + +impl From for UiQueryKind { + fn from(value: QueryKind) -> Self { + match value { + QueryKind::LatestAt { time } => Self::LatestAt { time }, + QueryKind::Range { + from: TimeInt::MIN, + to: TimeInt::MAX, + } => Self::TimeRangeAll, + QueryKind::Range { from, to } => Self::TimeRange { from, to }, + } + } +} + +impl From for QueryKind { + fn from(value: UiQueryKind) -> Self { + match value { + UiQueryKind::LatestAt { time } => Self::LatestAt { time }, + UiQueryKind::TimeRangeAll => Self::Range { + from: TimeInt::MIN, + to: TimeInt::MAX, + }, + UiQueryKind::TimeRange { from, to } => Self::Range { from, to }, + } + } +} diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index dc94679a0b9f..b6c8aa660dd2 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -1,45 +1,24 @@ use egui::Ui; -use std::any::Any; -use re_log_types::EntityPath; +use re_chunk_store::LatestAtQuery; +use re_log_types::{EntityPath, ResolvedTimeRange}; use re_space_view::view_property_ui; use re_types::blueprint::{archetypes, components}; -use re_types_core::datatypes::TimeRange; use re_types_core::SpaceViewClassIdentifier; use re_ui::list_item; use re_viewer_context::{ - QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, - SpaceViewStateExt, SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, - ViewerContext, + SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, + SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, ViewerContext, }; use re_viewport_blueprint::ViewProperty; use crate::{ - latest_at_table::latest_at_table_ui, time_range_table::time_range_table_ui, + latest_at_table::latest_at_table_ui, + time_range_table::time_range_table_ui, + view_query::{Query, QueryKind}, visualizer_system::EmptySystem, }; -/// State for the Dataframe view. -/// -/// We use this to carry information from `ui()` to `default_query_range()` as a workaround for -/// `https://github.com/rerun-io/rerun/issues/6918`. -#[derive(Debug, Default)] -struct DataframeViewState { - mode: components::DataframeViewMode, -} - -impl SpaceViewState for DataframeViewState { - #[inline] - fn as_any(&self) -> &dyn Any { - self - } - - #[inline] - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - #[derive(Default)] pub struct DataframeSpaceView; @@ -86,7 +65,7 @@ mode sets the default time range to _everything_. You can override this in the s } fn new_state(&self) -> Box { - Box::::default() + Box::<()>::default() } fn preferred_tile_aspect_ratio(&self, _state: &dyn SpaceViewState) -> Option { @@ -97,23 +76,6 @@ mode sets the default time range to _everything_. You can override this in the s re_viewer_context::SpaceViewClassLayoutPriority::Low } - fn default_query_range(&self, state: &dyn SpaceViewState) -> QueryRange { - // TODO(#6918): passing the mode via view state is a hacky work-around, until we're able to - // pass more context to this function. - let mode = state - .downcast_ref::() - .map(|state| state.mode) - .inspect_err(|err| re_log::warn_once!("Unexpected view type: {err}")) - .unwrap_or_default(); - - match mode { - components::DataframeViewMode::LatestAt => QueryRange::LatestAt, - components::DataframeViewMode::TimeRange => { - QueryRange::TimeRange(TimeRange::EVERYTHING) - } - } - } - fn spawn_heuristics( &self, _ctx: &ViewerContext<'_>, @@ -130,31 +92,26 @@ mode sets the default time range to _everything_. You can override this in the s _space_origin: &EntityPath, space_view_id: SpaceViewId, ) -> Result<(), SpaceViewSystemExecutionError> { - let settings = ViewProperty::from_archetype::( - ctx.blueprint_db(), - ctx.blueprint_query, - space_view_id, - ); - - let mode = - settings.component_or_fallback::(ctx, self, state)?; + crate::view_query::query_ui(ctx, ui, state, space_view_id)?; list_item::list_item_scope(ui, "dataframe_view_selection_ui", |ui| { - //TODO(ab): ideally we'd drop the "Dataframe" part in the UI label - view_property_ui::(ctx, ui, space_view_id, self, state); - - ui.add_enabled_ui(mode == components::DataframeViewMode::TimeRange, |ui| { - view_property_ui::( - ctx, - ui, - space_view_id, - self, - state, - ); - }); - }); + let view_query = Query::try_from_blueprint(ctx, space_view_id)?; + //TODO(#7070): column order and sorting needs much love + ui.add_enabled_ui( + matches!(view_query.kind(ctx), QueryKind::Range { .. }), + |ui| { + view_property_ui::( + ctx, + ui, + space_view_id, + self, + state, + ); + }, + ); - Ok(()) + Ok(()) + }) } fn ui( @@ -167,23 +124,25 @@ mode sets the default time range to _everything_. You can override this in the s ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - let settings = ViewProperty::from_archetype::( - ctx.blueprint_db(), - ctx.blueprint_query, - query.space_view_id, - ); - - let mode = - settings.component_or_fallback::(ctx, self, state)?; - - // update state - let state = state.downcast_mut::()?; - state.mode = mode; - - match mode { - components::DataframeViewMode::LatestAt => latest_at_table_ui(ctx, ui, query), + let view_query = super::view_query::Query::try_from_blueprint(ctx, query.space_view_id)?; + let timeline_name = view_query.timeline_name(ctx); + let query_mode = view_query.kind(ctx); + + let Some(timeline) = ctx + .recording() + .timelines() + .find(|t| t.name() == &timeline_name) + else { + re_log::warn_once!("Could not find timeline {:?}.", timeline_name.as_str()); + //TODO(ab): we should have an error for that + return Ok(()); + }; - components::DataframeViewMode::TimeRange => { + match query_mode { + QueryKind::LatestAt { time } => { + latest_at_table_ui(ctx, ui, query, &LatestAtQuery::new(*timeline, time)); + } + QueryKind::Range { from, to } => { let time_range_table_order = ViewProperty::from_archetype::( ctx.blueprint_db(), @@ -195,9 +154,17 @@ mode sets the default time range to _everything_. You can override this in the s let sort_order = time_range_table_order .component_or_fallback::(ctx, self, state)?; - time_range_table_ui(ctx, ui, query, sort_key, sort_order); + time_range_table_ui( + ctx, + ui, + query, + sort_key, + sort_order, + timeline, + ResolvedTimeRange::new(from, to), + ); } - }; + } Ok(()) } diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index 7448ea0b0e57..abea5757a82f 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -1,14 +1,13 @@ use std::collections::{BTreeMap, BTreeSet}; use std::sync::Arc; -use re_chunk_store::{Chunk, RangeQuery, RowId}; +use re_chunk_store::{Chunk, LatestAtQuery, RangeQuery, RowId}; use re_data_ui::item_ui::entity_path_button; use re_entity_db::InstancePath; use re_log_types::{EntityPath, ResolvedTimeRange, TimeInt, Timeline}; use re_types::blueprint::components::{SortKey, SortOrder}; -use re_types_core::datatypes::TimeRange; use re_types_core::ComponentName; -use re_viewer_context::{Item, QueryRange, UiLayout, ViewQuery, ViewerContext}; +use re_viewer_context::{Item, UiLayout, ViewQuery, ViewerContext}; use crate::table_ui::{row_id_ui, table_ui}; @@ -33,6 +32,8 @@ pub(crate) fn time_range_table_ui( query: &ViewQuery<'_>, sort_key: SortKey, sort_order: SortOrder, + timeline: &Timeline, + resolved_time_range: ResolvedTimeRange, ) { re_tracing::profile_function!(); @@ -51,7 +52,7 @@ pub(crate) fn time_range_table_ui( .filter(|data_result| data_result.is_visible(ctx)) .flat_map(|data_result| { ctx.recording_store() - .all_components_on_timeline(&query.timeline, &data_result.entity_path) + .all_components_on_timeline(timeline, &data_result.entity_path) .unwrap_or_default() }) // TODO(#4466): make showing/hiding indicators components an explicit optional @@ -119,20 +120,12 @@ pub(crate) fn time_range_table_ui( .iter_all_data_results() .filter(|data_result| data_result.is_visible(ctx)) .flat_map(|data_result| { - let time_range = match &data_result.property_overrides.query_range { - QueryRange::TimeRange(time_range) => time_range.clone(), - QueryRange::LatestAt => TimeRange::AT_CURSOR, - }; - - let resolved_time_range = - ResolvedTimeRange::from_relative_time_range(&time_range, ctx.current_query().at()); - sorted_components.iter().flat_map(move |component| { entity_components_to_key_value_iter( ctx, &data_result.entity_path, component, - query.timeline, + *timeline, resolved_time_range, ) }) @@ -218,17 +211,17 @@ pub(crate) fn time_range_table_ui( } }; - let latest_at_query = query.latest_at_query(); - let entity_ui = |ui: &mut egui::Ui, entity_path: &EntityPath| { - entity_path_button( - ctx, - &latest_at_query, - ctx.recording(), - ui, - Some(query.space_view_id), - entity_path, - ); - }; + let entity_ui = + |ui: &mut egui::Ui, entity_path: &EntityPath, latest_at_query: &LatestAtQuery| { + entity_path_button( + ctx, + latest_at_query, + ctx.recording(), + ui, + Some(query.space_view_id), + entity_path, + ); + }; let time_ui = |ui: &mut egui::Ui, time: &TimeInt| { if ui @@ -245,20 +238,22 @@ pub(crate) fn time_range_table_ui( }; // Draw a single line of the table. This is called for each _visible_ row. - let latest_at_query = query.latest_at_query(); let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { let row_key = rows[row.index()]; let row_chunk = &rows_to_chunk[row_key]; let (entity_path, time, row_id) = row_key; + // Latest at query corresponding to the current time + let latest_at_query = LatestAtQuery::new(*timeline, *time); + match sort_key { SortKey::Entity => { - row.col(|ui| entity_ui(ui, entity_path)); + row.col(|ui| entity_ui(ui, entity_path, &latest_at_query)); row.col(|ui| time_ui(ui, time)); } SortKey::Time => { row.col(|ui| time_ui(ui, time)); - row.col(|ui| entity_ui(ui, entity_path)); + row.col(|ui| entity_ui(ui, entity_path, &latest_at_query)); } }; diff --git a/crates/viewer/re_space_view_dataframe/src/utils.rs b/crates/viewer/re_space_view_dataframe/src/utils.rs index e622e2cb413a..b5b2cc938ee9 100644 --- a/crates/viewer/re_space_view_dataframe/src/utils.rs +++ b/crates/viewer/re_space_view_dataframe/src/utils.rs @@ -22,7 +22,7 @@ pub(crate) fn sorted_visible_entity_path( pub(crate) fn sorted_instance_paths_for<'a>( entity_path: &'a EntityPath, store: &'a ChunkStore, - timeline: &'a Timeline, + timeline: &Timeline, latest_at_query: &'a LatestAtQuery, ) -> impl Iterator + 'a { re_tracing::profile_function!(); diff --git a/crates/viewer/re_space_view_dataframe/src/view_query.rs b/crates/viewer/re_space_view_dataframe/src/view_query.rs new file mode 100644 index 000000000000..dcf716abe7e8 --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/view_query.rs @@ -0,0 +1,287 @@ +use re_log_types::{TimeInt, TimelineName}; +use re_types::blueprint::{archetypes, components, datatypes}; +use re_types_core::Loggable as _; +use re_ui::UiExt as _; +use re_viewer_context::{ + SpaceViewId, SpaceViewState, SpaceViewSystemExecutionError, TimeDragValue, ViewerContext, +}; +use re_viewport_blueprint::ViewProperty; + +use crate::query_kind_ui::UiQueryKind; +use crate::visualizer_system::EmptySystem; + +/// The query kind for the dataframe view. +#[derive(Debug, Clone, Copy)] +pub(crate) enum QueryKind { + LatestAt { + time: TimeInt, + }, + Range { + from: TimeInt, + to: TimeInt, + //TODO(#7072): add PoV components + }, + //TODO(#7067): add selected components +} + +/// Helper for handling the dataframe view query blueprint. +pub(crate) enum Query { + FollowTimeline, + + Override { + timeline: TimelineName, + kind: QueryKind, + }, +} + +impl Query { + pub(crate) fn try_from_blueprint( + ctx: &ViewerContext<'_>, + space_view_id: SpaceViewId, + ) -> Result { + let property = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query, + space_view_id, + ); + + // The presence (or not) of the timeline component determines if the view should follow the + // time panel timeline/latest at query, or override it. + let Some(timeline) = property + .component_or_empty::()? + .map(|t| t.into()) + else { + return Ok(Self::FollowTimeline); + }; + + let kind = property + .component_or_empty::()? + .unwrap_or(components::QueryKind::LatestAt); + + let kind = match kind { + components::QueryKind::LatestAt => { + let time = property + .component_or_empty::()? + .unwrap_or_default() + .query_for_timeline(&timeline) + .map_or(TimeInt::MAX, |q| q.time.into()); + + QueryKind::LatestAt { time } + } + components::QueryKind::TimeRange => { + let (from, to) = property + .component_or_empty::()? + .unwrap_or_default() + .query_for_timeline(&timeline) + .map_or((TimeInt::MIN, TimeInt::MAX), |q| { + (q.start.into(), q.end.into()) + }); + + QueryKind::Range { from, to } + } + }; + + Ok(Self::Override { timeline, kind }) + } + + /// Get the timeline name for the query + #[inline] + pub(crate) fn timeline_name(&self, ctx: &ViewerContext<'_>) -> TimelineName { + match self { + Self::FollowTimeline => *ctx.rec_cfg.time_ctrl.read().timeline().name(), + Self::Override { timeline, .. } => *timeline, + } + } + + /// Get the kind for the query + #[inline] + pub(crate) fn kind(&self, ctx: &ViewerContext<'_>) -> QueryKind { + match self { + Self::FollowTimeline => { + let time_ctrl = ctx.rec_cfg.time_ctrl.read(); + QueryKind::LatestAt { + time: time_ctrl.time_int().unwrap_or(TimeInt::MAX), + } + } + Self::Override { kind, .. } => *kind, + } + } + + /// Save the query kind for the given timeline to the blueprint. + pub(crate) fn save_kind_for_timeline( + ctx: &ViewerContext<'_>, + space_view_id: SpaceViewId, + timeline_name: &TimelineName, + query_kind: &QueryKind, + ) -> Result<(), SpaceViewSystemExecutionError> { + let property = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query, + space_view_id, + ); + + match query_kind { + QueryKind::LatestAt { time } => { + let mut latest_at_queries = property + .component_or_empty::()? + .unwrap_or_default(); + + latest_at_queries.set_query_for_timeline(datatypes::LatestAtQuery { + timeline: timeline_name.as_str().into(), + time: (*time).into(), + }); + + property.save_blueprint_component(ctx, &latest_at_queries); + property.save_blueprint_component(ctx, &components::QueryKind::LatestAt); + } + QueryKind::Range { from, to } => { + let mut time_range_queries = property + .component_or_empty::()? + .unwrap_or_default(); + + time_range_queries.set_query_for_timeline(datatypes::TimeRangeQuery { + timeline: timeline_name.as_str().into(), + start: (*from).into(), + end: (*to).into(), + }); + + property.save_blueprint_component(ctx, &time_range_queries); + property.save_blueprint_component(ctx, &components::QueryKind::TimeRange); + } + }; + + Ok(()) + } +} + +pub(crate) fn query_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + state: &dyn SpaceViewState, + space_view_id: SpaceViewId, +) -> Result<(), SpaceViewSystemExecutionError> { + let property = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query, + space_view_id, + ); + + // The existence of a timeline component determines if we are in follow time panel or + // override mode. + let timeline_component = property.component_or_empty::()?; + let timeline_name: Option = timeline_component.as_ref().map(|t| t.into()); + + let timeline = timeline_name.and_then(|timeline_name| { + ctx.recording() + .timelines() + .find(|t| t.name() == &timeline_name) + }); + + ui.add_space(5.0); + + let mut override_query = timeline.is_some(); + let changed = ui.selectable_toggle(|ui| { + ui.selectable_value(&mut override_query, false, "Follow timeline") + .changed() + || ui + .selectable_value(&mut override_query, true, "Override") + .changed() + }); + + if changed { + if override_query { + let time_ctrl = ctx.rec_cfg.time_ctrl.read(); + let timeline = time_ctrl.timeline(); + + // UX least surprising behavior: when switching from "follow" to "override", we ensure + // that the override configuration defaults to the current timeline configuration, so + // the table content remains stable. + property.save_blueprint_component( + ctx, + &components::TimelineName::from(timeline.name().as_str()), + ); + Query::save_kind_for_timeline( + ctx, + space_view_id, + timeline.name(), + &QueryKind::LatestAt { + time: time_ctrl.time_int().unwrap_or(TimeInt::MAX), + }, + )?; + } else { + property.reset_blueprint_component::(ctx); + } + } + + if override_query { + override_ui(ctx, ui, state, space_view_id, &property) + } else { + Ok(()) + } +} + +fn override_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + state: &dyn SpaceViewState, + space_view_id: SpaceViewId, + property: &ViewProperty<'_>, +) -> Result<(), SpaceViewSystemExecutionError> { + egui::Grid::new("dataframe_view_query_ui") + .num_columns(2) + .spacing(egui::vec2(8.0, 10.0)) + .show(ui, |ui| { + ui.grid_left_hand_label("Timeline"); + + let component_name = components::TimelineName::name(); + + //TODO(ab, andreas): maybe have a `singleline_edit_ui` wrapper directly in `ViewProperty` + ctx.component_ui_registry.singleline_edit_ui( + &property.query_context(ctx, state), + ui, + ctx.blueprint_db(), + &property.blueprint_store_path, + component_name, + property.component_raw(component_name).as_deref(), + // we don't need to provide a fallback here as the timeline should be present by definition + &EmptySystem {}, + ); + + ui.end_row(); + + ui.grid_left_hand_label("Showing"); + + let timeline = property + .component_or_empty::()? + .map(|t| t.into()) + .and_then(|timeline_name: TimelineName| { + ctx.recording() + .timelines() + .find(|t| t.name() == &timeline_name) + .copied() + }) + .unwrap_or(*ctx.rec_cfg.time_ctrl.read().timeline()); + let timeline_name = timeline.name(); + + let query = Query::try_from_blueprint(ctx, space_view_id)?; + let mut ui_query_kind: UiQueryKind = query.kind(ctx).into(); + let time_drag_value = if let Some(times) = ctx.recording().time_histogram(&timeline) { + TimeDragValue::from_time_histogram(times) + } else { + TimeDragValue::from_time_range(0..=0) + }; + let changed = + ui_query_kind.ui(ctx, ui, &time_drag_value, timeline.name(), timeline.typ()); + if changed { + Query::save_kind_for_timeline( + ctx, + space_view_id, + timeline_name, + &ui_query_kind.into(), + )?; + } + + Ok(()) + }) + .inner +} diff --git a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs index b81e71f7eb26..4dd334f2c5a7 100644 --- a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs @@ -5,18 +5,21 @@ pub use re_types::blueprint::components::ActiveTab; pub use re_types::blueprint::components::BackgroundKind; pub use re_types::blueprint::components::ColumnShare; pub use re_types::blueprint::components::Corner2D; -pub use re_types::blueprint::components::DataframeViewMode; pub use re_types::blueprint::components::IncludedContent; pub use re_types::blueprint::components::Interactive; +pub use re_types::blueprint::components::LatestAtQueries; pub use re_types::blueprint::components::LockRangeDuringZoom; pub use re_types::blueprint::components::PanelState; pub use re_types::blueprint::components::QueryExpression; +pub use re_types::blueprint::components::QueryKind; pub use re_types::blueprint::components::RowShare; pub use re_types::blueprint::components::SortKey; pub use re_types::blueprint::components::SortOrder; pub use re_types::blueprint::components::SpaceViewClass; pub use re_types::blueprint::components::SpaceViewOrigin; pub use re_types::blueprint::components::TensorDimensionIndexSlider; +pub use re_types::blueprint::components::TimeRangeQueries; +pub use re_types::blueprint::components::TimelineName; pub use re_types::blueprint::components::ViewFit; pub use re_types::blueprint::components::ViewerRecommendationHash; pub use re_types::blueprint::components::Visible; @@ -42,14 +45,15 @@ 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) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) @@ -58,6 +62,8 @@ 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/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 4d8f41023cdd..7789e6ad2775 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -83,13 +83,6 @@ fn generate_component_reflection() -> Result::name(), - ComponentReflection { - docstring_md: "The kind of table displayed by the dataframe view", - placeholder: Some(DataframeViewMode::default().to_arrow()?), - }, - ), ( ::name(), ComponentReflection { @@ -118,6 +111,13 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "Configuration for latest at queries.\n\nNote: configuration as saved on a per-timeline basis.", + placeholder: Some(LatestAtQueries::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -139,6 +139,13 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "The kind of query displayed by the dataframe view", + placeholder: Some(QueryKind::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -195,6 +202,20 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "Configuration for time range queries.\n\nNote: configuration as saved on a per-timeline basis.", + placeholder: Some(TimeRangeQueries::default().to_arrow()?), + }, + ), + ( + ::name(), + ComponentReflection { + docstring_md: "A timeline identified by its name.", + placeholder: Some(TimelineName::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -733,14 +754,27 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { }, ), ( - ArchetypeName::new("rerun.blueprint.archetypes.DataframeViewMode"), + ArchetypeName::new("rerun.blueprint.archetypes.DataframeQuery"), ArchetypeReflection { - display_name: "Dataframe view mode", - docstring_md: "Configuration for the dataframe view", + display_name: "Dataframe query", + docstring_md: "The query for the dataframe view.", fields: vec![ ArchetypeFieldReflection { component_name : - "rerun.blueprint.components.DataframeViewMode".into(), display_name : - "Mode", docstring_md : "The kind of table to display", }, + "rerun.blueprint.components.TimelineName".into(), display_name : + "Timeline", docstring_md : + "The timeline for this query.\n\nIf unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype.", + }, ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.QueryKind".into(), display_name : "Kind", + docstring_md : "Kind of query: latest-at or range.", }, + ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.LatestAtQueries".into(), display_name : + "Latest at queries", docstring_md : + "Configuration for latest-at queries.\n\nNote: configuration as saved on a per-timeline basis.", + }, ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.TimeRangeQueries".into(), display_name : + "Time range queries", docstring_md : + "Configuration for the time range queries.\n\nNote: configuration as saved on a per-timeline basis.", + }, ], }, ), diff --git a/crates/viewer/re_viewer_context/src/time_drag_value.rs b/crates/viewer/re_viewer_context/src/time_drag_value.rs index 1c973cc5bc69..1f7788795f63 100644 --- a/crates/viewer/re_viewer_context/src/time_drag_value.rs +++ b/crates/viewer/re_viewer_context/src/time_drag_value.rs @@ -130,7 +130,7 @@ impl TimeDragValue { time_range = low_bound_override.0.at_least(*time_range.start())..=*time_range.end(); } - let mut time_unit = (value.0 - offset) as f32 / factor; + let mut time_unit = (value.0.saturating_sub(offset)) as f32 / factor; let time_range = (*time_range.start() - offset) as f32 / factor ..=(*time_range.end() - offset) as f32 / factor; diff --git a/crates/viewer/re_viewport_blueprint/src/view_properties.rs b/crates/viewer/re_viewport_blueprint/src/view_properties.rs index a0b96f7d7dca..a5b04b71e835 100644 --- a/crates/viewer/re_viewport_blueprint/src/view_properties.rs +++ b/crates/viewer/re_viewport_blueprint/src/view_properties.rs @@ -29,7 +29,10 @@ impl From for SpaceViewSystemExecutionError { /// Utility for querying view properties. pub struct ViewProperty<'a> { + /// Entity path in the blueprint store where all components of this view property archetype are + /// stored. pub blueprint_store_path: EntityPath, + archetype_name: ArchetypeName, component_names: Vec, query_results: LatestAtResults, @@ -133,7 +136,7 @@ impl<'a> ViewProperty<'a> { .map(|value| value.unwrap_or_default()) } - fn component_raw( + pub fn component_raw( &self, component_name: ComponentName, ) -> Option> { @@ -194,7 +197,8 @@ impl<'a> ViewProperty<'a> { }) } - fn query_context( + /// Create a query context for this view property. + pub fn query_context( &self, viewer_ctx: &'a ViewerContext<'a>, view_state: &'a dyn re_viewer_context::SpaceViewState, @@ -210,6 +214,8 @@ impl<'a> ViewProperty<'a> { } } +/// Entity path in the blueprint store where all components of the given view property archetype are +/// stored. pub fn entity_path_for_view_property( space_view_id: SpaceViewId, _blueprint_entity_tree: &EntityTree, diff --git a/rerun_cpp/src/rerun/blueprint/archetypes.hpp b/rerun_cpp/src/rerun/blueprint/archetypes.hpp index cb7eb69e8012..39a6b0f8053b 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes.hpp @@ -4,7 +4,7 @@ #include "blueprint/archetypes/background.hpp" #include "blueprint/archetypes/container_blueprint.hpp" -#include "blueprint/archetypes/dataframe_view_mode.hpp" +#include "blueprint/archetypes/dataframe_query.hpp" #include "blueprint/archetypes/panel_blueprint.hpp" #include "blueprint/archetypes/plot_legend.hpp" #include "blueprint/archetypes/scalar_axis.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes index a8d7bcacc964..eae6a969df5b 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes @@ -5,8 +5,8 @@ background.cpp linguist-generated=true background.hpp linguist-generated=true container_blueprint.cpp linguist-generated=true container_blueprint.hpp linguist-generated=true -dataframe_view_mode.cpp linguist-generated=true -dataframe_view_mode.hpp linguist-generated=true +dataframe_query.cpp linguist-generated=true +dataframe_query.hpp linguist-generated=true panel_blueprint.cpp linguist-generated=true panel_blueprint.hpp linguist-generated=true plot_legend.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp new file mode 100644 index 000000000000..0bd53a79fd93 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.cpp @@ -0,0 +1,49 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +#include "dataframe_query.hpp" + +#include "../../collection_adapter_builtins.hpp" + +namespace rerun::blueprint::archetypes {} + +namespace rerun { + + Result> + AsComponents::serialize( + const blueprint::archetypes::DataframeQuery& archetype + ) { + using namespace blueprint::archetypes; + std::vector cells; + cells.reserve(5); + + if (archetype.timeline.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.timeline.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.kind.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.kind.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.latest_at_queries.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.latest_at_queries.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.time_range_queries.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.time_range_queries.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + { + auto indicator = DataframeQuery::IndicatorComponent(); + auto result = ComponentBatch::from_loggable(indicator); + RR_RETURN_NOT_OK(result.error); + cells.emplace_back(std::move(result.value)); + } + + return cells; + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp new file mode 100644 index 000000000000..b5824179e677 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_query.hpp @@ -0,0 +1,107 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +#pragma once + +#include "../../blueprint/components/latest_at_queries.hpp" +#include "../../blueprint/components/query_kind.hpp" +#include "../../blueprint/components/time_range_queries.hpp" +#include "../../blueprint/components/timeline_name.hpp" +#include "../../collection.hpp" +#include "../../compiler_utils.hpp" +#include "../../component_batch.hpp" +#include "../../indicator_component.hpp" +#include "../../result.hpp" + +#include +#include +#include +#include + +namespace rerun::blueprint::archetypes { + /// **Archetype**: The query for the dataframe view. + struct DataframeQuery { + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + std::optional timeline; + + /// Kind of query: latest-at or range. + std::optional kind; + + /// Configuration for latest-at queries. + /// + /// Note: configuration as saved on a per-timeline basis. + std::optional latest_at_queries; + + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. + std::optional time_range_queries; + + public: + static constexpr const char IndicatorComponentName[] = + "rerun.blueprint.components.DataframeQueryIndicator"; + + /// Indicator component, used to identify the archetype when converting to a list of components. + using IndicatorComponent = rerun::components::IndicatorComponent; + + public: + DataframeQuery() = default; + DataframeQuery(DataframeQuery&& other) = default; + + /// The timeline for this query. + /// + /// If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + DataframeQuery with_timeline(rerun::blueprint::components::TimelineName _timeline) && { + timeline = std::move(_timeline); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Kind of query: latest-at or range. + DataframeQuery with_kind(rerun::blueprint::components::QueryKind _kind) && { + kind = std::move(_kind); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Configuration for latest-at queries. + /// + /// Note: configuration as saved on a per-timeline basis. + DataframeQuery with_latest_at_queries( + rerun::blueprint::components::LatestAtQueries _latest_at_queries + ) && { + latest_at_queries = std::move(_latest_at_queries); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Configuration for the time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. + DataframeQuery with_time_range_queries( + rerun::blueprint::components::TimeRangeQueries _time_range_queries + ) && { + time_range_queries = std::move(_time_range_queries); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + }; + +} // namespace rerun::blueprint::archetypes + +namespace rerun { + /// \private + template + struct AsComponents; + + /// \private + template <> + struct AsComponents { + /// Serialize all set component batches. + static Result> serialize( + const blueprint::archetypes::DataframeQuery& archetype + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp deleted file mode 100644 index 4c6aea965abc..000000000000 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -#include "dataframe_view_mode.hpp" - -#include "../../collection_adapter_builtins.hpp" - -namespace rerun::blueprint::archetypes {} - -namespace rerun { - - Result> - AsComponents::serialize( - const blueprint::archetypes::DataframeViewMode& archetype - ) { - using namespace blueprint::archetypes; - std::vector cells; - cells.reserve(2); - - if (archetype.mode.has_value()) { - auto result = ComponentBatch::from_loggable(archetype.mode.value()); - RR_RETURN_NOT_OK(result.error); - cells.push_back(std::move(result.value)); - } - { - auto indicator = DataframeViewMode::IndicatorComponent(); - auto result = ComponentBatch::from_loggable(indicator); - RR_RETURN_NOT_OK(result.error); - cells.emplace_back(std::move(result.value)); - } - - return cells; - } -} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp deleted file mode 100644 index 5a2d971130e0..000000000000 --- a/rerun_cpp/src/rerun/blueprint/archetypes/dataframe_view_mode.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -#pragma once - -#include "../../blueprint/components/dataframe_view_mode.hpp" -#include "../../collection.hpp" -#include "../../compiler_utils.hpp" -#include "../../component_batch.hpp" -#include "../../indicator_component.hpp" -#include "../../result.hpp" - -#include -#include -#include -#include - -namespace rerun::blueprint::archetypes { - /// **Archetype**: Configuration for the dataframe view - struct DataframeViewMode { - /// The kind of table to display - std::optional mode; - - public: - static constexpr const char IndicatorComponentName[] = - "rerun.blueprint.components.DataframeViewModeIndicator"; - - /// Indicator component, used to identify the archetype when converting to a list of components. - using IndicatorComponent = rerun::components::IndicatorComponent; - - public: - DataframeViewMode() = default; - DataframeViewMode(DataframeViewMode&& other) = default; - - /// The kind of table to display - DataframeViewMode with_mode(rerun::blueprint::components::DataframeViewMode _mode) && { - mode = std::move(_mode); - // See: https://github.com/rerun-io/rerun/issues/4027 - RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) - } - }; - -} // namespace rerun::blueprint::archetypes - -namespace rerun { - /// \private - template - struct AsComponents; - - /// \private - template <> - struct AsComponents { - /// Serialize all set component batches. - static Result> serialize( - const blueprint::archetypes::DataframeViewMode& archetype - ); - }; -} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index f157b8a7db1f..19657a843547 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -9,14 +9,15 @@ #include "blueprint/components/column_share.hpp" #include "blueprint/components/container_kind.hpp" #include "blueprint/components/corner2d.hpp" -#include "blueprint/components/dataframe_view_mode.hpp" #include "blueprint/components/grid_columns.hpp" #include "blueprint/components/included_content.hpp" #include "blueprint/components/included_space_view.hpp" #include "blueprint/components/interactive.hpp" +#include "blueprint/components/latest_at_queries.hpp" #include "blueprint/components/lock_range_during_zoom.hpp" #include "blueprint/components/panel_state.hpp" #include "blueprint/components/query_expression.hpp" +#include "blueprint/components/query_kind.hpp" #include "blueprint/components/root_container.hpp" #include "blueprint/components/row_share.hpp" #include "blueprint/components/sort_key.hpp" @@ -25,6 +26,8 @@ #include "blueprint/components/space_view_maximized.hpp" #include "blueprint/components/space_view_origin.hpp" #include "blueprint/components/tensor_dimension_index_slider.hpp" +#include "blueprint/components/time_range_queries.hpp" +#include "blueprint/components/timeline_name.hpp" #include "blueprint/components/view_fit.hpp" #include "blueprint/components/viewer_recommendation_hash.hpp" #include "blueprint/components/visible.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/components/.gitattributes b/rerun_cpp/src/rerun/blueprint/components/.gitattributes index 62e282550cc4..96df82b452ea 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -11,16 +11,18 @@ container_kind.cpp linguist-generated=true container_kind.hpp linguist-generated=true corner2d.cpp linguist-generated=true corner2d.hpp linguist-generated=true -dataframe_view_mode.cpp linguist-generated=true -dataframe_view_mode.hpp linguist-generated=true grid_columns.hpp linguist-generated=true included_content.hpp linguist-generated=true included_space_view.hpp linguist-generated=true interactive.hpp linguist-generated=true +latest_at_queries.cpp linguist-generated=true +latest_at_queries.hpp linguist-generated=true lock_range_during_zoom.hpp linguist-generated=true panel_state.cpp linguist-generated=true panel_state.hpp linguist-generated=true query_expression.hpp linguist-generated=true +query_kind.cpp linguist-generated=true +query_kind.hpp linguist-generated=true root_container.hpp linguist-generated=true row_share.hpp linguist-generated=true sort_key.cpp linguist-generated=true @@ -31,6 +33,9 @@ space_view_class.hpp linguist-generated=true space_view_maximized.hpp linguist-generated=true space_view_origin.hpp linguist-generated=true tensor_dimension_index_slider.hpp linguist-generated=true +time_range_queries.cpp linguist-generated=true +time_range_queries.hpp linguist-generated=true +timeline_name.hpp linguist-generated=true view_fit.cpp linguist-generated=true view_fit.hpp linguist-generated=true viewer_recommendation_hash.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp new file mode 100644 index 000000000000..6f951ad7fb76 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.cpp @@ -0,0 +1,81 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +#include "latest_at_queries.hpp" + +#include "../../blueprint/datatypes/latest_at_query.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; + } + + Result> + Loggable::to_arrow( + const blueprint::components::LatestAtQueries* 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; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::LatestAtQueries* 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.queries.data()) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + value_builder, + element.queries.data(), + element.queries.size() + ) + ); + } + } + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp new file mode 100644 index 000000000000..d570ac94ba6a --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/latest_at_queries.hpp @@ -0,0 +1,65 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +#pragma once + +#include "../../blueprint/datatypes/latest_at_query.hpp" +#include "../../collection.hpp" +#include "../../result.hpp" + +#include +#include +#include + +namespace arrow { + class Array; + class DataType; + class ListBuilder; +} // namespace arrow + +namespace rerun::blueprint::components { + /// **Component**: Configuration for latest at queries. + /// + /// Note: configuration as saved on a per-timeline basis. + struct LatestAtQueries { + rerun::Collection queries; + + public: + LatestAtQueries() = default; + + LatestAtQueries(rerun::Collection queries_) + : queries(std::move(queries_)) {} + + LatestAtQueries& operator=( + rerun::Collection queries_ + ) { + queries = std::move(queries_); + return *this; + } + }; +} // namespace rerun::blueprint::components + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.LatestAtQueries"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: components::LatestAtQueries` into an arrow array. + static Result> to_arrow( + const blueprint::components::LatestAtQueries* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::LatestAtQueries* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.cpp b/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp similarity index 67% rename from rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.cpp rename to rerun_cpp/src/rerun/blueprint/components/query_kind.cpp index 575a0868bbe1..a6e0297f884e 100644 --- a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/query_kind.cpp @@ -1,43 +1,40 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". -#include "dataframe_view_mode.hpp" +#include "query_kind.hpp" #include #include namespace rerun { const std::shared_ptr& - Loggable::arrow_datatype() { + Loggable::arrow_datatype() { static const auto datatype = arrow::uint8(); return datatype; } - Result> - Loggable::to_arrow( - const blueprint::components::DataframeViewMode* instances, size_t num_instances - ) { + Result> Loggable::to_arrow( + const blueprint::components::QueryKind* 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 - ) - ); + 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; } - rerun::Error Loggable::fill_arrow_array_builder( - arrow::UInt8Builder* builder, const blueprint::components::DataframeViewMode* elements, + rerun::Error Loggable::fill_arrow_array_builder( + arrow::UInt8Builder* builder, const blueprint::components::QueryKind* elements, size_t num_elements ) { if (builder == nullptr) { diff --git a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.hpp b/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp similarity index 59% rename from rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.hpp rename to rerun_cpp/src/rerun/blueprint/components/query_kind.hpp index 7e03b018ab04..83ada16ad531 100644 --- a/rerun_cpp/src/rerun/blueprint/components/dataframe_view_mode.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/query_kind.hpp @@ -1,5 +1,5 @@ // DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs -// Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". #pragma once @@ -20,18 +20,13 @@ namespace arrow { } // namespace arrow namespace rerun::blueprint::components { - /// **Component**: The kind of table displayed by the dataframe view - enum class DataframeViewMode : uint8_t { + /// **Component**: The kind of query displayed by the dataframe view + enum class QueryKind : uint8_t { - /// Display the entity values at the current time. - /// - /// In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. + /// Query LatestAt = 1, - /// Display a temporal table of entity values. - /// - /// In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - /// timestamp shown are determined by each view entity's visible time range setting. + /// Time range query. TimeRange = 2, }; } // namespace rerun::blueprint::components @@ -42,20 +37,20 @@ namespace rerun { /// \private template <> - struct Loggable { - static constexpr const char Name[] = "rerun.blueprint.components.DataframeViewMode"; + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.QueryKind"; /// Returns the arrow data type this type corresponds to. static const std::shared_ptr& arrow_datatype(); - /// Serializes an array of `rerun::blueprint:: components::DataframeViewMode` into an arrow array. + /// Serializes an array of `rerun::blueprint:: components::QueryKind` into an arrow array. static Result> to_arrow( - const blueprint::components::DataframeViewMode* instances, size_t num_instances + const blueprint::components::QueryKind* instances, size_t num_instances ); /// Fills an arrow array builder with an array of this type. static rerun::Error fill_arrow_array_builder( - arrow::UInt8Builder* builder, const blueprint::components::DataframeViewMode* elements, + arrow::UInt8Builder* builder, const blueprint::components::QueryKind* elements, size_t num_elements ); }; diff --git a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp new file mode 100644 index 000000000000..924d17db7a1c --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.cpp @@ -0,0 +1,81 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +#include "time_range_queries.hpp" + +#include "../../blueprint/datatypes/time_range_query.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; + } + + Result> + Loggable::to_arrow( + const blueprint::components::TimeRangeQueries* 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; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::TimeRangeQueries* 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.queries.data()) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + value_builder, + element.queries.data(), + element.queries.size() + ) + ); + } + } + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp new file mode 100644 index 000000000000..4ecee518f49b --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/time_range_queries.hpp @@ -0,0 +1,65 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +#pragma once + +#include "../../blueprint/datatypes/time_range_query.hpp" +#include "../../collection.hpp" +#include "../../result.hpp" + +#include +#include +#include + +namespace arrow { + class Array; + class DataType; + class ListBuilder; +} // namespace arrow + +namespace rerun::blueprint::components { + /// **Component**: Configuration for time range queries. + /// + /// Note: configuration as saved on a per-timeline basis. + struct TimeRangeQueries { + rerun::Collection queries; + + public: + TimeRangeQueries() = default; + + TimeRangeQueries(rerun::Collection queries_) + : queries(std::move(queries_)) {} + + TimeRangeQueries& operator=( + rerun::Collection queries_ + ) { + queries = std::move(queries_); + return *this; + } + }; +} // namespace rerun::blueprint::components + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.TimeRangeQueries"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: components::TimeRangeQueries` into an arrow array. + static Result> to_arrow( + const blueprint::components::TimeRangeQueries* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::ListBuilder* builder, const blueprint::components::TimeRangeQueries* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/timeline_name.hpp b/rerun_cpp/src/rerun/blueprint/components/timeline_name.hpp new file mode 100644 index 000000000000..7b068de8a301 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/timeline_name.hpp @@ -0,0 +1,63 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs". + +#pragma once + +#include "../../datatypes/utf8.hpp" +#include "../../result.hpp" + +#include +#include +#include +#include + +namespace rerun::blueprint::components { + /// **Component**: A timeline identified by its name. + struct TimelineName { + rerun::datatypes::Utf8 value; + + public: + TimelineName() = default; + + TimelineName(rerun::datatypes::Utf8 value_) : value(std::move(value_)) {} + + TimelineName& operator=(rerun::datatypes::Utf8 value_) { + value = std::move(value_); + return *this; + } + + TimelineName(std::string value_) : value(std::move(value_)) {} + + TimelineName& operator=(std::string value_) { + value = std::move(value_); + return *this; + } + + /// Cast to the underlying Utf8 datatype + operator rerun::datatypes::Utf8() const { + return value; + } + }; +} // namespace rerun::blueprint::components + +namespace rerun { + static_assert(sizeof(rerun::datatypes::Utf8) == sizeof(blueprint::components::TimelineName)); + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.TimelineName"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype() { + return Loggable::arrow_datatype(); + } + + /// Serializes an array of `rerun::blueprint:: components::TimelineName` into an arrow array. + static Result> to_arrow( + const blueprint::components::TimelineName* instances, size_t num_instances + ) { + return Loggable::to_arrow(&instances->value, num_instances); + } + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes.hpp b/rerun_cpp/src/rerun/blueprint/datatypes.hpp index 429e06dea010..0908c7ae3a56 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/datatypes.hpp @@ -2,5 +2,7 @@ #pragma once +#include "blueprint/datatypes/latest_at_query.hpp" #include "blueprint/datatypes/tensor_dimension_index_slider.hpp" +#include "blueprint/datatypes/time_range_query.hpp" #include "blueprint/datatypes/utf8list.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes index 914f011d695c..38ef06171ae0 100644 --- a/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes @@ -1,7 +1,11 @@ # DO NOT EDIT! This file is generated by crates/build/re_types_builder/src/lib.rs .gitattributes linguist-generated=true +latest_at_query.cpp linguist-generated=true +latest_at_query.hpp linguist-generated=true tensor_dimension_index_slider.cpp linguist-generated=true tensor_dimension_index_slider.hpp linguist-generated=true +time_range_query.cpp linguist-generated=true +time_range_query.hpp linguist-generated=true utf8list.cpp linguist-generated=true utf8list.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp new file mode 100644 index 000000000000..490f5df72cd9 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.cpp @@ -0,0 +1,86 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +#include "latest_at_query.hpp" + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" + +#include +#include + +namespace rerun::blueprint::datatypes {} + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::struct_({ + arrow::field("timeline", Loggable::arrow_datatype(), false), + arrow::field("time", Loggable::arrow_datatype(), false), + }); + return datatype; + } + + Result> Loggable::to_arrow( + const blueprint::datatypes::LatestAtQuery* 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; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::LatestAtQuery* 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 field_builder = static_cast(builder->field_builder(0)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].timeline, + 1 + )); + } + } + { + auto field_builder = static_cast(builder->field_builder(1)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].time, + 1 + )); + } + } + ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast(num_elements), nullptr)); + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp new file mode 100644 index 000000000000..8538eeed7697 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/latest_at_query.hpp @@ -0,0 +1,56 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +#pragma once + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" +#include "../../result.hpp" + +#include +#include + +namespace arrow { + class Array; + class DataType; + class StructBuilder; +} // namespace arrow + +namespace rerun::blueprint::datatypes { + /// **Datatype**: Latest at query configuration for a specific timeline. + struct LatestAtQuery { + /// Name of the timeline this applies to. + rerun::datatypes::Utf8 timeline; + + /// Time value to use for this query. + rerun::datatypes::TimeInt time; + + public: + LatestAtQuery() = default; + }; +} // namespace rerun::blueprint::datatypes + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.datatypes.LatestAtQuery"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: datatypes::LatestAtQuery` into an arrow array. + static Result> to_arrow( + const blueprint::datatypes::LatestAtQuery* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::LatestAtQuery* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp new file mode 100644 index 000000000000..1ce005eba6b8 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.cpp @@ -0,0 +1,98 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +#include "time_range_query.hpp" + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" + +#include +#include + +namespace rerun::blueprint::datatypes {} + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::struct_({ + arrow::field("timeline", Loggable::arrow_datatype(), false), + arrow::field("start", Loggable::arrow_datatype(), false), + arrow::field("end", Loggable::arrow_datatype(), false), + }); + return datatype; + } + + Result> Loggable::to_arrow( + const blueprint::datatypes::TimeRangeQuery* 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; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::TimeRangeQuery* 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 field_builder = static_cast(builder->field_builder(0)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].timeline, + 1 + )); + } + } + { + auto field_builder = static_cast(builder->field_builder(1)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].start, + 1 + )); + } + } + { + auto field_builder = static_cast(builder->field_builder(2)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + field_builder, + &elements[elem_idx].end, + 1 + )); + } + } + ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast(num_elements), nullptr)); + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp new file mode 100644 index 000000000000..91e71a00acd2 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/time_range_query.hpp @@ -0,0 +1,59 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +#pragma once + +#include "../../datatypes/time_int.hpp" +#include "../../datatypes/utf8.hpp" +#include "../../result.hpp" + +#include +#include + +namespace arrow { + class Array; + class DataType; + class StructBuilder; +} // namespace arrow + +namespace rerun::blueprint::datatypes { + /// **Datatype**: Time range query configuration for a specific timeline. + struct TimeRangeQuery { + /// Name of the timeline this applies to. + rerun::datatypes::Utf8 timeline; + + /// Beginning of the time range. + rerun::datatypes::TimeInt start; + + /// End of the time range (inclusive). + rerun::datatypes::TimeInt end; + + public: + TimeRangeQuery() = default; + }; +} // namespace rerun::blueprint::datatypes + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.datatypes.TimeRangeQuery"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: datatypes::TimeRangeQuery` into an arrow array. + static Result> to_arrow( + const blueprint::datatypes::TimeRangeQuery* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::TimeRangeQuery* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes index 19180594d84a..58d01529a89b 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes @@ -4,7 +4,7 @@ __init__.py linguist-generated=true background.py linguist-generated=true container_blueprint.py linguist-generated=true -dataframe_view_mode.py linguist-generated=true +dataframe_query.py linguist-generated=true panel_blueprint.py linguist-generated=true plot_legend.py linguist-generated=true scalar_axis.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py index 61638524540e..c07e1563847d 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py @@ -4,7 +4,7 @@ from .background import Background from .container_blueprint import ContainerBlueprint -from .dataframe_view_mode import DataframeViewMode +from .dataframe_query import DataframeQuery from .panel_blueprint import PanelBlueprint from .plot_legend import PlotLegend from .scalar_axis import ScalarAxis @@ -21,7 +21,7 @@ __all__ = [ "Background", "ContainerBlueprint", - "DataframeViewMode", + "DataframeQuery", "PanelBlueprint", "PlotLegend", "ScalarAxis", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py new file mode 100644 index 000000000000..733490f56550 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_query.py @@ -0,0 +1,123 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_query.fbs". + +# You can extend this class by creating a "DataframeQueryExt" class in "dataframe_query_ext.py". + +from __future__ import annotations + +from typing import Any + +from attrs import define, field + +from ... import datatypes +from ..._baseclasses import ( + Archetype, +) +from ...blueprint import components as blueprint_components +from ...error_utils import catch_and_log_exceptions + +__all__ = ["DataframeQuery"] + + +@define(str=False, repr=False, init=False) +class DataframeQuery(Archetype): + """**Archetype**: The query for the dataframe view.""" + + def __init__( + self: Any, + *, + timeline: datatypes.Utf8Like | None = None, + kind: blueprint_components.QueryKindLike | None = None, + latest_at_queries: blueprint_components.LatestAtQueriesLike | None = None, + time_range_queries: blueprint_components.TimeRangeQueriesLike | None = None, + ): + """ + Create a new instance of the DataframeQuery archetype. + + Parameters + ---------- + timeline: + The timeline for this query. + + If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + kind: + Kind of query: latest-at or range. + latest_at_queries: + Configuration for latest-at queries. + + Note: configuration as saved on a per-timeline basis. + time_range_queries: + Configuration for the time range queries. + + Note: configuration as saved on a per-timeline basis. + + """ + + # You can define your own __init__ function as a member of DataframeQueryExt in dataframe_query_ext.py + with catch_and_log_exceptions(context=self.__class__.__name__): + self.__attrs_init__( + timeline=timeline, kind=kind, latest_at_queries=latest_at_queries, time_range_queries=time_range_queries + ) + return + self.__attrs_clear__() + + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( + timeline=None, # type: ignore[arg-type] + kind=None, # type: ignore[arg-type] + latest_at_queries=None, # type: ignore[arg-type] + time_range_queries=None, # type: ignore[arg-type] + ) + + @classmethod + def _clear(cls) -> DataframeQuery: + """Produce an empty DataframeQuery, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + + timeline: blueprint_components.TimelineNameBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.TimelineNameBatch._optional, # type: ignore[misc] + ) + # The timeline for this query. + # + # If unset, use the time panel's timeline and a latest at query, ignoring all other components of this archetype. + # + # (Docstring intentionally commented out to hide this field from the docs) + + kind: blueprint_components.QueryKindBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.QueryKindBatch._optional, # type: ignore[misc] + ) + # Kind of query: latest-at or range. + # + # (Docstring intentionally commented out to hide this field from the docs) + + latest_at_queries: blueprint_components.LatestAtQueriesBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.LatestAtQueriesBatch._optional, # type: ignore[misc] + ) + # Configuration for latest-at queries. + # + # Note: configuration as saved on a per-timeline basis. + # + # (Docstring intentionally commented out to hide this field from the docs) + + time_range_queries: blueprint_components.TimeRangeQueriesBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.TimeRangeQueriesBatch._optional, # type: ignore[misc] + ) + # Configuration for the time range queries. + # + # Note: configuration as saved on a per-timeline basis. + # + # (Docstring intentionally commented out to hide this field from the docs) + + __str__ = Archetype.__str__ + __repr__ = Archetype.__repr__ # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py deleted file mode 100644 index 475ac728ab00..000000000000 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/dataframe_view_mode.py +++ /dev/null @@ -1,65 +0,0 @@ -# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs -# Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/dataframe_view_mode.fbs". - -# You can extend this class by creating a "DataframeViewModeExt" class in "dataframe_view_mode_ext.py". - -from __future__ import annotations - -from typing import Any - -from attrs import define, field - -from ..._baseclasses import ( - Archetype, -) -from ...blueprint import components as blueprint_components -from ...error_utils import catch_and_log_exceptions - -__all__ = ["DataframeViewMode"] - - -@define(str=False, repr=False, init=False) -class DataframeViewMode(Archetype): - """**Archetype**: Configuration for the dataframe view.""" - - def __init__(self: Any, *, mode: blueprint_components.DataframeViewModeLike | None = None): - """ - Create a new instance of the DataframeViewMode archetype. - - Parameters - ---------- - mode: - The kind of table to display - - """ - - # You can define your own __init__ function as a member of DataframeViewModeExt in dataframe_view_mode_ext.py - with catch_and_log_exceptions(context=self.__class__.__name__): - self.__attrs_init__(mode=mode) - return - self.__attrs_clear__() - - def __attrs_clear__(self) -> None: - """Convenience method for calling `__attrs_init__` with all `None`s.""" - self.__attrs_init__( - mode=None, # type: ignore[arg-type] - ) - - @classmethod - def _clear(cls) -> DataframeViewMode: - """Produce an empty DataframeViewMode, bypassing `__init__`.""" - inst = cls.__new__(cls) - inst.__attrs_clear__() - return inst - - mode: blueprint_components.DataframeViewModeBatch | None = field( - metadata={"component": "optional"}, - default=None, - converter=blueprint_components.DataframeViewModeBatch._optional, # type: ignore[misc] - ) - # The kind of table to display - # - # (Docstring intentionally commented out to hide this field from the docs) - - __str__ = Archetype.__str__ - __repr__ = Archetype.__repr__ # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index cbbd0123a5e2..201c9647727e 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -9,14 +9,15 @@ background_kind.py linguist-generated=true column_share.py linguist-generated=true container_kind.py linguist-generated=true corner2d.py linguist-generated=true -dataframe_view_mode.py linguist-generated=true grid_columns.py linguist-generated=true included_content.py linguist-generated=true included_space_view.py linguist-generated=true interactive.py linguist-generated=true +latest_at_queries.py linguist-generated=true lock_range_during_zoom.py linguist-generated=true panel_state.py linguist-generated=true query_expression.py linguist-generated=true +query_kind.py linguist-generated=true root_container.py linguist-generated=true row_share.py linguist-generated=true sort_key.py linguist-generated=true @@ -25,6 +26,8 @@ space_view_class.py linguist-generated=true space_view_maximized.py linguist-generated=true space_view_origin.py linguist-generated=true tensor_dimension_index_slider.py linguist-generated=true +time_range_queries.py linguist-generated=true +timeline_name.py linguist-generated=true view_fit.py linguist-generated=true viewer_recommendation_hash.py linguist-generated=true visible.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 7e966a7394ec..672894030dcb 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -21,20 +21,21 @@ ContainerKindType, ) from .corner2d import Corner2D, Corner2DArrayLike, Corner2DBatch, Corner2DLike, Corner2DType -from .dataframe_view_mode import ( - DataframeViewMode, - DataframeViewModeArrayLike, - DataframeViewModeBatch, - DataframeViewModeLike, - DataframeViewModeType, -) from .grid_columns import GridColumns, GridColumnsBatch, GridColumnsType from .included_content import IncludedContent, IncludedContentBatch, IncludedContentType from .included_space_view import IncludedSpaceView, IncludedSpaceViewBatch, IncludedSpaceViewType from .interactive import Interactive, InteractiveBatch, InteractiveType +from .latest_at_queries import ( + LatestAtQueries, + LatestAtQueriesArrayLike, + LatestAtQueriesBatch, + LatestAtQueriesLike, + LatestAtQueriesType, +) from .lock_range_during_zoom import LockRangeDuringZoom, LockRangeDuringZoomBatch, LockRangeDuringZoomType from .panel_state import PanelState, PanelStateArrayLike, PanelStateBatch, PanelStateLike, PanelStateType from .query_expression import QueryExpression, QueryExpressionBatch, QueryExpressionType +from .query_kind import QueryKind, QueryKindArrayLike, QueryKindBatch, QueryKindLike, QueryKindType from .root_container import RootContainer, RootContainerBatch, RootContainerType from .row_share import RowShare, RowShareBatch, RowShareType from .sort_key import SortKey, SortKeyArrayLike, SortKeyBatch, SortKeyLike, SortKeyType @@ -47,6 +48,14 @@ TensorDimensionIndexSliderBatch, TensorDimensionIndexSliderType, ) +from .time_range_queries import ( + TimeRangeQueries, + TimeRangeQueriesArrayLike, + TimeRangeQueriesBatch, + TimeRangeQueriesLike, + TimeRangeQueriesType, +) +from .timeline_name import TimelineName, TimelineNameBatch, TimelineNameType from .view_fit import ViewFit, ViewFitArrayLike, ViewFitBatch, ViewFitLike, ViewFitType from .viewer_recommendation_hash import ( ViewerRecommendationHash, @@ -86,11 +95,6 @@ "Corner2DBatch", "Corner2DLike", "Corner2DType", - "DataframeViewMode", - "DataframeViewModeArrayLike", - "DataframeViewModeBatch", - "DataframeViewModeLike", - "DataframeViewModeType", "GridColumns", "GridColumnsBatch", "GridColumnsType", @@ -103,6 +107,11 @@ "Interactive", "InteractiveBatch", "InteractiveType", + "LatestAtQueries", + "LatestAtQueriesArrayLike", + "LatestAtQueriesBatch", + "LatestAtQueriesLike", + "LatestAtQueriesType", "LockRangeDuringZoom", "LockRangeDuringZoomBatch", "LockRangeDuringZoomType", @@ -114,6 +123,11 @@ "QueryExpression", "QueryExpressionBatch", "QueryExpressionType", + "QueryKind", + "QueryKindArrayLike", + "QueryKindBatch", + "QueryKindLike", + "QueryKindType", "RootContainer", "RootContainerBatch", "RootContainerType", @@ -142,6 +156,14 @@ "TensorDimensionIndexSlider", "TensorDimensionIndexSliderBatch", "TensorDimensionIndexSliderType", + "TimeRangeQueries", + "TimeRangeQueriesArrayLike", + "TimeRangeQueriesBatch", + "TimeRangeQueriesLike", + "TimeRangeQueriesType", + "TimelineName", + "TimelineNameBatch", + "TimelineNameType", "ViewFit", "ViewFitArrayLike", "ViewFitBatch", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py b/rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py deleted file mode 100644 index 9ce262636db5..000000000000 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/dataframe_view_mode.py +++ /dev/null @@ -1,90 +0,0 @@ -# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs -# Based on "crates/store/re_types/definitions/rerun/blueprint/components/dataframe_view_mode.fbs". - -# You can extend this class by creating a "DataframeViewModeExt" class in "dataframe_view_mode_ext.py". - -from __future__ import annotations - -from typing import Literal, Sequence, Union - -import pyarrow as pa - -from ..._baseclasses import ( - BaseBatch, - BaseExtensionType, - ComponentBatchMixin, -) - -__all__ = [ - "DataframeViewMode", - "DataframeViewModeArrayLike", - "DataframeViewModeBatch", - "DataframeViewModeLike", - "DataframeViewModeType", -] - - -from enum import Enum - - -class DataframeViewMode(Enum): - """**Component**: The kind of table displayed by the dataframe view.""" - - LatestAt = 1 - """ - Display the entity values at the current time. - - In this mode, rows are entity instances, and columns are components. The visible time range setting is ignored. - """ - - TimeRange = 2 - """ - Display a temporal table of entity values. - - In this mode, rows are combination of entity path, timestamp, and row id, and columns are components. The - timestamp shown are determined by each view entity's visible time range setting. - """ - - @classmethod - def auto(cls, val: str | int | DataframeViewMode) -> DataframeViewMode: - """Best-effort converter, including a case-insensitive string matcher.""" - if isinstance(val, DataframeViewMode): - return val - if isinstance(val, int): - return cls(val) - try: - return cls[val] - except KeyError: - val_lower = val.lower() - for variant in cls: - if variant.name.lower() == val_lower: - return variant - raise ValueError(f"Cannot convert {val} to {cls.__name__}") - - def __str__(self) -> str: - """Returns the variant name.""" - return self.name - - -DataframeViewModeLike = Union[DataframeViewMode, Literal["LatestAt", "TimeRange", "latestat", "timerange"], int] -DataframeViewModeArrayLike = Union[DataframeViewModeLike, Sequence[DataframeViewModeLike]] - - -class DataframeViewModeType(BaseExtensionType): - _TYPE_NAME: str = "rerun.blueprint.components.DataframeViewMode" - - def __init__(self) -> None: - pa.ExtensionType.__init__(self, pa.uint8(), self._TYPE_NAME) - - -class DataframeViewModeBatch(BaseBatch[DataframeViewModeArrayLike], ComponentBatchMixin): - _ARROW_TYPE = DataframeViewModeType() - - @staticmethod - def _native_to_pa_array(data: DataframeViewModeArrayLike, data_type: pa.DataType) -> pa.Array: - if isinstance(data, (DataframeViewMode, int, str)): - data = [data] - - pa_data = [DataframeViewMode.auto(v).value if v is not None else None for v in data] # type: ignore[redundant-expr] - - return pa.array(pa_data, type=data_type) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py b/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py new file mode 100644 index 000000000000..f4882af5f88d --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/latest_at_queries.py @@ -0,0 +1,88 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/latest_at_queries.fbs". + +# You can extend this class by creating a "LatestAtQueriesExt" class in "latest_at_queries_ext.py". + +from __future__ import annotations + +from typing import Any, Sequence, Union + +import pyarrow as pa +from attrs import define, field + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, + ComponentMixin, +) +from ...blueprint import datatypes as blueprint_datatypes + +__all__ = [ + "LatestAtQueries", + "LatestAtQueriesArrayLike", + "LatestAtQueriesBatch", + "LatestAtQueriesLike", + "LatestAtQueriesType", +] + + +@define(init=False) +class LatestAtQueries(ComponentMixin): + """ + **Component**: Configuration for latest at queries. + + Note: configuration as saved on a per-timeline basis. + """ + + _BATCH_TYPE = None + + def __init__(self: Any, queries: LatestAtQueriesLike): + """Create a new instance of the LatestAtQueries component.""" + + # You can define your own __init__ function as a member of LatestAtQueriesExt in latest_at_queries_ext.py + self.__attrs_init__(queries=queries) + + queries: list[blueprint_datatypes.LatestAtQuery] = field() + + +LatestAtQueriesLike = LatestAtQueries +LatestAtQueriesArrayLike = Union[ + LatestAtQueries, + Sequence[LatestAtQueriesLike], +] + + +class LatestAtQueriesType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.LatestAtQueries" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.list_( + pa.field( + "item", + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("time", pa.int64(), nullable=False, metadata={}), + ]), + nullable=False, + metadata={}, + ) + ), + self._TYPE_NAME, + ) + + +class LatestAtQueriesBatch(BaseBatch[LatestAtQueriesArrayLike], ComponentBatchMixin): + _ARROW_TYPE = LatestAtQueriesType() + + @staticmethod + def _native_to_pa_array(data: LatestAtQueriesArrayLike, data_type: pa.DataType) -> pa.Array: + raise NotImplementedError( + "Arrow serialization of LatestAtQueries not implemented: We lack codegen for arrow-serialization of general structs" + ) # You need to implement native_to_pa_array_override in latest_at_queries_ext.py + + +# This is patched in late to avoid circular dependencies. +LatestAtQueries._BATCH_TYPE = LatestAtQueriesBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py b/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py new file mode 100644 index 000000000000..cd8e452fb9e2 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/query_kind.py @@ -0,0 +1,75 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/query_kind.fbs". + +# You can extend this class by creating a "QueryKindExt" class in "query_kind_ext.py". + +from __future__ import annotations + +from typing import Literal, Sequence, Union + +import pyarrow as pa + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, +) + +__all__ = ["QueryKind", "QueryKindArrayLike", "QueryKindBatch", "QueryKindLike", "QueryKindType"] + + +from enum import Enum + + +class QueryKind(Enum): + """**Component**: The kind of query displayed by the dataframe view.""" + + LatestAt = 1 + """Query""" + + TimeRange = 2 + """Time range query.""" + + @classmethod + def auto(cls, val: str | int | QueryKind) -> QueryKind: + """Best-effort converter, including a case-insensitive string matcher.""" + if isinstance(val, QueryKind): + return val + if isinstance(val, int): + return cls(val) + try: + return cls[val] + except KeyError: + val_lower = val.lower() + for variant in cls: + if variant.name.lower() == val_lower: + return variant + raise ValueError(f"Cannot convert {val} to {cls.__name__}") + + def __str__(self) -> str: + """Returns the variant name.""" + return self.name + + +QueryKindLike = Union[QueryKind, Literal["LatestAt", "TimeRange", "latestat", "timerange"], int] +QueryKindArrayLike = Union[QueryKindLike, Sequence[QueryKindLike]] + + +class QueryKindType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.QueryKind" + + def __init__(self) -> None: + pa.ExtensionType.__init__(self, pa.uint8(), self._TYPE_NAME) + + +class QueryKindBatch(BaseBatch[QueryKindArrayLike], ComponentBatchMixin): + _ARROW_TYPE = QueryKindType() + + @staticmethod + def _native_to_pa_array(data: QueryKindArrayLike, data_type: pa.DataType) -> pa.Array: + if isinstance(data, (QueryKind, int, str)): + data = [data] + + pa_data = [QueryKind.auto(v).value if v is not None else None for v in data] # type: ignore[redundant-expr] + + return pa.array(pa_data, type=data_type) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py b/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py new file mode 100644 index 000000000000..bb884758bc8b --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/time_range_queries.py @@ -0,0 +1,89 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/time_range_queries.fbs". + +# You can extend this class by creating a "TimeRangeQueriesExt" class in "time_range_queries_ext.py". + +from __future__ import annotations + +from typing import Any, Sequence, Union + +import pyarrow as pa +from attrs import define, field + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, + ComponentMixin, +) +from ...blueprint import datatypes as blueprint_datatypes + +__all__ = [ + "TimeRangeQueries", + "TimeRangeQueriesArrayLike", + "TimeRangeQueriesBatch", + "TimeRangeQueriesLike", + "TimeRangeQueriesType", +] + + +@define(init=False) +class TimeRangeQueries(ComponentMixin): + """ + **Component**: Configuration for time range queries. + + Note: configuration as saved on a per-timeline basis. + """ + + _BATCH_TYPE = None + + def __init__(self: Any, queries: TimeRangeQueriesLike): + """Create a new instance of the TimeRangeQueries component.""" + + # You can define your own __init__ function as a member of TimeRangeQueriesExt in time_range_queries_ext.py + self.__attrs_init__(queries=queries) + + queries: list[blueprint_datatypes.TimeRangeQuery] = field() + + +TimeRangeQueriesLike = TimeRangeQueries +TimeRangeQueriesArrayLike = Union[ + TimeRangeQueries, + Sequence[TimeRangeQueriesLike], +] + + +class TimeRangeQueriesType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.TimeRangeQueries" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.list_( + pa.field( + "item", + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("start", pa.int64(), nullable=False, metadata={}), + pa.field("end", pa.int64(), nullable=False, metadata={}), + ]), + nullable=False, + metadata={}, + ) + ), + self._TYPE_NAME, + ) + + +class TimeRangeQueriesBatch(BaseBatch[TimeRangeQueriesArrayLike], ComponentBatchMixin): + _ARROW_TYPE = TimeRangeQueriesType() + + @staticmethod + def _native_to_pa_array(data: TimeRangeQueriesArrayLike, data_type: pa.DataType) -> pa.Array: + raise NotImplementedError( + "Arrow serialization of TimeRangeQueries not implemented: We lack codegen for arrow-serialization of general structs" + ) # You need to implement native_to_pa_array_override in time_range_queries_ext.py + + +# This is patched in late to avoid circular dependencies. +TimeRangeQueries._BATCH_TYPE = TimeRangeQueriesBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py new file mode 100644 index 000000000000..99c49ffee02e --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/timeline_name.py @@ -0,0 +1,36 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/timeline_name.fbs". + +# You can extend this class by creating a "TimelineNameExt" class in "timeline_name_ext.py". + +from __future__ import annotations + +from ... import datatypes +from ..._baseclasses import ( + ComponentBatchMixin, + ComponentMixin, +) + +__all__ = ["TimelineName", "TimelineNameBatch", "TimelineNameType"] + + +class TimelineName(datatypes.Utf8, ComponentMixin): + """**Component**: A timeline identified by its name.""" + + _BATCH_TYPE = None + # You can define your own __init__ function as a member of TimelineNameExt in timeline_name_ext.py + + # Note: there are no fields here because TimelineName delegates to datatypes.Utf8 + pass + + +class TimelineNameType(datatypes.Utf8Type): + _TYPE_NAME: str = "rerun.blueprint.components.TimelineName" + + +class TimelineNameBatch(datatypes.Utf8Batch, ComponentBatchMixin): + _ARROW_TYPE = TimelineNameType() + + +# This is patched in late to avoid circular dependencies. +TimelineName._BATCH_TYPE = TimelineNameBatch # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes index 8ae92d95c142..71e16d43761e 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes @@ -2,5 +2,7 @@ .gitattributes linguist-generated=true __init__.py linguist-generated=true +latest_at_query.py linguist-generated=true tensor_dimension_index_slider.py linguist-generated=true +time_range_query.py linguist-generated=true utf8list.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py index 929fa1b8089b..709ee623a9e0 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py @@ -2,6 +2,13 @@ from __future__ import annotations +from .latest_at_query import ( + LatestAtQuery, + LatestAtQueryArrayLike, + LatestAtQueryBatch, + LatestAtQueryLike, + LatestAtQueryType, +) from .tensor_dimension_index_slider import ( TensorDimensionIndexSlider, TensorDimensionIndexSliderArrayLike, @@ -9,14 +16,31 @@ TensorDimensionIndexSliderLike, TensorDimensionIndexSliderType, ) +from .time_range_query import ( + TimeRangeQuery, + TimeRangeQueryArrayLike, + TimeRangeQueryBatch, + TimeRangeQueryLike, + TimeRangeQueryType, +) from .utf8list import Utf8List, Utf8ListArrayLike, Utf8ListBatch, Utf8ListLike, Utf8ListType __all__ = [ + "LatestAtQuery", + "LatestAtQueryArrayLike", + "LatestAtQueryBatch", + "LatestAtQueryLike", + "LatestAtQueryType", "TensorDimensionIndexSlider", "TensorDimensionIndexSliderArrayLike", "TensorDimensionIndexSliderBatch", "TensorDimensionIndexSliderLike", "TensorDimensionIndexSliderType", + "TimeRangeQuery", + "TimeRangeQueryArrayLike", + "TimeRangeQueryBatch", + "TimeRangeQueryLike", + "TimeRangeQueryType", "Utf8List", "Utf8ListArrayLike", "Utf8ListBatch", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py new file mode 100644 index 000000000000..58d7aa2a80a7 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query.py @@ -0,0 +1,100 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/latest_at_query.fbs". + +# You can extend this class by creating a "LatestAtQueryExt" class in "latest_at_query_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, +) +from .latest_at_query_ext import LatestAtQueryExt + +__all__ = ["LatestAtQuery", "LatestAtQueryArrayLike", "LatestAtQueryBatch", "LatestAtQueryLike", "LatestAtQueryType"] + + +def _latest_at_query__timeline__special_field_converter_override(x: datatypes.Utf8Like) -> datatypes.Utf8: + if isinstance(x, datatypes.Utf8): + return x + else: + return datatypes.Utf8(x) + + +@define(init=False) +class LatestAtQuery(LatestAtQueryExt): + """**Datatype**: Latest at query configuration for a specific timeline.""" + + def __init__(self: Any, timeline: datatypes.Utf8Like, time: datatypes.TimeIntLike): + """ + Create a new instance of the LatestAtQuery datatype. + + Parameters + ---------- + timeline: + Name of the timeline this applies to. + time: + Time value to use for this query. + + """ + + # You can define your own __init__ function as a member of LatestAtQueryExt in latest_at_query_ext.py + self.__attrs_init__(timeline=timeline, time=time) + + timeline: datatypes.Utf8 = field(converter=_latest_at_query__timeline__special_field_converter_override) + # Name of the timeline this applies to. + # + # (Docstring intentionally commented out to hide this field from the docs) + + time: datatypes.TimeInt = field( + converter=LatestAtQueryExt.time__field_converter_override, # type: ignore[misc] + ) + # Time value to use for this query. + # + # (Docstring intentionally commented out to hide this field from the docs) + + +LatestAtQueryLike = LatestAtQuery +LatestAtQueryArrayLike = Union[ + LatestAtQuery, + Sequence[LatestAtQueryLike], +] + + +class LatestAtQueryType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.datatypes.LatestAtQuery" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("time", pa.int64(), nullable=False, metadata={}), + ]), + self._TYPE_NAME, + ) + + +class LatestAtQueryBatch(BaseBatch[LatestAtQueryArrayLike]): + _ARROW_TYPE = LatestAtQueryType() + + @staticmethod + def _native_to_pa_array(data: LatestAtQueryArrayLike, data_type: pa.DataType) -> pa.Array: + from rerun.datatypes import TimeIntBatch, Utf8Batch + + if isinstance(data, LatestAtQuery): + data = [data] + + return pa.StructArray.from_arrays( + [ + Utf8Batch([x.timeline for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + TimeIntBatch([x.time for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + ], + fields=list(data_type), + ) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py new file mode 100644 index 000000000000..92805bd119e8 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/latest_at_query_ext.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from ... import datatypes + + +class LatestAtQueryExt: + """Extension for [LatestAtQuery][rerun.blueprint.datatypes.LatestAtQuery].""" + + # This override is required because otherwise the codegen uses `TimeInt(x)`, which is not valid with the custom + # `TimeInt.__init__` override. + + @staticmethod + def time__field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(seq=x) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py new file mode 100644 index 000000000000..f8ab08cfee48 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query.py @@ -0,0 +1,117 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/datatypes/time_range_query.fbs". + +# You can extend this class by creating a "TimeRangeQueryExt" class in "time_range_query_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, +) +from .time_range_query_ext import TimeRangeQueryExt + +__all__ = [ + "TimeRangeQuery", + "TimeRangeQueryArrayLike", + "TimeRangeQueryBatch", + "TimeRangeQueryLike", + "TimeRangeQueryType", +] + + +def _time_range_query__timeline__special_field_converter_override(x: datatypes.Utf8Like) -> datatypes.Utf8: + if isinstance(x, datatypes.Utf8): + return x + else: + return datatypes.Utf8(x) + + +@define(init=False) +class TimeRangeQuery(TimeRangeQueryExt): + """**Datatype**: Time range query configuration for a specific timeline.""" + + def __init__(self: Any, timeline: datatypes.Utf8Like, start: datatypes.TimeIntLike, end: datatypes.TimeIntLike): + """ + Create a new instance of the TimeRangeQuery datatype. + + Parameters + ---------- + timeline: + Name of the timeline this applies to. + start: + Beginning of the time range. + end: + End of the time range (inclusive). + + """ + + # You can define your own __init__ function as a member of TimeRangeQueryExt in time_range_query_ext.py + self.__attrs_init__(timeline=timeline, start=start, end=end) + + timeline: datatypes.Utf8 = field(converter=_time_range_query__timeline__special_field_converter_override) + # Name of the timeline this applies to. + # + # (Docstring intentionally commented out to hide this field from the docs) + + start: datatypes.TimeInt = field( + converter=TimeRangeQueryExt.start__field_converter_override, # type: ignore[misc] + ) + # Beginning of the time range. + # + # (Docstring intentionally commented out to hide this field from the docs) + + end: datatypes.TimeInt = field( + converter=TimeRangeQueryExt.end__field_converter_override, # type: ignore[misc] + ) + # End of the time range (inclusive). + # + # (Docstring intentionally commented out to hide this field from the docs) + + +TimeRangeQueryLike = TimeRangeQuery +TimeRangeQueryArrayLike = Union[ + TimeRangeQuery, + Sequence[TimeRangeQueryLike], +] + + +class TimeRangeQueryType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.datatypes.TimeRangeQuery" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.struct([ + pa.field("timeline", pa.utf8(), nullable=False, metadata={}), + pa.field("start", pa.int64(), nullable=False, metadata={}), + pa.field("end", pa.int64(), nullable=False, metadata={}), + ]), + self._TYPE_NAME, + ) + + +class TimeRangeQueryBatch(BaseBatch[TimeRangeQueryArrayLike]): + _ARROW_TYPE = TimeRangeQueryType() + + @staticmethod + def _native_to_pa_array(data: TimeRangeQueryArrayLike, data_type: pa.DataType) -> pa.Array: + from rerun.datatypes import TimeIntBatch, Utf8Batch + + if isinstance(data, TimeRangeQuery): + data = [data] + + return pa.StructArray.from_arrays( + [ + Utf8Batch([x.timeline for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + TimeIntBatch([x.start for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + TimeIntBatch([x.end for x in data]).as_arrow_array().storage, # type: ignore[misc, arg-type] + ], + fields=list(data_type), + ) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py new file mode 100644 index 000000000000..6ddc984eb361 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/time_range_query_ext.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from ... import datatypes + + +class TimeRangeQueryExt: + """Extension for [TimeRangeQuery][rerun.blueprint.datatypes.TimeRangeQuery].""" + + # These overrides are required because otherwise the codegen uses `TimeInt(x)`, which is not valid with the custom + # `TimeInt.__init__` override. + + @staticmethod + def start__field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(seq=x) + + @staticmethod + def end__field_converter_override(x: datatypes.TimeIntLike) -> datatypes.TimeInt: + if isinstance(x, datatypes.TimeInt): + return x + else: + return datatypes.TimeInt(seq=x)