re_types_core/archetype.rs
1use crate::{ComponentDescriptor, DeserializationResult};
2
3#[expect(unused_imports, clippy::unused_trait_names)] // used in docstrings
4use crate::{Component, Loggable};
5
6// ---
7
8/// An archetype is a high-level construct that represents a set of [`Component`]s that usually
9/// play well with each other (i.e. they compose nicely).
10///
11/// Internally, it is no different than a collection of components, but working at that higher
12/// layer of abstraction opens opportunities for nicer APIs & tools that wouldn't be possible
13/// otherwise.
14///
15/// E.g. consider the `crate::archetypes::Points3D` archetype, which represents the set of
16/// components to consider when working with a 3D point cloud within Rerun.
17pub trait Archetype {
18 /// The fully-qualified name of this archetype, e.g. `rerun.archetypes.Points2D`.
19 fn name() -> ArchetypeName;
20
21 /// Readable name for displaying in UI.
22 fn display_name() -> &'static str;
23
24 // ---
25
26 /// Returns all component descriptors that _must_ be provided by the user when constructing this archetype.
27 fn required_components() -> std::borrow::Cow<'static, [ComponentDescriptor]>;
28
29 /// Returns all component descriptors that _should_ be provided by the user when constructing this archetype.
30 #[inline]
31 fn recommended_components() -> std::borrow::Cow<'static, [ComponentDescriptor]> {
32 // TODO(#10512): Maybe add the "marker" component back here?
33 std::borrow::Cow::Owned(vec![])
34 }
35
36 /// Returns all component descriptors that _may_ be provided by the user when constructing this archetype.
37 #[inline]
38 fn optional_components() -> std::borrow::Cow<'static, [ComponentDescriptor]> {
39 std::borrow::Cow::Borrowed(&[])
40 }
41
42 /// Returns all component descriptors that must, should and may be provided by the user when constructing
43 /// this archetype.
44 ///
45 /// The default implementation always does the right thing, at the cost of some runtime
46 /// allocations.
47 /// If you know all your component descriptors statically, you can override this method to get rid of the
48 /// extra allocations.
49 #[inline]
50 fn all_components() -> std::borrow::Cow<'static, [ComponentDescriptor]> {
51 [
52 Self::required_components().into_owned(),
53 Self::recommended_components().into_owned(),
54 Self::optional_components().into_owned(),
55 ]
56 .into_iter()
57 .flatten()
58 .collect::<Vec<_>>()
59 .into()
60 }
61
62 // ---
63
64 /// Given an iterator of Arrow arrays and their respective field metadata, deserializes them
65 /// into this archetype.
66 ///
67 /// Arrow arrays that are unknown to this [`Archetype`] will simply be ignored and a warning
68 /// logged to stderr.
69 #[inline]
70 fn from_arrow(
71 data: impl IntoIterator<Item = (arrow::datatypes::Field, ::arrow::array::ArrayRef)>,
72 ) -> DeserializationResult<Self>
73 where
74 Self: Sized,
75 {
76 Self::from_arrow_components(
77 data.into_iter()
78 .map(|(field, array)| (ComponentDescriptor::from(field), array)),
79 )
80 }
81
82 /// Given an iterator of Arrow arrays and their respective [`ComponentDescriptor`]s, deserializes them
83 /// into this archetype.
84 ///
85 /// Arrow arrays that are unknown to this [`Archetype`] will simply be ignored and a warning
86 /// logged to stderr.
87 #[inline]
88 fn from_arrow_components(
89 data: impl IntoIterator<Item = (ComponentDescriptor, ::arrow::array::ArrayRef)>,
90 ) -> DeserializationResult<Self>
91 where
92 Self: Sized,
93 {
94 _ = data; // NOTE: do this here to avoid breaking users' autocomplete snippets
95 Err(crate::DeserializationError::NotImplemented {
96 fqname: Self::name().to_string(),
97 backtrace: std::backtrace::Backtrace::capture(),
98 })
99 }
100}
101
102/// Indicates that the archetype has reflection data available for it.
103pub trait ArchetypeReflectionMarker {}
104
105// ---
106
107re_string_interner::declare_new_type!(
108 /// The fully-qualified name of an [`Archetype`], e.g. `rerun.archetypes.Points3D`.
109 #[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
110 pub struct ArchetypeName;
111);
112
113impl ArchetypeName {
114 /// Runs some asserts in debug mode to make sure the name is not weird.
115 #[inline]
116 #[track_caller]
117 pub fn sanity_check(&self) {
118 let full_name = self.0.as_str();
119 debug_assert!(
120 !full_name.starts_with("rerun.archetypes.rerun.archetypes.")
121 && !full_name.contains(':'),
122 "DEBUG ASSERT: Found archetype with full name {full_name:?}. Maybe some bad round-tripping?"
123 );
124 }
125
126 /// Returns the fully-qualified name, e.g. `rerun.archetypes.Points3D`.
127 ///
128 /// This is the default `Display` implementation for [`ArchetypeName`].
129 #[inline]
130 pub fn full_name(&self) -> &'static str {
131 self.sanity_check();
132 self.0.as_str()
133 }
134
135 /// Returns the unqualified name, e.g. `Points3D`.
136 ///
137 /// Used for most UI elements.
138 ///
139 /// ```
140 /// # use re_types_core::ArchetypeName;
141 /// assert_eq!(ArchetypeName::from("rerun.archetypes.Points3D").short_name(), "Points3D");
142 /// ```
143 #[inline]
144 pub fn short_name(&self) -> &'static str {
145 self.sanity_check();
146 let full_name = self.0.as_str();
147 if let Some(short_name) = full_name.strip_prefix("rerun.archetypes.") {
148 short_name
149 } else if let Some(short_name) = full_name.strip_prefix("rerun.blueprint.archetypes.") {
150 short_name
151 } else if let Some(short_name) = full_name.strip_prefix("rerun.") {
152 short_name
153 } else {
154 full_name
155 }
156 }
157
158 /// Url to the rerun docs for this Rerun archetype.
159 pub fn doc_url(&self) -> Option<String> {
160 // This code should be correct as long as this url passes our link checker:
161 // https://rerun.io/docs/reference/types/archetypes/line_strips3d
162 let short_name_pascal_case = self.full_name().strip_prefix("rerun.archetypes.")?;
163 let archetype_name_snake_case = re_case::to_snake_case(short_name_pascal_case);
164 let base_url = "https://rerun.io/docs/reference/types/archetypes";
165 Some(format!("{base_url}/{archetype_name_snake_case}"))
166 }
167}
168
169impl re_byte_size::SizeBytes for ArchetypeName {
170 #[inline]
171 fn heap_size_bytes(&self) -> u64 {
172 0
173 }
174}
175
176// ---
177
178re_string_interner::declare_new_type!(
179 /// An identifier for a component, i.e. a field in an [`Archetype`].
180 #[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
181 pub struct ComponentIdentifier;
182);
183
184impl re_byte_size::SizeBytes for ComponentIdentifier {
185 #[inline]
186 fn heap_size_bytes(&self) -> u64 {
187 0
188 }
189}