1use crate::{
2 grouping::{Range, Range3d, RangeEnd},
3 Path, SubspaceId,
4};
5
6use compact_u64::{CompactU64, Tag, TagWidth};
7use ufotofu::{BulkConsumer, BulkProducer};
8
9use ufotofu_codec::{
10 Blame, DecodableCanonic, DecodeError, Encodable, EncodableKnownSize, EncodableSync,
11 RelativeDecodable, RelativeDecodableCanonic, RelativeDecodableSync, RelativeEncodable,
12 RelativeEncodableKnownSize, RelativeEncodableSync,
13};
14use willow_encoding::is_bitflagged;
15
16impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
17 RelativeEncodable<Range3d<MCL, MCC, MPL, S>> for Range3d<MCL, MCC, MPL, S>
18where
19 S: SubspaceId + Encodable,
20{
21 async fn relative_encode<C>(
25 &self,
26 consumer: &mut C,
27 r: &Range3d<MCL, MCC, MPL, S>,
28 ) -> Result<(), C::Error>
29 where
30 C: BulkConsumer<Item = u8>,
31 {
32 let start_to_start = self.times().start.abs_diff(r.times().start);
33 let start_to_end = match r.times().end {
34 RangeEnd::Closed(end) => self.times().start.abs_diff(end),
35 RangeEnd::Open => u64::MAX,
36 };
37 let end_to_start = match self.times().end {
38 RangeEnd::Closed(end) => end.abs_diff(r.times().start),
39 RangeEnd::Open => u64::MAX,
40 };
41 let end_to_end = match (&self.times().end, &r.times().end) {
42 (RangeEnd::Closed(self_end), RangeEnd::Closed(ref_end)) => self_end.abs_diff(*ref_end),
43 (RangeEnd::Closed(_), RangeEnd::Open) => u64::MAX,
44 (RangeEnd::Open, RangeEnd::Closed(_)) => u64::MAX,
45 (RangeEnd::Open, RangeEnd::Open) => 0, };
47
48 let start_time_diff = core::cmp::min(start_to_start, start_to_end);
49
50 let end_time_diff = core::cmp::min(end_to_start, end_to_end);
51
52 let mut header_1 = 0b0000_0000;
53
54 if self.subspaces().start == r.subspaces().start {
56 header_1 |= 0b0100_0000;
57 } else if r.subspaces().end == self.subspaces().start {
58 header_1 |= 0b1000_0000;
59 } else {
60 header_1 |= 0b1100_0000;
61 }
62
63 if self.subspaces().end == RangeEnd::Open {
65 } else if self.subspaces().end == r.subspaces().start {
67 header_1 |= 0b0001_0000;
68 } else if self.subspaces().end == r.subspaces().end {
69 header_1 |= 0b0010_0000;
70 } else if self.subspaces().end != RangeEnd::Open {
71 header_1 |= 0b0011_0000;
72 }
73
74 if let RangeEnd::Closed(ref_path_end) = &r.paths().end {
76 let lcp_start_start = self.paths().start.longest_common_prefix(&r.paths().start);
77 let lcp_start_end = self.paths().start.longest_common_prefix(ref_path_end);
78
79 if lcp_start_start.component_count() >= lcp_start_end.component_count() {
80 header_1 |= 0b0000_1000;
81 }
82 } else {
83 header_1 |= 0b0000_1000;
84 }
85
86 if self.paths().end == RangeEnd::Open {
88 header_1 |= 0b0000_0100;
89 }
90
91 match (&self.paths().end, &r.paths().end) {
93 (RangeEnd::Closed(self_path_end), RangeEnd::Closed(ref_path_end)) => {
94 let lcp_end_start = self_path_end.longest_common_prefix(&r.paths().start);
95 let lcp_end_end = self_path_end.longest_common_prefix(ref_path_end);
96
97 if lcp_end_start.component_count() >= lcp_end_end.component_count() {
98 header_1 |= 0b0000_0010;
99 }
100 }
101 (RangeEnd::Closed(_), RangeEnd::Open) => {
102 header_1 |= 0b0000_0010;
103 }
104 (RangeEnd::Open, RangeEnd::Closed(_)) => {}
105 (RangeEnd::Open, RangeEnd::Open) => {}
106 }
107
108 if self.times().end == RangeEnd::Open {
110 header_1 |= 0b0000_0001;
111 }
112
113 consumer.consume(header_1).await?;
114
115 let mut header_2 = 0b0000_0000;
116
117 if start_to_start <= start_to_end {
119 header_2 |= 0b1000_0000;
120 }
121
122 if is_bitflagged(header_2, 0) && self.times().start >= r.times().start
124 || !is_bitflagged(header_2, 0) && self.times().start >= r.times().end
125 {
126 header_2 |= 0b0100_0000;
127 }
128
129 let start_diff_tag = Tag::min_tag(start_time_diff, TagWidth::two());
131 header_2 |= start_diff_tag.data_at_offset(2);
132
133 if self.times().end != RangeEnd::Open && end_to_start <= end_to_end {
135 header_2 |= 0b0000_1000;
136 }
137
138 if self.times().end == RangeEnd::Open {
140 } else if (is_bitflagged(header_2, 4) && self.times().end >= r.times().start)
142 || (!is_bitflagged(header_2, 4) && self.times().end >= r.times().end)
143 {
144 header_2 |= 0b0000_0100;
145 }
146
147 if self.times().end == RangeEnd::Open {
149 } else {
151 let end_diff_tag = Tag::min_tag(end_time_diff, TagWidth::two());
152 header_2 |= end_diff_tag.data_at_offset(6);
153 }
154
155 consumer.consume(header_2).await?;
156
157 if (self.subspaces().start == r.subspaces().start)
158 || (r.subspaces().end == self.subspaces().start)
159 {
160 } else {
162 self.subspaces().start.encode(consumer).await?;
163 }
164
165 if self.subspaces().end == RangeEnd::Open
166 || (self.subspaces().end == r.subspaces().start)
167 || (self.subspaces().end == r.subspaces().end)
168 {
169 } else if let RangeEnd::Closed(end_subspace) = &self.subspaces().end {
171 end_subspace.encode(consumer).await?;
172 }
173
174 if is_bitflagged(header_1, 4) {
175 self.paths()
176 .start
177 .relative_encode(consumer, &r.paths().start)
178 .await?;
179 } else if let RangeEnd::Closed(end_path) = &r.paths().end {
180 self.paths()
181 .start
182 .relative_encode(consumer, end_path)
183 .await?;
184 }
185
186 if let RangeEnd::Closed(end_path) = &self.paths().end {
187 if is_bitflagged(header_1, 6) {
188 end_path.relative_encode(consumer, &r.paths().start).await?
189 } else if let RangeEnd::Closed(ref_end_path) = &r.paths().end {
190 end_path.relative_encode(consumer, ref_end_path).await?;
191 }
192 }
193
194 CompactU64(start_time_diff)
195 .relative_encode(consumer, &start_diff_tag.encoding_width())
196 .await?;
197
198 if self.times().end != RangeEnd::Open {
199 let end_diff_tag = Tag::min_tag(end_time_diff, TagWidth::two());
200
201 CompactU64(end_time_diff)
202 .relative_encode(consumer, &end_diff_tag.encoding_width())
203 .await?;
204 }
205
206 Ok(())
207 }
208}
209
210impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
211 RelativeDecodable<Range3d<MCL, MCC, MPL, S>, Blame> for Range3d<MCL, MCC, MPL, S>
212where
213 S: SubspaceId + DecodableCanonic,
214 Blame: From<S::ErrorReason> + From<S::ErrorCanonic>,
215{
216 async fn relative_decode<P>(
222 producer: &mut P,
223 r: &Range3d<MCL, MCC, MPL, S>,
224 ) -> Result<Self, DecodeError<P::Final, P::Error, Blame>>
225 where
226 P: BulkProducer<Item = u8>,
227 Self: Sized,
228 {
229 relative_decode_maybe_canonic::<false, MCL, MCC, MPL, S, P>(producer, r).await
230 }
231}
232
233impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
234 RelativeDecodableCanonic<Range3d<MCL, MCC, MPL, S>, Blame, Blame> for Range3d<MCL, MCC, MPL, S>
235where
236 S: SubspaceId + DecodableCanonic,
237 Blame: From<S::ErrorReason> + From<S::ErrorCanonic>,
238{
239 async fn relative_decode_canonic<P>(
240 producer: &mut P,
241 r: &Range3d<MCL, MCC, MPL, S>,
242 ) -> Result<Self, DecodeError<P::Final, P::Error, Blame>>
243 where
244 P: BulkProducer<Item = u8>,
245 Self: Sized,
246 {
247 relative_decode_maybe_canonic::<true, MCL, MCC, MPL, S, P>(producer, r).await
248 }
249}
250
251impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
252 RelativeEncodableKnownSize<Range3d<MCL, MCC, MPL, S>> for Range3d<MCL, MCC, MPL, S>
253where
254 S: SubspaceId + EncodableKnownSize,
255{
256 fn relative_len_of_encoding(&self, r: &Range3d<MCL, MCC, MPL, S>) -> usize {
257 let start_to_start = self.times().start.abs_diff(r.times().start);
258 let start_to_end = match r.times().end {
259 RangeEnd::Closed(end) => self.times().start.abs_diff(end),
260 RangeEnd::Open => u64::MAX,
261 };
262 let end_to_start = match self.times().end {
263 RangeEnd::Closed(end) => end.abs_diff(r.times().start),
264 RangeEnd::Open => u64::MAX,
265 };
266 let end_to_end = match (&self.times().end, &r.times().end) {
267 (RangeEnd::Closed(self_end), RangeEnd::Closed(ref_end)) => self_end.abs_diff(*ref_end),
268 (RangeEnd::Closed(_), RangeEnd::Open) => u64::MAX,
269 (RangeEnd::Open, RangeEnd::Closed(_)) => u64::MAX,
270 (RangeEnd::Open, RangeEnd::Open) => 0, };
272
273 let start_time_diff = core::cmp::min(start_to_start, start_to_end);
274
275 let end_time_diff = core::cmp::min(end_to_start, end_to_end);
276
277 let subspace_start_len = if (self.subspaces().start == r.subspaces().start)
278 || (r.subspaces().end == self.subspaces().start)
279 {
280 0
281 } else {
282 self.subspaces().start.len_of_encoding()
283 };
284
285 let subspace_end_len = if self.subspaces().end == RangeEnd::Open
286 || (self.subspaces().end == r.subspaces().start)
287 || (self.subspaces().end == r.subspaces().end)
288 {
289 0
291 } else if let RangeEnd::Closed(end_subspace) = &self.subspaces().end {
292 end_subspace.len_of_encoding()
293 } else {
294 0
295 };
296
297 let path_start_rel_to_start = if let RangeEnd::Closed(ref_path_end) = &r.paths().end {
298 let lcp_start_start = self.paths().start.longest_common_prefix(&r.paths().start);
299 let lcp_start_end = self.paths().start.longest_common_prefix(ref_path_end);
300
301 lcp_start_start.component_count() >= lcp_start_end.component_count()
302 } else {
303 true
304 };
305
306 let path_start_len = if path_start_rel_to_start {
307 self.paths()
308 .start
309 .relative_len_of_encoding(&r.paths().start)
310 } else if let RangeEnd::Closed(end_path) = &r.paths().end {
311 self.paths().start.relative_len_of_encoding(end_path)
312 } else {
313 panic!("Tried to encode a path range start relative to an open end")
314 };
315
316 let path_end_rel_to_start = match (&self.paths().end, &r.paths().end) {
317 (RangeEnd::Closed(self_path_end), RangeEnd::Closed(ref_path_end)) => {
318 let lcp_end_start = self_path_end.longest_common_prefix(&r.paths().start);
319 let lcp_end_end = self_path_end.longest_common_prefix(ref_path_end);
320
321 lcp_end_start.component_count() >= lcp_end_end.component_count()
322 }
323 (RangeEnd::Closed(_), RangeEnd::Open) => true,
324 (RangeEnd::Open, RangeEnd::Closed(_)) => false,
325 (RangeEnd::Open, RangeEnd::Open) => false,
326 };
327
328 let path_end_len = if let RangeEnd::Closed(end_path) = &self.paths().end {
329 if path_end_rel_to_start {
330 end_path.relative_len_of_encoding(&r.paths().start)
331 } else if let RangeEnd::Closed(ref_end_path) = &r.paths().end {
332 end_path.relative_len_of_encoding(ref_end_path)
333 } else {
334 0
335 }
336 } else {
337 0
338 };
339
340 let start_diff_tag = Tag::min_tag(start_time_diff, TagWidth::two());
341
342 let start_diff_len =
343 CompactU64(start_time_diff).relative_len_of_encoding(&start_diff_tag.encoding_width());
344
345 let end_diff_len = if self.times().end != RangeEnd::Open {
346 let end_diff_tag = Tag::min_tag(end_time_diff, TagWidth::two());
347
348 CompactU64(end_time_diff).relative_len_of_encoding(&end_diff_tag.encoding_width())
349 } else {
350 0
351 };
352
353 2 + subspace_start_len
354 + subspace_end_len
355 + path_start_len
356 + path_end_len
357 + start_diff_len
358 + end_diff_len
359 }
360}
361
362impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
363 RelativeEncodableSync<Range3d<MCL, MCC, MPL, S>> for Range3d<MCL, MCC, MPL, S>
364where
365 S: SubspaceId + EncodableSync,
366{
367}
368
369impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
370 RelativeDecodableSync<Range3d<MCL, MCC, MPL, S>, Blame> for Range3d<MCL, MCC, MPL, S>
371where
372 S: SubspaceId + DecodableCanonic,
373 Blame: From<S::ErrorReason> + From<S::ErrorCanonic>,
374{
375}
376
377async fn relative_decode_maybe_canonic<
378 const CANONIC: bool,
379 const MCL: usize,
380 const MCC: usize,
381 const MPL: usize,
382 S,
383 P,
384>(
385 producer: &mut P,
386 r: &Range3d<MCL, MCC, MPL, S>,
387) -> Result<Range3d<MCL, MCC, MPL, S>, DecodeError<P::Final, P::Error, Blame>>
388where
389 P: BulkProducer<Item = u8>,
390 S: SubspaceId + DecodableCanonic,
391 Blame: From<S::ErrorReason> + From<S::ErrorCanonic>,
392{
393 let header_1 = producer.produce_item().await?;
394
395 let subspace_start_flags = header_1 & 0b1100_0000;
396 let subspace_end_flags = header_1 & 0b0011_0000;
397 let is_path_start_rel_to_start = is_bitflagged(header_1, 4);
398 let is_path_end_open = is_bitflagged(header_1, 5);
399 let is_path_end_rel_to_start = is_bitflagged(header_1, 6);
400 let is_times_end_open = is_bitflagged(header_1, 7);
401
402 let header_2 = producer.produce_item().await?;
403
404 let is_time_start_rel_to_start = is_bitflagged(header_2, 0);
405 let add_or_subtract_start_time_diff = is_bitflagged(header_2, 1);
406
407 let start_time_diff_tag = Tag::from_raw(header_2, TagWidth::two(), 2);
408 let is_time_end_rel_to_start = is_bitflagged(header_2, 4);
409 let add_or_subtract_end_time_diff = is_bitflagged(header_2, 5);
410 let end_time_diff_tag = Tag::from_raw(header_2, TagWidth::two(), 6);
411
412 let subspace_start = match subspace_start_flags {
414 0b0100_0000 => r.subspaces().start.clone(),
415 0b1000_0000 => match &r.subspaces().end {
416 RangeEnd::Closed(end) => end.clone(),
417 RangeEnd::Open => Err(DecodeError::Other(Blame::TheirFault))?,
418 },
419 0b1100_0000 => {
420 let decoded_subspace = if CANONIC {
421 S::decode_canonic(producer)
422 .await
423 .map_err(DecodeError::map_other_from)?
424 } else {
425 S::decode(producer)
426 .await
427 .map_err(DecodeError::map_other_from)?
428 };
429
430 if decoded_subspace == r.subspaces().start || r.subspaces().end == decoded_subspace {
431 return Err(DecodeError::Other(Blame::TheirFault));
432 }
433
434 decoded_subspace
435 }
436 _ => Err(DecodeError::Other(Blame::TheirFault))?,
438 };
439
440 let subspace_end = match subspace_end_flags {
441 0b0000_0000 => RangeEnd::Open,
442 0b0001_0000 => RangeEnd::Closed(r.subspaces().start.clone()),
443 0b0010_0000 => match &r.subspaces().end {
444 RangeEnd::Closed(end) => RangeEnd::Closed(end.clone()),
445 RangeEnd::Open => Err(DecodeError::Other(Blame::TheirFault))?,
446 },
447 _ => {
449 let decoded_subspace = if CANONIC {
450 RangeEnd::Closed(
451 S::decode_canonic(producer)
452 .await
453 .map_err(DecodeError::map_other_from)?,
454 )
455 } else {
456 RangeEnd::Closed(
457 S::decode(producer)
458 .await
459 .map_err(DecodeError::map_other_from)?,
460 )
461 };
462
463 if decoded_subspace == r.subspaces().start || r.subspaces().end == decoded_subspace {
464 return Err(DecodeError::Other(Blame::TheirFault));
465 }
466
467 decoded_subspace
468 }
469 };
470
471 let path_start = match (is_path_start_rel_to_start, &r.paths().end) {
474 (true, RangeEnd::Closed(_)) => {
475 if CANONIC {
476 Path::relative_decode_canonic(producer, &r.paths().start).await?
477 } else {
478 Path::relative_decode(producer, &r.paths().start).await?
479 }
480 }
481 (true, RangeEnd::Open) => {
482 if CANONIC {
483 Path::relative_decode_canonic(producer, &r.paths().start).await?
484 } else {
485 Path::relative_decode(producer, &r.paths().start).await?
486 }
487 }
488 (false, RangeEnd::Closed(path_end)) => {
489 if CANONIC {
490 Path::relative_decode_canonic(producer, path_end).await?
491 } else {
492 Path::relative_decode(producer, path_end).await?
493 }
494 }
495 (false, RangeEnd::Open) => Err(DecodeError::Other(Blame::TheirFault))?,
496 };
497
498 if CANONIC {
500 match &r.paths().end {
501 RangeEnd::Closed(ref_path_end) => {
502 let lcp_start_start = path_start.longest_common_prefix(&r.paths().start);
503 let lcp_start_end = path_start.longest_common_prefix(ref_path_end);
504
505 let expected_is_start_rel_to_start =
506 lcp_start_start.component_count() >= lcp_start_end.component_count();
507
508 if expected_is_start_rel_to_start != is_path_start_rel_to_start {
509 return Err(DecodeError::Other(Blame::TheirFault));
510 }
511 }
512 RangeEnd::Open => {
513 if !is_path_start_rel_to_start {
514 return Err(DecodeError::Other(Blame::TheirFault));
515 }
516 }
517 }
518 }
519 let path_end = if is_path_end_open {
522 RangeEnd::Open
523 } else if is_path_end_rel_to_start {
524 if CANONIC {
525 RangeEnd::Closed(Path::relative_decode_canonic(producer, &r.paths().start).await?)
526 } else {
527 RangeEnd::Closed(Path::relative_decode(producer, &r.paths().start).await?)
528 }
529 } else {
530 match &r.paths().end {
531 RangeEnd::Closed(end) => {
532 if CANONIC {
533 RangeEnd::Closed(Path::relative_decode_canonic(producer, end).await?)
534 } else {
535 RangeEnd::Closed(Path::relative_decode(producer, end).await?)
536 }
537 }
538 RangeEnd::Open => Err(DecodeError::Other(Blame::TheirFault))?,
539 }
540 };
541
542 if CANONIC {
544 match &path_end {
545 RangeEnd::Closed(p_end) => match &r.paths().end {
546 RangeEnd::Closed(ref_end) => {
547 let lcp_end_start = p_end.longest_common_prefix(&r.paths().start);
548 let lcp_end_end = p_end.longest_common_prefix(ref_end);
549
550 let expected_is_path_end_rel_to_start =
551 lcp_end_start.component_count() >= lcp_end_end.component_count();
552
553 if expected_is_path_end_rel_to_start != is_path_end_rel_to_start {
554 return Err(DecodeError::Other(Blame::TheirFault));
555 }
556 }
557 RangeEnd::Open => {}
558 },
559 RangeEnd::Open => {
560 if is_path_end_rel_to_start {
561 return Err(DecodeError::Other(Blame::TheirFault));
562 }
563 }
564 }
565 }
566 let start_time_diff = if CANONIC {
569 CompactU64::relative_decode_canonic(producer, &start_time_diff_tag)
570 .await
571 .map_err(DecodeError::map_other_from)?
572 .0
573 } else {
574 CompactU64::relative_decode(producer, &start_time_diff_tag)
575 .await
576 .map_err(DecodeError::map_other_from)?
577 .0
578 };
579
580 let time_start = match (is_time_start_rel_to_start, add_or_subtract_start_time_diff) {
581 (true, true) => r.times().start.checked_add(start_time_diff),
582 (true, false) => r.times().start.checked_sub(start_time_diff),
583 (false, true) => match r.times().end {
584 RangeEnd::Closed(ref_end) => ref_end.checked_add(start_time_diff),
585 RangeEnd::Open => Err(DecodeError::Other(Blame::TheirFault))?,
586 },
587 (false, false) => match r.times().end {
588 RangeEnd::Closed(ref_end) => ref_end.checked_sub(start_time_diff),
589 RangeEnd::Open => Err(DecodeError::Other(Blame::TheirFault))?,
590 },
591 }
592 .ok_or(DecodeError::Other(Blame::TheirFault))?;
593
594 if CANONIC {
596 match r.times().end {
597 RangeEnd::Closed(ref_time_end) => {
598 let start_to_start = time_start.abs_diff(r.times().start);
599 let start_to_end = time_start.abs_diff(ref_time_end);
600
601 let expected_is_start_rel_to_start = start_to_start <= start_to_end;
602
603 if expected_is_start_rel_to_start != is_time_start_rel_to_start {
604 return Err(DecodeError::Other(Blame::TheirFault));
605 }
606
607 let expected_add_or_subtract_start_time_diff = is_time_start_rel_to_start
608 && time_start >= r.times().start
609 || !expected_is_start_rel_to_start && time_start >= ref_time_end;
610
611 if expected_add_or_subtract_start_time_diff != add_or_subtract_start_time_diff {
612 return Err(DecodeError::Other(Blame::TheirFault));
613 }
614 }
615 RangeEnd::Open => {
616 if !is_time_start_rel_to_start {
617 return Err(DecodeError::Other(Blame::TheirFault));
618 }
619
620 let expected_add_or_subtract_time_diff = time_start >= r.times().start;
622
623 if expected_add_or_subtract_time_diff != add_or_subtract_start_time_diff {
624 return Err(DecodeError::Other(Blame::TheirFault));
625 }
626 }
627 }
628 }
629 let time_end = if is_times_end_open {
632 if CANONIC {
633 if add_or_subtract_end_time_diff {
634 return Err(DecodeError::Other(Blame::TheirFault));
635 }
636
637 if is_time_end_rel_to_start {
638 return Err(DecodeError::Other(Blame::TheirFault));
639 }
640
641 let end_time_diff_compact_width_flags = 0b0000_0011;
642 if header_2 & end_time_diff_compact_width_flags != 0b0000_0000 {
643 return Err(DecodeError::Other(Blame::TheirFault));
644 }
645 }
646
647 RangeEnd::Open
648 } else {
649 let end_time_diff = if CANONIC {
650 CompactU64::relative_decode_canonic(producer, &end_time_diff_tag)
651 .await
652 .map_err(DecodeError::map_other_from)?
653 .0
654 } else {
655 CompactU64::relative_decode(producer, &end_time_diff_tag)
656 .await
657 .map_err(DecodeError::map_other_from)?
658 .0
659 };
660
661 let time_end = match (is_time_end_rel_to_start, add_or_subtract_end_time_diff) {
662 (true, true) => r
663 .times()
664 .start
665 .checked_add(end_time_diff)
666 .ok_or(DecodeError::Other(Blame::TheirFault))?,
667
668 (true, false) => r
669 .times()
670 .start
671 .checked_sub(end_time_diff)
672 .ok_or(DecodeError::Other(Blame::TheirFault))?,
673
674 (false, true) => match r.times().end {
675 RangeEnd::Closed(ref_end) => ref_end
676 .checked_add(end_time_diff)
677 .ok_or(DecodeError::Other(Blame::TheirFault))?,
678
679 RangeEnd::Open => Err(DecodeError::Other(Blame::TheirFault))?,
680 },
681 (false, false) => match r.times().end {
682 RangeEnd::Closed(ref_end) => ref_end
683 .checked_sub(end_time_diff)
684 .ok_or(DecodeError::Other(Blame::TheirFault))?,
685
686 RangeEnd::Open => Err(DecodeError::Other(Blame::TheirFault))?,
687 },
688 };
689
690 let end_to_start = time_end.abs_diff(r.times().start);
691 let end_to_end = match &r.times().end {
692 RangeEnd::Closed(ref_end) => time_end.abs_diff(*ref_end),
693 RangeEnd::Open => u64::MAX,
694 };
695
696 if CANONIC {
697 let expected_is_time_end_rel_to_start = end_to_start <= end_to_end;
698 if expected_is_time_end_rel_to_start != is_time_end_rel_to_start {
699 return Err(DecodeError::Other(Blame::TheirFault));
700 }
701
702 let expected_end_time_diff = core::cmp::min(end_to_start, end_to_end);
703
704 if expected_end_time_diff != end_time_diff {
705 return Err(DecodeError::Other(Blame::TheirFault));
706 }
707
708 let expected_add_or_subtract_end_time_diff = (is_time_end_rel_to_start
709 && time_end >= r.times().start)
710 || (!is_time_end_rel_to_start && time_end >= r.times().end);
711
712 if expected_add_or_subtract_end_time_diff != add_or_subtract_end_time_diff {
713 return Err(DecodeError::Other(Blame::TheirFault));
714 }
715 }
716
717 RangeEnd::Closed(time_end)
718 };
719
720 Ok(Range3d::new(
721 Range {
722 start: subspace_start,
723 end: subspace_end,
724 },
725 Range {
726 start: path_start,
727 end: path_end,
728 },
729 Range {
730 start: time_start,
731 end: time_end,
732 },
733 ))
734}