1use syncify::syncify;
2use syncify::syncify_replace;
3
4#[syncify(encoding_sync)]
5pub(super) mod encoding {
6 use super::*;
7
8 #[syncify_replace(use ufotofu::sync::{BulkConsumer, BulkProducer};)]
9 use ufotofu::local_nb::{BulkConsumer, BulkProducer};
10
11 use willow_encoding::{is_bitflagged, CompactWidth, DecodeError};
12 #[syncify_replace(use willow_encoding::sync::{Encodable, Decodable, RelativeDecodable, RelativeEncodable};)]
13 use willow_encoding::{Decodable, Encodable, RelativeDecodable, RelativeEncodable};
14
15 #[syncify_replace(use willow_encoding::sync::{decode_max_power, encode_max_power};)]
16 use willow_encoding::{decode_max_power, encode_max_power};
17
18 #[syncify_replace(use willow_encoding::sync::{ decode_compact_width_be, encode_compact_width_be};)]
19 use willow_encoding::{decode_compact_width_be, encode_compact_width_be};
20
21 #[syncify_replace(use willow_encoding::sync::produce_byte;)]
22 use willow_encoding::produce_byte;
23
24 use core::mem::size_of;
25
26 use crate::{
27 entry::Entry,
28 grouping::{Area, AreaSubspace, Range, Range3d, RangeEnd},
29 parameters::{NamespaceId, PayloadDigest, SubspaceId},
30 path::Path,
31 ScratchSpacePathDecoding,
32 };
33
34 impl<const MCL: usize, const MCC: usize, const MPL: usize>
36 RelativeEncodable<Path<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
37 {
38 async fn relative_encode<Consumer>(
42 &self,
43 reference: &Path<MCL, MCC, MPL>,
44 consumer: &mut Consumer,
45 ) -> Result<(), Consumer::Error>
46 where
47 Consumer: BulkConsumer<Item = u8>,
48 {
49 let lcp = self.longest_common_prefix(reference);
50 let lcp_component_count = lcp.get_component_count();
51 encode_max_power(lcp_component_count, MCC, consumer).await?;
52
53 let suffix_component_count = self.get_component_count() - lcp_component_count;
54 encode_max_power(suffix_component_count, MCC, consumer).await?;
55
56 for component in self.suffix_components(lcp_component_count) {
57 encode_max_power(component.len(), MCL, consumer).await?;
58
59 consumer
60 .bulk_consume_full_slice(component.as_ref())
61 .await
62 .map_err(|f| f.reason)?;
63 }
64
65 Ok(())
66 }
67 }
68
69 impl<const MCL: usize, const MCC: usize, const MPL: usize>
70 RelativeDecodable<Path<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
71 {
72 async fn relative_decode<Producer>(
76 reference: &Path<MCL, MCC, MPL>,
77 producer: &mut Producer,
78 ) -> Result<Self, DecodeError<Producer::Error>>
79 where
80 Producer: BulkProducer<Item = u8>,
81 Self: Sized,
82 {
83 let lcp_component_count: usize = decode_max_power(MCC, producer).await?.try_into()?;
84
85 if lcp_component_count == 0 {
86 let decoded = Path::<MCL, MCC, MPL>::decode(producer).await?;
87
88 if lcp_component_count
90 != decoded
91 .longest_common_prefix(reference)
92 .get_component_count()
93 {
94 return Err(DecodeError::InvalidInput);
95 }
96 return Ok(decoded);
99 }
100
101 let prefix = reference
102 .create_prefix(lcp_component_count as usize)
103 .ok_or(DecodeError::InvalidInput)?;
104
105 let mut buf = ScratchSpacePathDecoding::<MCC, MPL>::new();
106
107 let raw_prefix_acc_component_lengths = &prefix.raw_buf()
109 [size_of::<usize>()..size_of::<usize>() * (lcp_component_count + 1)];
110 unsafe {
111 buf.set_many_component_accumulated_lengths_from_ne(
113 raw_prefix_acc_component_lengths,
114 );
115 }
116
117 unsafe {
119 buf.path_data_until_as_mut(lcp_component_count)
121 .copy_from_slice(
122 &reference.raw_buf()[size_of::<usize>()
123 * (reference.get_component_count() + 1)
124 ..size_of::<usize>() * (reference.get_component_count() + 1)
125 + prefix.get_path_length()],
126 );
127 }
128
129 let remaining_component_count: usize =
130 decode_max_power(MCC, producer).await?.try_into()?;
131 let total_component_count = lcp_component_count + remaining_component_count;
132 if total_component_count > MCC {
133 return Err(DecodeError::InvalidInput);
134 }
135
136 let mut accumulated_component_length: usize = prefix.get_path_length(); for i in lcp_component_count..total_component_count {
138 let component_len: usize = decode_max_power(MCL, producer).await?.try_into()?;
139 if component_len > MCL {
140 return Err(DecodeError::InvalidInput);
141 }
142
143 accumulated_component_length += component_len;
144 if accumulated_component_length > MPL {
145 return Err(DecodeError::InvalidInput);
146 }
147
148 buf.set_component_accumulated_length(accumulated_component_length, i);
149
150 producer
152 .bulk_overwrite_full_slice(unsafe {
153 buf.path_data_as_mut(i)
155 })
156 .await?;
157 }
158
159 let decoded = unsafe { buf.to_path(total_component_count) };
160
161 if lcp_component_count
163 != decoded
164 .longest_common_prefix(reference)
165 .get_component_count()
166 {
167 return Err(DecodeError::InvalidInput);
168 }
169 Ok(decoded)
172 }
173 }
174
175 impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
178 RelativeEncodable<Entry<MCL, MCC, MPL, N, S, PD>> for Entry<MCL, MCC, MPL, N, S, PD>
179 where
180 N: NamespaceId + Encodable,
181 S: SubspaceId + Encodable,
182 PD: PayloadDigest + Encodable,
183 {
184 async fn relative_encode<Consumer>(
188 &self,
189 reference: &Entry<MCL, MCC, MPL, N, S, PD>,
190 consumer: &mut Consumer,
191 ) -> Result<(), Consumer::Error>
192 where
193 Consumer: BulkConsumer<Item = u8>,
194 {
195 let time_diff = self.timestamp().abs_diff(reference.timestamp());
196
197 let mut header: u8 = 0b0000_0000;
198
199 if self.namespace_id() != reference.namespace_id() {
200 header |= 0b1000_0000;
201 }
202
203 if self.subspace_id() != reference.subspace_id() {
204 header |= 0b0100_0000;
205 }
206
207 if self.timestamp() > reference.timestamp() {
208 header |= 0b0010_0000;
209 }
210
211 header |= CompactWidth::from_u64(time_diff).bitmask(4);
212
213 header |= CompactWidth::from_u64(self.payload_length()).bitmask(6);
214
215 consumer.consume(header).await?;
216
217 if self.namespace_id() != reference.namespace_id() {
218 self.namespace_id().encode(consumer).await?;
219 }
220
221 if self.subspace_id() != reference.subspace_id() {
222 self.subspace_id().encode(consumer).await?;
223 }
224
225 self.path()
226 .relative_encode(reference.path(), consumer)
227 .await?;
228
229 encode_compact_width_be(time_diff, consumer).await?;
230
231 encode_compact_width_be(self.payload_length(), consumer).await?;
232
233 self.payload_digest().encode(consumer).await?;
234
235 Ok(())
236 }
237 }
238
239 impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
240 RelativeDecodable<Entry<MCL, MCC, MPL, N, S, PD>> for Entry<MCL, MCC, MPL, N, S, PD>
241 where
242 N: NamespaceId + Decodable + std::fmt::Debug,
243 S: SubspaceId + Decodable + std::fmt::Debug,
244 PD: PayloadDigest + Decodable,
245 {
246 async fn relative_decode<Producer>(
250 reference: &Entry<MCL, MCC, MPL, N, S, PD>,
251 producer: &mut Producer,
252 ) -> Result<Entry<MCL, MCC, MPL, N, S, PD>, DecodeError<Producer::Error>>
253 where
254 Producer: BulkProducer<Item = u8>,
255 Self: Sized,
256 {
257 let header = produce_byte(producer).await?;
258
259 if is_bitflagged(header, 3) {
261 return Err(DecodeError::InvalidInput);
262 }
263
264 let is_namespace_encoded = is_bitflagged(header, 0);
265 let is_subspace_encoded = is_bitflagged(header, 1);
266 let add_or_subtract_time_diff = is_bitflagged(header, 2);
267 let compact_width_time_diff = CompactWidth::decode_fixed_width_bitmask(header, 4);
268 let compact_width_payload_length = CompactWidth::decode_fixed_width_bitmask(header, 6);
269
270 let namespace_id = if is_namespace_encoded {
271 N::decode(producer).await?
272 } else {
273 reference.namespace_id().clone()
274 };
275
276 let subspace_id = if is_subspace_encoded {
285 S::decode(producer).await?
286 } else {
287 reference.subspace_id().clone()
288 };
289
290 let path = Path::<MCL, MCC, MPL>::relative_decode(reference.path(), producer).await?;
299
300 let time_diff = decode_compact_width_be(compact_width_time_diff, producer).await?;
301
302 let timestamp = if add_or_subtract_time_diff {
304 reference
305 .timestamp()
306 .checked_add(time_diff)
307 .ok_or(DecodeError::InvalidInput)?
308 } else {
309 reference
310 .timestamp()
311 .checked_sub(time_diff)
312 .ok_or(DecodeError::InvalidInput)?
313 };
314
315 let payload_length =
324 decode_compact_width_be(compact_width_payload_length, producer).await?;
325
326 let payload_digest = PD::decode(producer).await?;
327
328 Ok(Entry::new(
329 namespace_id,
330 subspace_id,
331 path,
332 timestamp,
333 payload_length,
334 payload_digest,
335 ))
336 }
337 }
338
339 impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
340 RelativeEncodable<(N, Area<MCL, MCC, MPL, S>)> for Entry<MCL, MCC, MPL, N, S, PD>
341 where
342 N: NamespaceId + Encodable,
343 S: SubspaceId + Encodable,
344 PD: PayloadDigest + Encodable,
345 {
346 async fn relative_encode<Consumer>(
350 &self,
351 reference: &(N, Area<MCL, MCC, MPL, S>),
352 consumer: &mut Consumer,
353 ) -> Result<(), Consumer::Error>
354 where
355 Consumer: BulkConsumer<Item = u8>,
356 {
357 let (namespace, out) = reference;
358
359 if self.namespace_id() != namespace {
360 panic!("Tried to encode an entry relative to a namespace it does not belong to")
361 }
362
363 if !out.includes_entry(self) {
364 panic!("Tried to encode an entry relative to an area it is not included by")
365 }
366
367 let time_diff = core::cmp::min(
368 self.timestamp() - out.times().start,
369 u64::from(&out.times().end) - self.timestamp(),
370 );
371
372 let mut header = 0b0000_0000;
373
374 if out.subspace().is_any() {
375 header |= 0b1000_0000;
376 }
377
378 if self.timestamp() - out.times().start
379 <= u64::from(&out.times().end) - self.timestamp()
380 {
381 header |= 0b0100_0000;
382 }
383
384 header |= CompactWidth::from_u64(time_diff).bitmask(2);
385 header |= CompactWidth::from_u64(self.payload_length()).bitmask(4);
386
387 consumer.consume(header).await?;
388
389 if out.subspace().is_any() {
390 self.subspace_id().encode(consumer).await?;
391 }
392
393 self.path().relative_encode(out.path(), consumer).await?;
394 encode_compact_width_be(time_diff, consumer).await?;
395 encode_compact_width_be(self.payload_length(), consumer).await?;
396 self.payload_digest().encode(consumer).await?;
397
398 Ok(())
399 }
400 }
401
402 impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
403 RelativeDecodable<(N, Area<MCL, MCC, MPL, S>)> for Entry<MCL, MCC, MPL, N, S, PD>
404 where
405 N: NamespaceId + Decodable,
406 S: SubspaceId + Decodable + std::fmt::Debug,
407 PD: PayloadDigest + Decodable,
408 {
409 async fn relative_decode<Producer>(
413 reference: &(N, Area<MCL, MCC, MPL, S>),
414 producer: &mut Producer,
415 ) -> Result<Self, DecodeError<Producer::Error>>
416 where
417 Producer: BulkProducer<Item = u8>,
418 Self: Sized,
419 {
420 let (namespace, out) = reference;
421
422 let header = produce_byte(producer).await?;
423
424 let is_subspace_encoded = is_bitflagged(header, 0);
425 let add_time_diff_to_start = is_bitflagged(header, 1);
426 let time_diff_compact_width = CompactWidth::decode_fixed_width_bitmask(header, 2);
427 let payload_length_compact_width = CompactWidth::decode_fixed_width_bitmask(header, 4);
428
429 if is_bitflagged(header, 6) || is_bitflagged(header, 7) {
430 return Err(DecodeError::InvalidInput);
431 }
432
433 let subspace_id = if is_subspace_encoded {
434 match &out.subspace() {
435 AreaSubspace::Any => S::decode(producer).await?,
436 AreaSubspace::Id(_) => return Err(DecodeError::InvalidInput),
437 }
438 } else {
439 match &out.subspace() {
440 AreaSubspace::Any => return Err(DecodeError::InvalidInput),
441 AreaSubspace::Id(id) => id.clone(),
442 }
443 };
444
445 let path = Path::relative_decode(out.path(), producer).await?;
446
447 if !path.is_prefixed_by(out.path()) {
448 return Err(DecodeError::InvalidInput);
449 }
450
451 let time_diff = decode_compact_width_be(time_diff_compact_width, producer).await?;
452 let payload_length =
453 decode_compact_width_be(payload_length_compact_width, producer).await?;
454
455 let payload_digest = PD::decode(producer).await?;
456
457 let timestamp = if add_time_diff_to_start {
458 out.times().start.checked_add(time_diff)
459 } else {
460 u64::from(&out.times().end).checked_sub(time_diff)
461 }
462 .ok_or(DecodeError::InvalidInput)?;
463
464 let should_have_added = timestamp.checked_sub(out.times().start)
467 <= u64::from(&out.times().end).checked_sub(timestamp);
468
469 if add_time_diff_to_start != should_have_added {
470 return Err(DecodeError::InvalidInput);
471 }
472 if !out.times().includes(×tamp) {
475 return Err(DecodeError::InvalidInput);
476 }
477
478 Ok(Self::new(
479 namespace.clone(),
480 subspace_id,
481 path,
482 timestamp,
483 payload_length,
484 payload_digest,
485 ))
486 }
487 }
488
489 impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
490 RelativeEncodable<(N, Range3d<MCL, MCC, MPL, S>)> for Entry<MCL, MCC, MPL, N, S, PD>
491 where
492 N: NamespaceId + Encodable,
493 S: SubspaceId + Encodable,
494 PD: PayloadDigest + Encodable,
495 {
496 async fn relative_encode<Consumer>(
500 &self,
501 reference: &(N, Range3d<MCL, MCC, MPL, S>),
502 consumer: &mut Consumer,
503 ) -> Result<(), Consumer::Error>
504 where
505 Consumer: BulkConsumer<Item = u8>,
506 {
507 let (namespace, out) = reference;
508
509 if self.namespace_id() != namespace {
510 panic!("Tried to encode an entry relative to a namespace it does not belong to")
511 }
512
513 if !out.includes_entry(self) {
514 panic!("Tried to encode an entry relative to a 3d range it is not included by")
515 }
516
517 let time_diff = core::cmp::min(
518 self.timestamp().abs_diff(out.times().start),
519 self.timestamp().abs_diff(u64::from(&out.times().end)),
520 );
521
522 let mut header = 0b0000_0000;
523
524 if self.subspace_id() != &out.subspaces().start {
526 header |= 0b1000_0000;
527 }
528
529 let encode_path_relative_to_start = match &out.paths().end {
531 RangeEnd::Closed(end_path) => {
532 let start_lcp = self.path().longest_common_prefix(&out.paths().start);
533 let end_lcp = self.path().longest_common_prefix(end_path);
534
535 start_lcp.get_component_count() >= end_lcp.get_component_count()
536 }
537 RangeEnd::Open => true,
538 };
539
540 if encode_path_relative_to_start {
541 header |= 0b0100_0000;
542 }
543
544 let add_time_diff_with_start =
546 time_diff == self.timestamp().abs_diff(out.times().start);
547
548 if add_time_diff_with_start {
549 header |= 0b0010_0000;
550 }
551
552 header |= CompactWidth::from_u64(time_diff).bitmask(4);
554
555 header |= CompactWidth::from_u64(self.payload_length()).bitmask(6);
557
558 consumer.consume(header).await?;
559
560 if self.subspace_id() != &out.subspaces().start {
561 self.subspace_id().encode(consumer).await?;
562 }
563
564 match &out.paths().end {
566 RangeEnd::Closed(end_path) => {
567 if encode_path_relative_to_start {
568 self.path()
569 .relative_encode(&out.paths().start, consumer)
570 .await?;
571 } else {
572 self.path().relative_encode(end_path, consumer).await?;
573 }
574 }
575 RangeEnd::Open => {
576 self.path()
577 .relative_encode(&out.paths().start, consumer)
578 .await?;
579 }
580 }
581
582 encode_compact_width_be(time_diff, consumer).await?;
583 encode_compact_width_be(self.payload_length(), consumer).await?;
584 self.payload_digest().encode(consumer).await?;
585
586 Ok(())
587 }
588 }
589
590 impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
591 RelativeDecodable<(N, Range3d<MCL, MCC, MPL, S>)> for Entry<MCL, MCC, MPL, N, S, PD>
592 where
593 N: NamespaceId + Decodable,
594 S: SubspaceId + Decodable + std::fmt::Debug,
595 PD: PayloadDigest + Decodable,
596 {
597 async fn relative_decode<Producer>(
601 reference: &(N, Range3d<MCL, MCC, MPL, S>),
602 producer: &mut Producer,
603 ) -> Result<Self, DecodeError<Producer::Error>>
604 where
605 Producer: BulkProducer<Item = u8>,
606 Self: Sized,
607 {
608 let (namespace, out) = reference;
609
610 let header = produce_byte(producer).await?;
611
612 let is_subspace_encoded = is_bitflagged(header, 0);
614
615 let decode_path_relative_to_start = is_bitflagged(header, 1);
617
618 let add_time_diff_with_start = is_bitflagged(header, 2);
620
621 if is_bitflagged(header, 3) {
622 return Err(DecodeError::InvalidInput);
623 }
624
625 let time_diff_compact_width = CompactWidth::decode_fixed_width_bitmask(header, 4);
626 let payload_length_compact_width = CompactWidth::decode_fixed_width_bitmask(header, 6);
627
628 let subspace_id = if is_subspace_encoded {
629 S::decode(producer).await?
630 } else {
631 out.subspaces().start.clone()
632 };
633
634 if subspace_id == out.subspaces().start && is_subspace_encoded {
637 return Err(DecodeError::InvalidInput);
638 }
639 if !out.subspaces().includes(&subspace_id) {
643 return Err(DecodeError::InvalidInput);
644 }
645
646 let path = if decode_path_relative_to_start {
647 Path::relative_decode(&out.paths().start, producer).await?
648 } else {
649 match &out.paths().end {
650 RangeEnd::Closed(end_path) => Path::relative_decode(end_path, producer).await?,
651 RangeEnd::Open => return Err(DecodeError::InvalidInput),
652 }
653 };
654
655 if !out.paths().includes(&path) {
657 return Err(DecodeError::InvalidInput);
658 }
659
660 let should_have_encoded_path_relative_to_start = match &out.paths().end {
663 RangeEnd::Closed(end_path) => {
664 let start_lcp = path.longest_common_prefix(&out.paths().start);
665 let end_lcp = path.longest_common_prefix(end_path);
666
667 start_lcp.get_component_count() >= end_lcp.get_component_count()
668 }
669 RangeEnd::Open => true,
670 };
671
672 if decode_path_relative_to_start != should_have_encoded_path_relative_to_start {
673 return Err(DecodeError::InvalidInput);
674 }
675 let time_diff = decode_compact_width_be(time_diff_compact_width, producer).await?;
678
679 let payload_length =
680 decode_compact_width_be(payload_length_compact_width, producer).await?;
681
682 let payload_digest = PD::decode(producer).await?;
683
684 let timestamp = if add_time_diff_with_start {
685 out.times().start.checked_add(time_diff)
686 } else {
687 match &out.times().end {
688 RangeEnd::Closed(end_time) => end_time.checked_sub(time_diff),
689 RangeEnd::Open => u64::from(&out.times().end).checked_sub(time_diff),
690 }
691 }
692 .ok_or(DecodeError::InvalidInput)?;
693
694 if !out.times().includes(×tamp) {
696 return Err(DecodeError::InvalidInput);
697 }
698
699 let correct_time_diff = core::cmp::min(
702 timestamp.abs_diff(out.times().start),
703 timestamp.abs_diff(u64::from(&out.times().end)),
704 );
705
706 if time_diff != correct_time_diff {
707 return Err(DecodeError::InvalidInput);
708 }
709
710 let should_have_added_to_start = time_diff == timestamp.abs_diff(out.times().start);
712
713 if should_have_added_to_start != add_time_diff_with_start {
714 return Err(DecodeError::InvalidInput);
715 }
716 Ok(Self::new(
719 namespace.clone(),
720 subspace_id,
721 path,
722 timestamp,
723 payload_length,
724 payload_digest,
725 ))
726 }
727 }
728
729 impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
730 RelativeEncodable<Area<MCL, MCC, MPL, S>> for Area<MCL, MCC, MPL, S>
731 where
732 S: SubspaceId + Encodable,
733 {
734 async fn relative_encode<Consumer>(
738 &self,
739 out: &Area<MCL, MCC, MPL, S>,
740 consumer: &mut Consumer,
741 ) -> Result<(), Consumer::Error>
742 where
743 Consumer: BulkConsumer<Item = u8>,
744 {
745 if !out.includes_area(self) {
746 panic!("Tried to encode an area relative to a area it is not included by")
747 }
748
749 let start_diff = core::cmp::min(
750 self.times().start - out.times().start,
751 u64::from(&out.times().end) - self.times().start,
752 );
753
754 let end_diff = core::cmp::min(
755 u64::from(&self.times().end) - out.times().start,
756 u64::from(&out.times().end) - u64::from(&self.times().end),
757 );
758
759 let mut header = 0;
760
761 if self.subspace() != out.subspace() {
762 header |= 0b1000_0000;
763 }
764
765 if self.times().end == RangeEnd::Open {
766 header |= 0b0100_0000;
767 }
768
769 if start_diff == self.times().start - out.times().start {
770 header |= 0b0010_0000;
771 }
772
773 if self.times().end != RangeEnd::Open
774 && end_diff == u64::from(&self.times().end) - out.times().start
775 {
776 header |= 0b0001_0000;
777 }
778
779 header |= CompactWidth::from_u64(start_diff).bitmask(4);
780 header |= CompactWidth::from_u64(end_diff).bitmask(6);
781
782 consumer.consume(header).await?;
783
784 match (&self.subspace(), &out.subspace()) {
785 (AreaSubspace::Any, AreaSubspace::Any) => {} (AreaSubspace::Id(_), AreaSubspace::Id(_)) => {} (AreaSubspace::Id(subspace), AreaSubspace::Any) => {
788 subspace.encode(consumer).await?;
789 }
790 (AreaSubspace::Any, AreaSubspace::Id(_)) => {
791 unreachable!(
792 "We should have already rejected an area not included by another area!"
793 )
794 }
795 }
796
797 self.path().relative_encode(out.path(), consumer).await?;
798
799 encode_compact_width_be(start_diff, consumer).await?;
800
801 if self.times().end != RangeEnd::Open {
802 encode_compact_width_be(end_diff, consumer).await?;
803 }
804
805 Ok(())
806 }
807 }
808
809 impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
810 RelativeDecodable<Area<MCL, MCC, MPL, S>> for Area<MCL, MCC, MPL, S>
811 where
812 S: SubspaceId + Decodable,
813 {
814 async fn relative_decode<Producer>(
818 out: &Area<MCL, MCC, MPL, S>,
819 producer: &mut Producer,
820 ) -> Result<Self, DecodeError<Producer::Error>>
821 where
822 Producer: BulkProducer<Item = u8>,
823 Self: Sized,
824 {
825 let header = produce_byte(producer).await?;
826
827 let is_subspace_encoded = is_bitflagged(header, 0);
829
830 let is_times_end_open = is_bitflagged(header, 1);
832
833 let add_start_diff = is_bitflagged(header, 2);
835
836 let add_end_diff = is_bitflagged(header, 3);
838
839 if add_end_diff && is_times_end_open {
842 return Err(DecodeError::InvalidInput);
843 }
844 let start_diff_compact_width = CompactWidth::decode_fixed_width_bitmask(header, 4);
847 let end_diff_compact_width = CompactWidth::decode_fixed_width_bitmask(header, 6);
848
849 if is_times_end_open && (end_diff_compact_width != CompactWidth::One) {
852 return Err(DecodeError::InvalidInput);
853 }
854 let subspace = if is_subspace_encoded {
857 let id = S::decode(producer).await?;
858 let sub = AreaSubspace::Id(id);
859
860 if &sub == out.subspace() {
863 return Err(DecodeError::InvalidInput);
864 }
865 sub
868 } else {
869 out.subspace().clone()
870 };
871
872 match (&out.subspace(), &subspace) {
874 (AreaSubspace::Any, AreaSubspace::Any) => {}
875 (AreaSubspace::Any, AreaSubspace::Id(_)) => {}
876 (AreaSubspace::Id(_), AreaSubspace::Any) => {
877 return Err(DecodeError::InvalidInput);
878 }
879 (AreaSubspace::Id(a), AreaSubspace::Id(b)) => {
880 if a != b {
881 return Err(DecodeError::InvalidInput);
882 }
883 }
884 }
885
886 let path = Path::relative_decode(out.path(), producer).await?;
887
888 if !path.is_prefixed_by(out.path()) {
890 return Err(DecodeError::InvalidInput);
891 }
892
893 let start_diff = decode_compact_width_be(start_diff_compact_width, producer).await?;
894
895 let start = if add_start_diff {
896 out.times().start.checked_add(start_diff)
897 } else {
898 u64::from(&out.times().end).checked_sub(start_diff)
899 }
900 .ok_or(DecodeError::InvalidInput)?;
901
902 let expected_start_diff = core::cmp::min(
904 start.checked_sub(out.times().start),
905 u64::from(&out.times().end).checked_sub(start),
906 )
907 .ok_or(DecodeError::InvalidInput)?;
908
909 if expected_start_diff != start_diff {
910 return Err(DecodeError::InvalidInput);
911 }
912
913 let should_add_start_diff = start_diff
916 == start
917 .checked_sub(out.times().start)
918 .ok_or(DecodeError::InvalidInput)?;
919
920 if add_start_diff != should_add_start_diff {
921 return Err(DecodeError::InvalidInput);
922 }
923 let end = if is_times_end_open {
926 if add_end_diff {
927 return Err(DecodeError::InvalidInput);
928 }
929
930 RangeEnd::Open
931 } else {
932 let end_diff = decode_compact_width_be(end_diff_compact_width, producer).await?;
933
934 let end = if add_end_diff {
935 out.times().start.checked_add(end_diff)
936 } else {
937 u64::from(&out.times().end).checked_sub(end_diff)
938 }
939 .ok_or(DecodeError::InvalidInput)?;
940
941 let expected_end_diff = core::cmp::min(
943 end.checked_sub(out.times().start),
944 u64::from(&out.times().end).checked_sub(end),
945 )
946 .ok_or(DecodeError::InvalidInput)?;
947
948 if end_diff != expected_end_diff {
949 return Err(DecodeError::InvalidInput);
950 }
951
952 let should_add_end_diff = end_diff
954 == end
955 .checked_sub(out.times().start)
956 .ok_or(DecodeError::InvalidInput)?;
957
958 if add_end_diff != should_add_end_diff {
959 return Err(DecodeError::InvalidInput);
960 }
961 RangeEnd::Closed(end)
964 };
965
966 let times = Range { start, end };
967
968 if !out.times().includes_range(×) {
970 return Err(DecodeError::InvalidInput);
971 }
972
973 Ok(Self::new(subspace, path, times))
974 }
975 }
976
977 impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
978 RelativeEncodable<Range3d<MCL, MCC, MPL, S>> for Range3d<MCL, MCC, MPL, S>
979 where
980 S: SubspaceId + Encodable + std::fmt::Debug,
981 {
982 async fn relative_encode<Consumer>(
986 &self,
987 reference: &Range3d<MCL, MCC, MPL, S>,
988 consumer: &mut Consumer,
989 ) -> Result<(), Consumer::Error>
990 where
991 Consumer: BulkConsumer<Item = u8>,
992 {
993 let start_to_start = self.times().start.abs_diff(reference.times().start);
994 let start_to_end = match reference.times().end {
995 RangeEnd::Closed(end) => self.times().start.abs_diff(end),
996 RangeEnd::Open => u64::MAX,
997 };
998 let end_to_start = match self.times().end {
999 RangeEnd::Closed(end) => end.abs_diff(reference.times().start),
1000 RangeEnd::Open => u64::MAX,
1001 };
1002 let end_to_end = match (&self.times().end, &reference.times().end) {
1003 (RangeEnd::Closed(self_end), RangeEnd::Closed(ref_end)) => {
1004 self_end.abs_diff(*ref_end)
1005 }
1006 (RangeEnd::Closed(_), RangeEnd::Open) => u64::MAX,
1007 (RangeEnd::Open, RangeEnd::Closed(_)) => u64::MAX,
1008 (RangeEnd::Open, RangeEnd::Open) => 0, };
1010
1011 let start_time_diff = core::cmp::min(start_to_start, start_to_end);
1012
1013 let end_time_diff = core::cmp::min(end_to_start, end_to_end);
1014
1015 let mut header_1 = 0b0000_0000;
1016
1017 if self.subspaces().start == reference.subspaces().start {
1019 header_1 |= 0b0100_0000;
1020 } else if reference.subspaces().end == self.subspaces().start {
1021 header_1 |= 0b1000_0000;
1022 } else {
1023 header_1 |= 0b1100_0000;
1024 }
1025
1026 if self.subspaces().end == RangeEnd::Open {
1028 } else if self.subspaces().end == reference.subspaces().start {
1030 header_1 |= 0b0001_0000;
1031 } else if self.subspaces().end == reference.subspaces().end {
1032 header_1 |= 0b0010_0000;
1033 } else if self.subspaces().end != RangeEnd::Open {
1034 header_1 |= 0b0011_0000;
1035 }
1036
1037 if let RangeEnd::Closed(ref_path_end) = &reference.paths().end {
1039 let lcp_start_start = self
1040 .paths()
1041 .start
1042 .longest_common_prefix(&reference.paths().start);
1043 let lcp_start_end = self.paths().start.longest_common_prefix(ref_path_end);
1044
1045 if lcp_start_start.get_component_count() >= lcp_start_end.get_component_count() {
1046 header_1 |= 0b0000_1000;
1047 }
1048 } else {
1049 header_1 |= 0b0000_1000;
1050 }
1051
1052 if self.paths().end == RangeEnd::Open {
1054 header_1 |= 0b0000_0100;
1055 }
1056
1057 match (&self.paths().end, &reference.paths().end) {
1059 (RangeEnd::Closed(self_path_end), RangeEnd::Closed(ref_path_end)) => {
1060 let lcp_end_start =
1061 self_path_end.longest_common_prefix(&reference.paths().start);
1062 let lcp_end_end = self_path_end.longest_common_prefix(ref_path_end);
1063
1064 if lcp_end_start.get_component_count() > lcp_end_end.get_component_count() {
1065 header_1 |= 0b0000_0010;
1066 }
1067 }
1068 (RangeEnd::Closed(_), RangeEnd::Open) => {
1069 header_1 |= 0b0000_0010;
1070 }
1071 (RangeEnd::Open, RangeEnd::Closed(_)) => {}
1072 (RangeEnd::Open, RangeEnd::Open) => {}
1073 }
1074
1075 if self.times().end == RangeEnd::Open {
1077 header_1 |= 0b0000_0001;
1078 }
1079
1080 consumer.consume(header_1).await?;
1081
1082 let mut header_2 = 0b0000_0000;
1083
1084 if start_to_start <= start_to_end {
1086 header_2 |= 0b1000_0000;
1087 }
1088
1089 if is_bitflagged(header_2, 0) && self.times().start >= reference.times().start
1091 || !is_bitflagged(header_2, 0) && self.times().start >= reference.times().end
1092 {
1093 header_2 |= 0b0100_0000;
1094 }
1095
1096 header_2 |= CompactWidth::from_u64(start_time_diff).bitmask(2);
1098
1099 if self.times().end != RangeEnd::Open && end_to_start <= end_to_end {
1101 header_2 |= 0b0000_1000;
1102 }
1103
1104 if self.times().end == RangeEnd::Open {
1106 } else if (is_bitflagged(header_2, 4) && self.times().end >= reference.times().start)
1108 || (!is_bitflagged(header_2, 4) && self.times().end >= reference.times().end)
1109 {
1110 header_2 |= 0b0000_0100;
1111 }
1112
1113 if self.times().end == RangeEnd::Open {
1115 } else {
1117 header_2 |= CompactWidth::from_u64(end_time_diff).bitmask(6);
1118 }
1119
1120 consumer.consume(header_2).await?;
1121
1122 if (self.subspaces().start == reference.subspaces().start)
1123 || (reference.subspaces().end == self.subspaces().start)
1124 {
1125 } else {
1127 self.subspaces().start.encode(consumer).await?;
1128 }
1129
1130 if self.subspaces().end == RangeEnd::Open
1131 || (self.subspaces().end == reference.subspaces().start)
1132 || (self.subspaces().end == reference.subspaces().end)
1133 {
1134 } else if let RangeEnd::Closed(end_subspace) = &self.subspaces().end {
1136 end_subspace.encode(consumer).await?;
1137 }
1138
1139 if is_bitflagged(header_1, 4) {
1140 self.paths()
1141 .start
1142 .relative_encode(&reference.paths().start, consumer)
1143 .await?;
1144 } else if let RangeEnd::Closed(end_path) = &reference.paths().end {
1145 self.paths()
1146 .start
1147 .relative_encode(end_path, consumer)
1148 .await?;
1149 }
1150
1151 if let RangeEnd::Closed(end_path) = &self.paths().end {
1152 if is_bitflagged(header_1, 6) {
1153 end_path
1154 .relative_encode(&reference.paths().start, consumer)
1155 .await?
1156 } else if let RangeEnd::Closed(ref_end_path) = &reference.paths().end {
1157 end_path.relative_encode(ref_end_path, consumer).await?;
1158 }
1159 }
1160
1161 encode_compact_width_be(start_time_diff, consumer).await?;
1162 encode_compact_width_be(end_time_diff, consumer).await?;
1163
1164 Ok(())
1165 }
1166 }
1167
1168 impl<const MCL: usize, const MCC: usize, const MPL: usize, S>
1169 RelativeDecodable<Range3d<MCL, MCC, MPL, S>> for Range3d<MCL, MCC, MPL, S>
1170 where
1171 S: SubspaceId + Decodable + std::fmt::Debug,
1172 {
1173 async fn relative_decode<Producer>(
1177 reference: &Range3d<MCL, MCC, MPL, S>,
1178 producer: &mut Producer,
1179 ) -> Result<Self, DecodeError<Producer::Error>>
1180 where
1181 Producer: BulkProducer<Item = u8>,
1182 Self: Sized,
1183 {
1184 let header_1 = produce_byte(producer).await?;
1185
1186 let subspace_start_flags = header_1 & 0b1100_0000;
1187 let subspace_end_flags = header_1 & 0b0011_0000;
1188 let is_path_start_rel_to_start = is_bitflagged(header_1, 4);
1189 let is_path_end_open = is_bitflagged(header_1, 5);
1190 let is_path_end_rel_to_start = is_bitflagged(header_1, 6);
1191 let is_times_end_open = is_bitflagged(header_1, 7);
1192
1193 let header_2 = produce_byte(producer).await?;
1194
1195 let is_time_start_rel_to_start = is_bitflagged(header_2, 0);
1196 let add_or_subtract_start_time_diff = is_bitflagged(header_2, 1);
1197 let start_time_diff_compact_width =
1198 CompactWidth::decode_fixed_width_bitmask(header_2, 2);
1199 let is_times_end_rel_to_start = is_bitflagged(header_2, 4);
1200 let add_or_subtract_end_time_diff = is_bitflagged(header_2, 5);
1201 let end_time_diff_compact_width = CompactWidth::decode_fixed_width_bitmask(header_2, 6);
1202
1203 let subspace_start = match subspace_start_flags {
1205 0b0100_0000 => reference.subspaces().start.clone(),
1206 0b1000_0000 => match &reference.subspaces().end {
1207 RangeEnd::Closed(end) => end.clone(),
1208 RangeEnd::Open => Err(DecodeError::InvalidInput)?,
1209 },
1210 _ => S::decode(producer).await?,
1212 };
1213
1214 let subspace_end = match subspace_end_flags {
1215 0b0000_0000 => RangeEnd::Open,
1216 0b0001_0000 => RangeEnd::Closed(reference.subspaces().start.clone()),
1217 0b0010_0000 => match &reference.subspaces().end {
1218 RangeEnd::Closed(end) => RangeEnd::Closed(end.clone()),
1219 RangeEnd::Open => Err(DecodeError::InvalidInput)?,
1220 },
1221 _ => RangeEnd::Closed(S::decode(producer).await?),
1223 };
1224
1225 let path_start = match (is_path_start_rel_to_start, &reference.paths().end) {
1226 (true, RangeEnd::Closed(_)) => {
1227 Path::relative_decode(&reference.paths().start, producer).await?
1228 }
1229 (true, RangeEnd::Open) => {
1230 Path::relative_decode(&reference.paths().start, producer).await?
1231 }
1232 (false, RangeEnd::Closed(path_end)) => {
1233 Path::relative_decode(path_end, producer).await?
1234 }
1235 (false, RangeEnd::Open) => Err(DecodeError::InvalidInput)?,
1236 };
1237
1238 let path_end = if is_path_end_open {
1239 RangeEnd::Open
1240 } else if is_path_end_rel_to_start {
1241 RangeEnd::Closed(Path::relative_decode(&reference.paths().start, producer).await?)
1242 } else {
1243 match &reference.paths().end {
1244 RangeEnd::Closed(end) => {
1245 RangeEnd::Closed(Path::relative_decode(end, producer).await?)
1246 }
1247 RangeEnd::Open => Err(DecodeError::InvalidInput)?,
1248 }
1249 };
1250
1251 let start_time_diff =
1252 decode_compact_width_be(start_time_diff_compact_width, producer).await?;
1253
1254 let time_start = match (is_time_start_rel_to_start, add_or_subtract_start_time_diff) {
1255 (true, true) => reference.times().start.checked_add(start_time_diff),
1256 (true, false) => reference.times().start.checked_sub(start_time_diff),
1257 (false, true) => match reference.times().end {
1258 RangeEnd::Closed(ref_end) => ref_end.checked_add(start_time_diff),
1259 RangeEnd::Open => Err(DecodeError::InvalidInput)?,
1260 },
1261 (false, false) => match reference.times().end {
1262 RangeEnd::Closed(ref_end) => ref_end.checked_sub(start_time_diff),
1263 RangeEnd::Open => Err(DecodeError::InvalidInput)?,
1264 },
1265 }
1266 .ok_or(DecodeError::InvalidInput)?;
1267
1268 let end_time_diff =
1269 decode_compact_width_be(end_time_diff_compact_width, producer).await?;
1270
1271 let time_end = if is_times_end_open {
1272 RangeEnd::Open
1273 } else {
1274 match (is_times_end_rel_to_start, add_or_subtract_end_time_diff) {
1275 (true, true) => RangeEnd::Closed(
1276 reference
1277 .times()
1278 .start
1279 .checked_add(end_time_diff)
1280 .ok_or(DecodeError::InvalidInput)?,
1281 ),
1282 (true, false) => RangeEnd::Closed(
1283 reference
1284 .times()
1285 .start
1286 .checked_sub(end_time_diff)
1287 .ok_or(DecodeError::InvalidInput)?,
1288 ),
1289 (false, true) => match reference.times().end {
1290 RangeEnd::Closed(ref_end) => RangeEnd::Closed(
1291 ref_end
1292 .checked_add(end_time_diff)
1293 .ok_or(DecodeError::InvalidInput)?,
1294 ),
1295 RangeEnd::Open => Err(DecodeError::InvalidInput)?,
1296 },
1297 (false, false) => match reference.times().end {
1298 RangeEnd::Closed(ref_end) => RangeEnd::Closed(
1299 ref_end
1300 .checked_sub(end_time_diff)
1301 .ok_or(DecodeError::InvalidInput)?,
1302 ),
1303 RangeEnd::Open => Err(DecodeError::InvalidInput)?,
1304 },
1305 }
1306 };
1307
1308 Ok(Self::new(
1309 Range {
1310 start: subspace_start,
1311 end: subspace_end,
1312 },
1313 Range {
1314 start: path_start,
1315 end: path_end,
1316 },
1317 Range {
1318 start: time_start,
1319 end: time_end,
1320 },
1321 ))
1322 }
1323 }
1324}