diff --git a/Cargo.lock b/Cargo.lock index 4409be78b369..6c1a3427802c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5365,8 +5365,11 @@ dependencies = [ "egui", "egui_extras", "egui_plot", + "re_data_source", "re_data_ui", "re_format", + "re_log", + "re_log_types", "re_tracing", "re_types", "re_types_blueprint", diff --git a/crates/store/re_types/definitions/rerun/components.fbs b/crates/store/re_types/definitions/rerun/components.fbs index b1a32fd2133f..daecdcc9e81a 100644 --- a/crates/store/re_types/definitions/rerun/components.fbs +++ b/crates/store/re_types/definitions/rerun/components.fbs @@ -38,6 +38,7 @@ include "./components/position2d.fbs"; include "./components/position3d.fbs"; include "./components/radius.fbs"; include "./components/range1d.fbs"; +include "./components/recording_uri.fbs"; include "./components/resolution.fbs"; include "./components/rotation_axis_angle.fbs"; include "./components/rotation_quat.fbs"; diff --git a/crates/store/re_types/definitions/rerun/components/recording_uri.fbs b/crates/store/re_types/definitions/rerun/components/recording_uri.fbs new file mode 100644 index 000000000000..22966e126eb4 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/components/recording_uri.fbs @@ -0,0 +1,10 @@ +namespace rerun.components; + +// --- + +/// A recording URI (Uniform Resource Identifier). +table RecordingUri ( + "attr.rust.derive": "PartialEq, Eq, PartialOrd, Ord, Hash" +) { + recording_uri: rerun.datatypes.Utf8 (order: 100); +} diff --git a/crates/store/re_types/src/components/.gitattributes b/crates/store/re_types/src/components/.gitattributes index def154d84908..8ad3aa2b072b 100644 --- a/crates/store/re_types/src/components/.gitattributes +++ b/crates/store/re_types/src/components/.gitattributes @@ -44,6 +44,7 @@ position2d.rs linguist-generated=true position3d.rs linguist-generated=true radius.rs linguist-generated=true range1d.rs linguist-generated=true +recording_uri.rs linguist-generated=true resolution.rs linguist-generated=true rotation_axis_angle.rs linguist-generated=true rotation_quat.rs linguist-generated=true diff --git a/crates/store/re_types/src/components/mod.rs b/crates/store/re_types/src/components/mod.rs index ee02251c6341..4b4af4ce9ca2 100644 --- a/crates/store/re_types/src/components/mod.rs +++ b/crates/store/re_types/src/components/mod.rs @@ -76,6 +76,8 @@ mod radius; mod radius_ext; mod range1d; mod range1d_ext; +mod recording_uri; +mod recording_uri_ext; mod resolution; mod resolution_ext; mod rotation_axis_angle; @@ -161,6 +163,7 @@ pub use self::position2d::Position2D; pub use self::position3d::Position3D; pub use self::radius::Radius; pub use self::range1d::Range1D; +pub use self::recording_uri::RecordingUri; pub use self::resolution::Resolution; pub use self::rotation_axis_angle::RotationAxisAngle; pub use self::rotation_quat::RotationQuat; diff --git a/crates/store/re_types/src/components/recording_uri.rs b/crates/store/re_types/src/components/recording_uri.rs new file mode 100644 index 000000000000..9ed42cec7da1 --- /dev/null +++ b/crates/store/re_types/src/components/recording_uri.rs @@ -0,0 +1,104 @@ +// 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/components/recording_uri.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 recording URI (Uniform Resource Identifier). +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct RecordingUri(pub crate::datatypes::Utf8); + +impl ::re_types_core::SizeBytes for RecordingUri { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +impl> From for RecordingUri { + fn from(v: T) -> Self { + Self(v.into()) + } +} + +impl std::borrow::Borrow for RecordingUri { + #[inline] + fn borrow(&self) -> &crate::datatypes::Utf8 { + &self.0 + } +} + +impl std::ops::Deref for RecordingUri { + type Target = crate::datatypes::Utf8; + + #[inline] + fn deref(&self) -> &crate::datatypes::Utf8 { + &self.0 + } +} + +impl std::ops::DerefMut for RecordingUri { + #[inline] + fn deref_mut(&mut self) -> &mut crate::datatypes::Utf8 { + &mut self.0 + } +} + +::re_types_core::macros::impl_into_cow!(RecordingUri); + +impl ::re_types_core::Loggable for RecordingUri { + #[inline] + fn arrow2_datatype() -> arrow2::datatypes::DataType { + crate::datatypes::Utf8::arrow2_datatype() + } + + fn to_arrow2_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + crate::datatypes::Utf8::to_arrow2_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_arrow2_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + crate::datatypes::Utf8::from_arrow2_opt(arrow_data) + .map(|v| v.into_iter().map(|v| v.map(Self)).collect()) + } +} + +impl ::re_types_core::Component for RecordingUri { + #[inline] + fn name() -> ComponentName { + "rerun.components.RecordingUri".into() + } +} diff --git a/crates/store/re_types/src/components/recording_uri_ext.rs b/crates/store/re_types/src/components/recording_uri_ext.rs new file mode 100644 index 000000000000..b3b65916a310 --- /dev/null +++ b/crates/store/re_types/src/components/recording_uri_ext.rs @@ -0,0 +1,8 @@ +use super::RecordingUri; + +impl RecordingUri { + /// Return the Recording URI contained in this component. + pub fn uri(&self) -> &str { + self.0.as_str() + } +} diff --git a/crates/viewer/re_component_ui/Cargo.toml b/crates/viewer/re_component_ui/Cargo.toml index 51f7ea4d25c9..c6a0f3329325 100644 --- a/crates/viewer/re_component_ui/Cargo.toml +++ b/crates/viewer/re_component_ui/Cargo.toml @@ -20,7 +20,10 @@ all-features = true [dependencies] re_data_ui.workspace = true # Needed for `item_ui`. +re_data_source.workspace = true re_format.workspace = true +re_log.workspace = true +re_log_types.workspace = true re_tracing.workspace = true re_types = { workspace = true, features = [ "egui_plot", # Needed to draw marker shapes. diff --git a/crates/viewer/re_component_ui/src/lib.rs b/crates/viewer/re_component_ui/src/lib.rs index 7d8d0577ccde..bab71d7656b8 100644 --- a/crates/viewer/re_component_ui/src/lib.rs +++ b/crates/viewer/re_component_ui/src/lib.rs @@ -15,6 +15,7 @@ mod map_provider; mod marker_shape; mod pinhole; mod radius; +mod recording_uri; mod resolution; mod response_utils; mod timeline; @@ -157,6 +158,8 @@ pub fn create_component_ui_registry() -> re_viewer_context::ComponentUiRegistry registry.add_singleline_edit_or_view(pinhole::singleline_view_pinhole); registry.add_multiline_edit_or_view(pinhole::multiline_view_pinhole); + registry.add_singleline_edit_or_view(recording_uri::singleline_view_recording_uri); + line_strip::register_linestrip_component_ui(&mut registry); geo_line_string::register_geo_line_string_component_ui(&mut registry); diff --git a/crates/viewer/re_component_ui/src/recording_uri.rs b/crates/viewer/re_component_ui/src/recording_uri.rs new file mode 100644 index 000000000000..99b8cb504a54 --- /dev/null +++ b/crates/viewer/re_component_ui/src/recording_uri.rs @@ -0,0 +1,40 @@ +use re_types::components::RecordingUri; +use re_viewer_context::{MaybeMutRef, SystemCommand, SystemCommandSender, ViewerContext}; + +pub fn singleline_view_recording_uri( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + value: &mut MaybeMutRef<'_, RecordingUri>, +) -> egui::Response { + let value = value.as_ref(); + + let response = ui + .scope(|ui| { + if ui.style().wrap_mode.is_none() { + ui.style_mut().wrap_mode = Some(if ui.is_sizing_pass() { + egui::TextWrapMode::Extend + } else { + egui::TextWrapMode::Truncate + }); + } + + ui.link(value.uri()) + }) + .inner; + + if response.clicked() { + let data_source = re_data_source::DataSource::from_uri( + re_log_types::FileSource::Cli, + value.uri().to_owned(), + ); + + match data_source.stream(None) { + Ok(rx) => ctx + .command_sender + .send_system(SystemCommand::AddReceiver(rx)), + Err(err) => re_log::warn!("Could not open recording URI: {err}"), + } + } + + response +} diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 0eea1468ccb8..72491c368420 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -656,6 +656,14 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "A recording URI (Uniform Resource Identifier).", + custom_placeholder: None, + datatype: RecordingUri::arrow2_datatype(), + }, + ), ( ::name(), ComponentReflection { diff --git a/docs/content/reference/types/components.md b/docs/content/reference/types/components.md index 9e0e3f07f681..81c087fc2562 100644 --- a/docs/content/reference/types/components.md +++ b/docs/content/reference/types/components.md @@ -56,6 +56,7 @@ on [Entities and Components](../../concepts/entity-component.md). * [`Position3D`](components/position3d.md): A position in 3D space. * [`Radius`](components/radius.md): The radius of something, e.g. a point. * [`Range1D`](components/range1d.md): A 1D range, specifying a lower and upper bound. +* [`RecordingUri`](components/recording_uri.md): A recording URI (Uniform Resource Identifier). * [`Resolution`](components/resolution.md): Pixel resolution width & height, e.g. of a camera sensor. * [`RotationAxisAngle`](components/rotation_axis_angle.md): 3D rotation represented by a rotation around a given axis. * [`RotationQuat`](components/rotation_quat.md): A 3D rotation expressed as a quaternion. diff --git a/docs/content/reference/types/components/.gitattributes b/docs/content/reference/types/components/.gitattributes index d2b7740214d4..88bf1c1c8594 100644 --- a/docs/content/reference/types/components/.gitattributes +++ b/docs/content/reference/types/components/.gitattributes @@ -44,6 +44,7 @@ position2d.md linguist-generated=true position3d.md linguist-generated=true radius.md linguist-generated=true range1d.md linguist-generated=true +recording_uri.md linguist-generated=true resolution.md linguist-generated=true rotation_axis_angle.md linguist-generated=true rotation_quat.md linguist-generated=true diff --git a/docs/content/reference/types/components/recording_uri.md b/docs/content/reference/types/components/recording_uri.md new file mode 100644 index 000000000000..a5d20e95f0ce --- /dev/null +++ b/docs/content/reference/types/components/recording_uri.md @@ -0,0 +1,22 @@ +--- +title: "RecordingUri" +--- + + +A recording URI (Uniform Resource Identifier). + +## Rerun datatype +[`Utf8`](../datatypes/utf8.md) + + +## Arrow datatype +``` +utf8 +``` + +## API reference links + * 🌊 [C++ API docs for `RecordingUri`](https://ref.rerun.io/docs/cpp/stable/structrerun_1_1components_1_1RecordingUri.html) + * 🐍 [Python API docs for `RecordingUri`](https://ref.rerun.io/docs/python/stable/common/components#rerun.components.RecordingUri) + * 🦀 [Rust API docs for `RecordingUri`](https://docs.rs/rerun/latest/rerun/components/struct.RecordingUri.html) + + diff --git a/docs/content/reference/types/datatypes/utf8.md b/docs/content/reference/types/datatypes/utf8.md index 7da350ef1499..7b8c8130da3c 100644 --- a/docs/content/reference/types/datatypes/utf8.md +++ b/docs/content/reference/types/datatypes/utf8.md @@ -22,6 +22,7 @@ utf8 * [`AnnotationInfo`](../datatypes/annotation_info.md) * [`MediaType`](../components/media_type.md) * [`Name`](../components/name.md) +* [`RecordingUri`](../components/recording_uri.md) * [`TextLogLevel`](../components/text_log_level.md) * [`Text`](../components/text.md) * [`VisibleTimeRange`](../datatypes/visible_time_range.md) diff --git a/rerun_cpp/src/rerun/components.hpp b/rerun_cpp/src/rerun/components.hpp index 8806bc1c90f5..1cf9b6d240ef 100644 --- a/rerun_cpp/src/rerun/components.hpp +++ b/rerun_cpp/src/rerun/components.hpp @@ -45,6 +45,7 @@ #include "components/position3d.hpp" #include "components/radius.hpp" #include "components/range1d.hpp" +#include "components/recording_uri.hpp" #include "components/resolution.hpp" #include "components/rotation_axis_angle.hpp" #include "components/rotation_quat.hpp" diff --git a/rerun_cpp/src/rerun/components/.gitattributes b/rerun_cpp/src/rerun/components/.gitattributes index 7fb37fd6dd9b..ccc5761565fa 100644 --- a/rerun_cpp/src/rerun/components/.gitattributes +++ b/rerun_cpp/src/rerun/components/.gitattributes @@ -53,6 +53,7 @@ position2d.hpp linguist-generated=true position3d.hpp linguist-generated=true radius.hpp linguist-generated=true range1d.hpp linguist-generated=true +recording_uri.hpp linguist-generated=true resolution.hpp linguist-generated=true rotation_axis_angle.hpp linguist-generated=true rotation_quat.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/components/recording_uri.hpp b/rerun_cpp/src/rerun/components/recording_uri.hpp new file mode 100644 index 000000000000..147e91eafd7a --- /dev/null +++ b/rerun_cpp/src/rerun/components/recording_uri.hpp @@ -0,0 +1,76 @@ +// 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/components/recording_uri.fbs". + +#pragma once + +#include "../datatypes/utf8.hpp" +#include "../result.hpp" + +#include +#include +#include +#include + +namespace rerun::components { + /// **Component**: A recording URI (Uniform Resource Identifier). + struct RecordingUri { + rerun::datatypes::Utf8 recording_uri; + + public: + RecordingUri() = default; + + RecordingUri(rerun::datatypes::Utf8 recording_uri_) + : recording_uri(std::move(recording_uri_)) {} + + RecordingUri& operator=(rerun::datatypes::Utf8 recording_uri_) { + recording_uri = std::move(recording_uri_); + return *this; + } + + RecordingUri(std::string value_) : recording_uri(std::move(value_)) {} + + RecordingUri& operator=(std::string value_) { + recording_uri = std::move(value_); + return *this; + } + + /// Cast to the underlying Utf8 datatype + operator rerun::datatypes::Utf8() const { + return recording_uri; + } + }; +} // namespace rerun::components + +namespace rerun { + static_assert(sizeof(rerun::datatypes::Utf8) == sizeof(components::RecordingUri)); + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.components.RecordingUri"; + + /// 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::components::RecordingUri` into an arrow array. + static Result> to_arrow( + const components::RecordingUri* instances, size_t num_instances + ) { + if (num_instances == 0) { + return Loggable::to_arrow(nullptr, 0); + } else if (instances == nullptr) { + return rerun::Error( + ErrorCode::UnexpectedNullArgument, + "Passed array instances is null when num_elements> 0." + ); + } else { + return Loggable::to_arrow( + &instances->recording_uri, + num_instances + ); + } + } + }; +} // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/components/.gitattributes b/rerun_py/rerun_sdk/rerun/components/.gitattributes index b27be864833b..0c519ece800a 100644 --- a/rerun_py/rerun_sdk/rerun/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/components/.gitattributes @@ -45,6 +45,7 @@ position2d.py linguist-generated=true position3d.py linguist-generated=true radius.py linguist-generated=true range1d.py linguist-generated=true +recording_uri.py linguist-generated=true resolution.py linguist-generated=true rotation_axis_angle.py linguist-generated=true rotation_quat.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/components/__init__.py b/rerun_py/rerun_sdk/rerun/components/__init__.py index 5226140b1b9e..e57ef630476e 100644 --- a/rerun_py/rerun_sdk/rerun/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/components/__init__.py @@ -60,6 +60,7 @@ from .position3d import Position3D, Position3DBatch from .radius import Radius, RadiusBatch from .range1d import Range1D, Range1DBatch +from .recording_uri import RecordingUri, RecordingUriBatch from .resolution import Resolution, ResolutionBatch from .rotation_axis_angle import RotationAxisAngle, RotationAxisAngleBatch from .rotation_quat import RotationQuat, RotationQuatBatch @@ -194,6 +195,8 @@ "RadiusBatch", "Range1D", "Range1DBatch", + "RecordingUri", + "RecordingUriBatch", "Resolution", "ResolutionBatch", "RotationAxisAngle", diff --git a/rerun_py/rerun_sdk/rerun/components/recording_uri.py b/rerun_py/rerun_sdk/rerun/components/recording_uri.py new file mode 100644 index 000000000000..52220d7f92d7 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/components/recording_uri.py @@ -0,0 +1,32 @@ +# 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/components/recording_uri.fbs". + +# You can extend this class by creating a "RecordingUriExt" class in "recording_uri_ext.py". + +from __future__ import annotations + +from .. import datatypes +from .._baseclasses import ( + ComponentBatchMixin, + ComponentMixin, +) + +__all__ = ["RecordingUri", "RecordingUriBatch"] + + +class RecordingUri(datatypes.Utf8, ComponentMixin): + """**Component**: A recording URI (Uniform Resource Identifier).""" + + _BATCH_TYPE = None + # You can define your own __init__ function as a member of RecordingUriExt in recording_uri_ext.py + + # Note: there are no fields here because RecordingUri delegates to datatypes.Utf8 + pass + + +class RecordingUriBatch(datatypes.Utf8Batch, ComponentBatchMixin): + _COMPONENT_NAME: str = "rerun.components.RecordingUri" + + +# This is patched in late to avoid circular dependencies. +RecordingUri._BATCH_TYPE = RecordingUriBatch # type: ignore[assignment]