re_types_core/
id.rs

1/// A unique ID for a `Chunk`.
2///
3/// `Chunk`s are the atomic unit of ingestion, transport, storage, events and GC in Rerun.
4///
5/// Internally, a `Chunk` is made up of rows, which are themselves uniquely identified by
6/// their [`RowId`].
7///
8/// There is no relationship whatsoever between a [`ChunkId`] and the [`RowId`]s within that chunk.
9///
10/// ### Uniqueness
11///
12/// [`ChunkId`] are assumed unique within a single Recording.
13///
14/// The chunk store will treat two chunks with the same [`ChunkId`] as the same, and only keep one
15/// of them (which one is kept is an arbitrary and unstable implementation detail).
16///
17/// This makes it easy to build and maintain secondary indices around [`RowId`]s with few to no
18/// extraneous state tracking.
19///
20/// ### Garbage collection
21///
22/// Garbage collection is handled at the chunk level by first ordering the chunks based on the minimum
23/// [`RowId`] present in each of them.
24/// Garbage collection therefore happens (roughly) in the logger's wall-clock order.
25///
26/// This has very important implications when inserting data far into the past or into the future:
27/// think carefully about your `RowId`s in these cases.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
30pub struct ChunkId(pub(crate) re_tuid::Tuid);
31
32impl std::fmt::Display for ChunkId {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        self.0.fmt(f)
35    }
36}
37
38impl ChunkId {
39    pub const ZERO: Self = Self(re_tuid::Tuid::ZERO);
40    pub const MAX: Self = Self(re_tuid::Tuid::MAX);
41
42    /// Create a new unique [`ChunkId`] based on the current time.
43    #[allow(clippy::new_without_default)]
44    #[inline]
45    pub fn new() -> Self {
46        Self(re_tuid::Tuid::new())
47    }
48
49    /// Returns the next logical [`ChunkId`].
50    ///
51    /// Beware: wrong usage can easily lead to conflicts.
52    /// Prefer [`ChunkId::new`] when unsure.
53    #[must_use]
54    #[inline]
55    pub fn next(&self) -> Self {
56        Self(self.0.next())
57    }
58
59    /// Returns the `n`-next logical [`ChunkId`].
60    ///
61    /// This is equivalent to calling [`ChunkId::next`] `n` times.
62    /// Wraps the monotonically increasing back to zero on overflow.
63    ///
64    /// Beware: wrong usage can easily lead to conflicts.
65    /// Prefer [`ChunkId::new`] when unsure.
66    #[must_use]
67    #[inline]
68    pub fn incremented_by(&self, n: u64) -> Self {
69        Self(self.0.incremented_by(n))
70    }
71
72    /// When the `ChunkId` was created, in nanoseconds since unix epoch.
73    #[inline]
74    pub fn nanoseconds_since_epoch(&self) -> u64 {
75        self.0.nanoseconds_since_epoch()
76    }
77
78    #[inline]
79    pub fn from_u128(id: u128) -> Self {
80        Self(re_tuid::Tuid::from_u128(id))
81    }
82
83    #[inline]
84    pub fn as_u128(&self) -> u128 {
85        self.0.as_u128()
86    }
87}
88
89impl re_byte_size::SizeBytes for ChunkId {
90    #[inline]
91    fn heap_size_bytes(&self) -> u64 {
92        0
93    }
94
95    #[inline]
96    fn is_pod() -> bool {
97        true
98    }
99}
100
101impl std::ops::Deref for ChunkId {
102    type Target = re_tuid::Tuid;
103
104    #[inline]
105    fn deref(&self) -> &Self::Target {
106        &self.0
107    }
108}
109
110impl std::ops::DerefMut for ChunkId {
111    #[inline]
112    fn deref_mut(&mut self) -> &mut Self::Target {
113        &mut self.0
114    }
115}
116
117crate::delegate_arrow_tuid!(ChunkId as "rerun.controls.ChunkId");
118
119// ---
120
121/// A unique ID for a row's worth of data within a chunk.
122///
123/// There is no relationship whatsoever between a [`ChunkId`] and the [`RowId`]s within that chunk.
124///
125/// ### Uniqueness
126///
127/// Duplicated [`RowId`]s within a single recording is considered undefined behavior.
128///
129/// While it is benign in most cases, care has to be taken when manually crafting [`RowId`]s.
130/// Ideally: don't do so and stick to [`RowId::new`] instead to avoid bad surprises.
131///
132/// This makes it easy to build and maintain secondary indices around [`RowId`]s with few to no
133/// extraneous state tracking.
134///
135/// ### Query
136///
137/// Queries (both latest-at & range semantics) will defer to `RowId` order as a tie-breaker when
138/// looking at several rows worth of data that rest at the exact same timestamp.
139///
140/// In pseudo-code:
141/// ```text
142/// rr.set_time_sequence("frame", 10)
143///
144/// rr.log("my_entity", point1, row_id=#1)
145/// rr.log("my_entity", point2, row_id=#0)
146///
147/// rr.query("my_entity", at=("frame", 10))  # returns `point1`
148/// ```
149///
150/// Think carefully about your `RowId`s when logging a lot of data at the same timestamp.
151///
152/// ### Garbage collection
153///
154/// Garbage collection is handled at the chunk level by first ordering the chunks based on the minimum
155/// [`RowId`] present in each of them.
156/// Garbage collection therefore happens (roughly) in the logger's wall-clock order.
157///
158/// This has very important implications when inserting data far into the past or into the future:
159/// think carefully about your `RowId`s in these cases.
160#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
161#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
162pub struct RowId(pub(crate) re_tuid::Tuid);
163
164impl std::fmt::Display for RowId {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        self.0.fmt(f)
167    }
168}
169
170impl RowId {
171    pub const ZERO: Self = Self(re_tuid::Tuid::ZERO);
172    pub const MAX: Self = Self(re_tuid::Tuid::MAX);
173
174    /// Create a new unique [`RowId`] based on the current time.
175    #[allow(clippy::new_without_default)]
176    #[inline]
177    pub fn new() -> Self {
178        Self(re_tuid::Tuid::new())
179    }
180
181    #[inline]
182    pub fn from_tuid(tuid: re_tuid::Tuid) -> Self {
183        Self(tuid)
184    }
185
186    /// Returns the next logical [`RowId`].
187    ///
188    /// Beware: wrong usage can easily lead to conflicts.
189    /// Prefer [`RowId::new`] when unsure.
190    #[must_use]
191    #[inline]
192    pub fn next(&self) -> Self {
193        Self(self.0.next())
194    }
195
196    /// Returns the `n`-next logical [`RowId`].
197    ///
198    /// This is equivalent to calling [`RowId::next`] `n` times.
199    /// Wraps the monotonically increasing back to zero on overflow.
200    ///
201    /// Beware: wrong usage can easily lead to conflicts.
202    /// Prefer [`RowId::new`] when unsure.
203    #[must_use]
204    #[inline]
205    pub fn incremented_by(&self, n: u64) -> Self {
206        Self(self.0.incremented_by(n))
207    }
208
209    /// When the `RowId` was created, in nanoseconds since unix epoch.
210    #[inline]
211    pub fn nanoseconds_since_epoch(&self) -> u64 {
212        self.0.nanoseconds_since_epoch()
213    }
214
215    #[inline]
216    pub fn from_u128(id: u128) -> Self {
217        Self(re_tuid::Tuid::from_u128(id))
218    }
219
220    #[inline]
221    pub fn as_u128(&self) -> u128 {
222        self.0.as_u128()
223    }
224}
225
226impl re_byte_size::SizeBytes for RowId {
227    #[inline]
228    fn heap_size_bytes(&self) -> u64 {
229        0
230    }
231
232    #[inline]
233    fn is_pod() -> bool {
234        true
235    }
236}
237
238impl std::ops::Deref for RowId {
239    type Target = re_tuid::Tuid;
240
241    #[inline]
242    fn deref(&self) -> &Self::Target {
243        &self.0
244    }
245}
246
247impl std::ops::DerefMut for RowId {
248    #[inline]
249    fn deref_mut(&mut self) -> &mut Self::Target {
250        &mut self.0
251    }
252}
253
254crate::delegate_arrow_tuid!(RowId as "rerun.controls.RowId");