re_log_types/index/
time_point.rs

1use std::collections::{BTreeMap, btree_map};
2
3use super::{NonMinI64, TimeCell, TimeInt, Timeline, TimelineName};
4
5/// A point in time on any number of [`Timeline`]s.
6///
7/// You can think of this as all the index values for one row of data.
8///
9/// If a [`TimePoint`] is empty ([`TimePoint::default`]), the data will be considered _static_.
10/// Static data has no time associated with it, exists on all timelines, and unconditionally shadows
11/// any temporal data of the same type.
12#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
13#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
14pub struct TimePoint(BTreeMap<TimelineName, TimeCell>);
15
16impl From<BTreeMap<TimelineName, TimeCell>> for TimePoint {
17    fn from(map: BTreeMap<TimelineName, TimeCell>) -> Self {
18        Self(map)
19    }
20}
21
22impl TimePoint {
23    /// A static time point, equivalent to [`TimePoint::default`].
24    pub const STATIC: Self = Self(BTreeMap::new());
25
26    #[inline]
27    pub fn get(&self, timeline_name: &TimelineName) -> Option<NonMinI64> {
28        self.0.get(timeline_name).map(|cell| cell.value)
29    }
30
31    #[inline]
32    pub fn insert_cell(
33        &mut self,
34        timeline_name: impl Into<TimelineName>,
35        cell: impl Into<TimeCell>,
36    ) {
37        let timeline_name = timeline_name.into();
38        let cell = cell.into();
39
40        match self.0.entry(timeline_name) {
41            btree_map::Entry::Vacant(vacant_entry) => {
42                vacant_entry.insert(cell);
43            }
44            btree_map::Entry::Occupied(mut occupied_entry) => {
45                let existing_typ = occupied_entry.get().typ();
46                if existing_typ != cell.typ() {
47                    re_log::warn_once!(
48                        "Timeline {timeline_name:?} changed type from {existing_typ:?} to {:?}. \
49                         Rerun does not support using different types for the same timeline.",
50                        cell.typ()
51                    );
52                }
53                occupied_entry.insert(cell);
54            }
55        }
56    }
57
58    #[inline]
59    pub fn insert(&mut self, timeline: Timeline, time: impl TryInto<TimeInt>) {
60        let cell = TimeCell::new(timeline.typ(), TimeInt::saturated_temporal(time).as_i64());
61        self.insert_cell(*timeline.name(), cell);
62    }
63
64    #[must_use]
65    #[inline]
66    pub fn with_index(
67        mut self,
68        timeline_name: impl Into<TimelineName>,
69        cell: impl Into<TimeCell>,
70    ) -> Self {
71        self.insert_cell(timeline_name, cell);
72        self
73    }
74
75    #[must_use]
76    #[inline]
77    pub fn with(mut self, timeline: Timeline, time: impl TryInto<TimeInt>) -> Self {
78        self.insert(timeline, time);
79        self
80    }
81
82    #[inline]
83    pub fn remove(&mut self, timeline: &TimelineName) {
84        self.0.remove(timeline);
85    }
86
87    #[inline]
88    pub fn is_static(&self) -> bool {
89        self.0.is_empty()
90    }
91
92    #[inline]
93    pub fn is_empty(&self) -> bool {
94        self.0.is_empty()
95    }
96
97    #[inline]
98    pub fn timeline_names(&self) -> impl ExactSizeIterator<Item = &TimelineName> {
99        self.0.keys()
100    }
101
102    #[inline]
103    pub fn iter(&self) -> impl ExactSizeIterator<Item = (&TimelineName, &TimeCell)> {
104        self.0.iter()
105    }
106}
107
108impl re_byte_size::SizeBytes for TimePoint {
109    #[inline]
110    fn heap_size_bytes(&self) -> u64 {
111        self.0.heap_size_bytes()
112    }
113}
114
115// ----------------------------------------------------------------------------
116
117impl IntoIterator for TimePoint {
118    type Item = (TimelineName, TimeCell);
119
120    type IntoIter = btree_map::IntoIter<TimelineName, TimeCell>;
121
122    #[inline]
123    fn into_iter(self) -> Self::IntoIter {
124        self.0.into_iter()
125    }
126}
127
128impl<'a> IntoIterator for &'a TimePoint {
129    type Item = (&'a TimelineName, &'a TimeCell);
130
131    type IntoIter = btree_map::Iter<'a, TimelineName, TimeCell>;
132
133    #[inline]
134    fn into_iter(self) -> Self::IntoIter {
135        self.0.iter()
136    }
137}
138
139impl<Name, Cell> FromIterator<(Name, Cell)> for TimePoint
140where
141    Name: Into<TimelineName>,
142    Cell: Into<TimeCell>,
143{
144    #[inline]
145    fn from_iter<I: IntoIterator<Item = (Name, Cell)>>(iter: I) -> Self {
146        Self(
147            iter.into_iter()
148                .map(|(name, cell)| (name.into(), cell.into()))
149                .collect(),
150        )
151    }
152}
153
154impl<Name, Cell, const N: usize> From<[(Name, Cell); N]> for TimePoint
155where
156    Name: Into<TimelineName>,
157    Cell: Into<TimeCell>,
158{
159    #[inline]
160    fn from(timelines: [(Name, Cell); N]) -> Self {
161        Self(
162            timelines
163                .into_iter()
164                .map(|(name, cell)| (name.into(), cell.into()))
165                .collect(),
166        )
167    }
168}
169
170impl<T: TryInto<TimeInt>> FromIterator<(Timeline, T)> for TimePoint {
171    #[inline]
172    fn from_iter<I: IntoIterator<Item = (Timeline, T)>>(iter: I) -> Self {
173        Self(
174            iter.into_iter()
175                .map(|(timeline, time)| {
176                    let time = TimeInt::saturated_temporal(time);
177                    (
178                        *timeline.name(),
179                        TimeCell::new(timeline.typ(), time.as_i64()),
180                    )
181                })
182                .collect(),
183        )
184    }
185}
186
187impl<T: TryInto<TimeInt>, const N: usize> From<[(Timeline, T); N]> for TimePoint {
188    #[inline]
189    fn from(timelines: [(Timeline, T); N]) -> Self {
190        Self(
191            timelines
192                .into_iter()
193                .map(|(timeline, time)| {
194                    let time = TimeInt::saturated_temporal(time);
195                    (
196                        *timeline.name(),
197                        TimeCell::new(timeline.typ(), time.as_i64()),
198                    )
199                })
200                .collect(),
201        )
202    }
203}