dash_runtime/address/
timeline.rs1use crate::limits::MAX_TIMELINE_SEGMENTS;
20use crate::mpd::model::SegmentTimeline;
21
22use super::AddressError;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[non_exhaustive]
27pub struct TimelineSegment {
28 pub number: u64,
30 pub time: u64,
32 pub duration: u64,
34}
35
36#[derive(Debug, Clone, Copy)]
37struct Run {
38 first_index: u64,
39 time: u64,
40 number: u64,
41 d: u64,
42 count: u64,
43}
44
45#[derive(Debug, Clone, Default)]
47pub struct TimelineIndex {
48 runs: Vec<Run>,
49 total: u64,
50}
51
52const TIMELINE_T_TOLERANCE_TICKS: u64 = 1;
58
59impl TimelineIndex {
60 pub fn build(
70 timeline: &SegmentTimeline,
71 start_number: u64,
72 period_end_ticks: Option<u64>,
73 ) -> Result<Self, AddressError> {
74 if let Some(u) = timeline.unsupported {
75 return Err(AddressError::Unsupported(u));
76 }
77 let entries = &timeline.entries;
78 let mut runs = Vec::with_capacity(entries.len());
79 let mut time: u64 = 0;
80 let mut number = start_number;
81 let mut total: u64 = 0;
82 for (i, s) in entries.iter().enumerate() {
83 if s.d == 0 {
84 return Err(AddressError::ZeroSegmentDuration);
85 }
86 if let Some(t) = s.t {
87 if time.saturating_sub(t) > TIMELINE_T_TOLERANCE_TICKS {
88 return Err(AddressError::TimelineNotIncreasing { t, floor: time });
89 }
90 time = t;
91 }
92 if let Some(n) = s.n {
93 if n < number {
94 return Err(AddressError::NumberNotIncreasing {
95 n,
96 expected: number,
97 });
98 }
99 number = n;
100 }
101 let count = if s.r >= 0 {
102 s.r.unsigned_abs().saturating_add(1)
103 } else {
104 let next_t = entries.get(i + 1).and_then(|n| n.t);
105 if let Some(next_t) = next_t
106 && time.saturating_sub(next_t) > TIMELINE_T_TOLERANCE_TICKS
107 {
108 return Err(AddressError::TimelineNotIncreasing {
109 t: next_t,
110 floor: time,
111 });
112 }
113 match next_t.or(period_end_ticks) {
114 Some(end) => end.saturating_sub(time).div_ceil(s.d),
115 None => 1,
116 }
117 };
118 if count > MAX_TIMELINE_SEGMENTS || total.saturating_add(count) > MAX_TIMELINE_SEGMENTS
119 {
120 return Err(AddressError::TimelineTooLong {
121 count_hint: total.saturating_add(count),
122 });
123 }
124 if count > 0 {
125 runs.push(Run {
126 first_index: total,
127 time,
128 number,
129 d: s.d,
130 count,
131 });
132 }
133 let span = s.d.checked_mul(count).ok_or(AddressError::Overflow)?;
134 let cut_at_next = s.r < 0 && entries.get(i + 1).is_some_and(|n| n.t.is_some());
135 time = if cut_at_next {
136 entries[i + 1].t.unwrap_or(time)
137 } else {
138 time.checked_add(span).ok_or(AddressError::Overflow)?
139 };
140 number = number.saturating_add(count);
141 total += count;
142 }
143 Ok(Self { runs, total })
144 }
145
146 #[must_use]
148 pub fn len(&self) -> u64 {
149 self.total
150 }
151
152 #[must_use]
154 pub fn is_empty(&self) -> bool {
155 self.total == 0
156 }
157
158 #[must_use]
160 pub fn segment(&self, index: u64) -> Option<TimelineSegment> {
161 if index >= self.total {
162 return None;
163 }
164 let at = self.runs.partition_point(|r| r.first_index <= index) - 1;
165 let run = self.runs[at];
166 let k = index - run.first_index;
167 Some(TimelineSegment {
168 number: run.number.saturating_add(k),
169 time: run.time.saturating_add(k.saturating_mul(run.d)),
170 duration: run.d,
171 })
172 }
173
174 #[must_use]
177 pub fn index_at_or_before(&self, time: u64) -> Option<u64> {
178 let at = self.runs.partition_point(|r| r.time <= time);
179 if at == 0 {
180 return None;
181 }
182 let run = self.runs[at - 1];
183 let k = ((time - run.time) / run.d).min(run.count - 1);
184 Some(run.first_index + k)
185 }
186
187 #[must_use]
190 pub fn count_up_to_number(&self, max_number: u64) -> u64 {
191 let mut count = 0u64;
192 for run in &self.runs {
193 if run.number > max_number {
194 break;
195 }
196 let fit = (max_number - run.number).saturating_add(1);
197 count += fit.min(run.count);
198 if fit < run.count {
199 break;
200 }
201 }
202 count
203 }
204
205 pub fn iter(&self) -> impl Iterator<Item = TimelineSegment> + '_ {
207 (0..self.total).filter_map(|i| self.segment(i))
208 }
209}