re_types_core/
component_descriptor.rs

1use std::borrow::Cow;
2
3use crate::{ArchetypeName, ComponentIdentifier, ComponentType};
4
5/// A [`ComponentDescriptor`] fully describes the semantics of a column of data.
6///
7/// Every component at a given entity path is uniquely identified by the
8/// `component` field of the descriptor. The `archetype` and `component_type`
9/// fields provide additional information about the semantics of the data.
10#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
11#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
12pub struct ComponentDescriptor {
13    /// Optional name of the `Archetype` associated with this data.
14    ///
15    /// `None` if the data wasn't logged through an archetype.
16    ///
17    /// Example: `rerun.archetypes.Points3D`.
18    pub archetype: Option<ArchetypeName>,
19
20    /// Uniquely identifies of the component associated with this data.
21    ///
22    /// Example: `Points3D:positions`.
23    pub component: ComponentIdentifier,
24
25    /// Optional type information for this component.
26    ///
27    /// Can be used to inform applications on how to interpret the data.
28    ///
29    /// Example: `rerun.components.Position3D`.
30    pub component_type: Option<ComponentType>,
31}
32
33impl std::hash::Hash for ComponentDescriptor {
34    #[inline]
35    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
36        let Self {
37            archetype: archetype_name,
38            component,
39            component_type,
40        } = self;
41
42        let archetype_name = archetype_name.map_or(0, |v| v.hash());
43        let component = component.hash();
44        let component_type = component_type.map_or(0, |v| v.hash());
45
46        // NOTE: This is a NoHash type, so we must respect the invariant that `write_XX` is only
47        // called once, see <https://docs.rs/nohash-hasher/0.2.0/nohash_hasher/trait.IsEnabled.html>.
48        state.write_u64(archetype_name ^ component ^ component_type);
49    }
50}
51
52impl nohash_hasher::IsEnabled for ComponentDescriptor {}
53
54impl std::fmt::Display for ComponentDescriptor {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        f.write_str(self.display_name())
57    }
58}
59
60impl From<ComponentDescriptor> for Cow<'static, ComponentDescriptor> {
61    #[inline]
62    fn from(descr: ComponentDescriptor) -> Self {
63        Cow::Owned(descr)
64    }
65}
66
67impl<'d> From<&'d ComponentDescriptor> for Cow<'d, ComponentDescriptor> {
68    #[inline]
69    fn from(descr: &'d ComponentDescriptor) -> Self {
70        Cow::Borrowed(descr)
71    }
72}
73
74impl ComponentDescriptor {
75    #[inline]
76    #[track_caller]
77    pub fn sanity_check(&self) {
78        if let Some(component_type) = self.component_type {
79            component_type.sanity_check();
80        }
81    }
82
83    /// Short and usually unique, used in UI.
84    pub fn display_name(&self) -> &str {
85        self.sanity_check();
86        self.component.as_str()
87    }
88}
89
90impl re_byte_size::SizeBytes for ComponentDescriptor {
91    #[inline]
92    fn heap_size_bytes(&self) -> u64 {
93        let Self {
94            archetype: archetype_name,
95            component,
96            component_type,
97        } = self;
98        archetype_name.heap_size_bytes()
99            + component_type.heap_size_bytes()
100            + component.heap_size_bytes()
101    }
102}
103
104impl ComponentDescriptor {
105    /// Creates a new component descriptor that only has the `component` set.
106    ///
107    /// Both `archetype` and `component_type` will be missing.
108    pub fn partial(component: impl Into<ComponentIdentifier>) -> Self {
109        Self {
110            archetype: None,
111            component: component.into(),
112            component_type: None,
113        }
114    }
115
116    /// Unconditionally sets [`Self::archetype`] to the given one.
117    #[inline]
118    pub fn with_archetype(mut self, archetype_name: ArchetypeName) -> Self {
119        self.archetype = Some(archetype_name);
120        self
121    }
122
123    /// Unconditionally sets [`Self::component`] to the given one.
124    #[inline]
125    pub fn with_component_type(mut self, component_type: ComponentType) -> Self {
126        self.component_type = Some(component_type);
127        self
128    }
129
130    /// Sets [`Self::archetype`] to the given one iff it's not already set.
131    #[inline]
132    pub fn or_with_archetype(mut self, archetype_name: impl Fn() -> ArchetypeName) -> Self {
133        if self.archetype.is_none() {
134            self.archetype = Some(archetype_name());
135        }
136        self
137    }
138
139    /// Sets [`Self::component_type`] to the given one iff it's not already set.
140    #[inline]
141    pub fn or_with_component_type(
142        mut self,
143        component_type: impl FnOnce() -> ComponentType,
144    ) -> Self {
145        if self.component_type.is_none() {
146            self.component_type = Some(component_type());
147        }
148        self
149    }
150}
151
152// ---
153
154// TODO(cmc): This is far from ideal and feels very hackish, but for now the priority is getting
155// all things related to tags up and running so we can gather learnings.
156// This is only used on the archetype deserialization path, which isn't ever used outside of tests anyway.
157
158// TODO(cmc): we really shouldn't be duplicating these.
159
160/// The key used to identify the [`crate::ArchetypeName`] in field-level metadata.
161const FIELD_METADATA_KEY_ARCHETYPE: &str = "rerun:archetype";
162
163/// The key used to identify the [`crate::ComponentIdentifier`] in field-level metadata.
164const FIELD_METADATA_KEY_COMPONENT: &str = "rerun:component";
165
166/// The key used to identify the [`crate::ComponentType`] in field-level metadata.
167const FIELD_METADATA_KEY_COMPONENT_TYPE: &str = "rerun:component_type";
168
169impl From<arrow::datatypes::Field> for ComponentDescriptor {
170    #[inline]
171    fn from(field: arrow::datatypes::Field) -> Self {
172        let md = field.metadata();
173
174        let descr = Self {
175            archetype: md
176                .get(FIELD_METADATA_KEY_ARCHETYPE)
177                .cloned()
178                .map(Into::into),
179            component: md.get(FIELD_METADATA_KEY_COMPONENT).cloned().unwrap_or_else(|| {
180                re_log::debug!("Missing metadata field {FIELD_METADATA_KEY_COMPONENT}, resorting to field name: {}", field.name());
181                field.name().to_string()
182            }).into(),
183            component_type: md
184                .get(FIELD_METADATA_KEY_COMPONENT_TYPE)
185                .cloned()
186                .map(Into::into),
187        };
188        descr.sanity_check();
189        descr
190    }
191}