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: Box::new(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 "DEBUG ASSERT: Found archetype with full name {full_name:?}. Maybe some bad round-tripping?"
122 );
123 }
124
125 /// Returns the fully-qualified name, e.g. `rerun.archetypes.Points3D`.
126 ///
127 /// This is the default `Display` implementation for [`ArchetypeName`].
128 #[inline]
129 pub fn full_name(&self) -> &'static str {
130 self.sanity_check();
131 self.0.as_str()
132 }
133
134 /// Returns the unqualified name, e.g. `Points3D`.
135 ///
136 /// Used for most UI elements.
137 ///
138 /// ```
139 /// # use re_types_core::ArchetypeName;
140 /// assert_eq!(ArchetypeName::from("rerun.archetypes.Points3D").short_name(), "Points3D");
141 /// ```
142 #[inline]
143 pub fn short_name(&self) -> &'static str {
144 self.sanity_check();
145 let full_name = self.0.as_str();
146 if let Some(short_name) = full_name.strip_prefix("rerun.archetypes.") {
147 short_name
148 } else if let Some(short_name) = full_name.strip_prefix("rerun.blueprint.archetypes.") {
149 short_name
150 } else if let Some(short_name) = full_name.strip_prefix("rerun.") {
151 short_name
152 } else {
153 full_name
154 }
155 }
156
157 /// Url to the rerun docs for this Rerun archetype.
158 pub fn doc_url(&self) -> Option<String> {
159 // This code should be correct as long as this url passes our link checker:
160 // https://rerun.io/docs/reference/types/archetypes/line_strips3d
161 let short_name_pascal_case = self.full_name().strip_prefix("rerun.archetypes.")?;
162 let archetype_name_snake_case = re_case::to_snake_case(short_name_pascal_case);
163 let base_url = "https://rerun.io/docs/reference/types/archetypes";
164 Some(format!("{base_url}/{archetype_name_snake_case}"))
165 }
166}
167
168impl re_byte_size::SizeBytes for ArchetypeName {
169 #[inline]
170 fn heap_size_bytes(&self) -> u64 {
171 0
172 }
173}
174
175// ---
176
177re_string_interner::declare_new_type!(
178 /// An identifier for a component, i.e. a field in an [`Archetype`].
179 #[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
180 pub struct ComponentIdentifier;
181);
182
183impl re_byte_size::SizeBytes for ComponentIdentifier {
184 #[inline]
185 fn heap_size_bytes(&self) -> u64 {
186 0
187 }
188}