1use crate::{Epochable, Viewable};
35use bytes::{Buf, BufMut};
36use commonware_codec::{varint::UInt, EncodeSize, Error, Read, ReadExt, Write};
37use commonware_utils::sequence::U64;
38use std::{
39 fmt::{self, Display, Formatter},
40 marker::PhantomData,
41 num::NonZeroU64,
42};
43
44#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
49#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
50pub struct Epoch(u64);
51
52impl Epoch {
53 pub const fn zero() -> Self {
55 Self(0)
56 }
57
58 pub const fn new(value: u64) -> Self {
60 Self(value)
61 }
62
63 pub const fn get(self) -> u64 {
65 self.0
66 }
67
68 pub const fn is_zero(self) -> bool {
70 self.0 == 0
71 }
72
73 pub const fn next(self) -> Self {
80 Self(self.0.checked_add(1).expect("epoch overflow"))
81 }
82
83 pub fn previous(self) -> Option<Self> {
89 self.0.checked_sub(1).map(Self)
90 }
91
92 pub const fn saturating_add(self, delta: EpochDelta) -> Self {
94 Self(self.0.saturating_add(delta.0))
95 }
96
97 pub fn checked_sub(self, delta: EpochDelta) -> Option<Self> {
99 self.0.checked_sub(delta.0).map(Self)
100 }
101
102 pub const fn saturating_sub(self, delta: EpochDelta) -> Self {
104 Self(self.0.saturating_sub(delta.0))
105 }
106}
107
108impl Display for Epoch {
109 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
110 write!(f, "{}", self.0)
111 }
112}
113
114impl Read for Epoch {
115 type Cfg = ();
116
117 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
118 let value: u64 = UInt::read(buf)?.into();
119 Ok(Self(value))
120 }
121}
122
123impl Write for Epoch {
124 fn write(&self, buf: &mut impl BufMut) {
125 UInt(self.0).write(buf);
126 }
127}
128
129impl EncodeSize for Epoch {
130 fn encode_size(&self) -> usize {
131 UInt(self.0).encode_size()
132 }
133}
134
135impl From<Epoch> for U64 {
136 fn from(epoch: Epoch) -> Self {
137 Self::from(epoch.get())
138 }
139}
140
141#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
145#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
146pub struct Height(u64);
147
148impl Height {
149 pub const fn zero() -> Self {
151 Self(0)
152 }
153
154 pub const fn new(value: u64) -> Self {
156 Self(value)
157 }
158
159 pub const fn get(self) -> u64 {
161 self.0
162 }
163
164 pub const fn is_zero(self) -> bool {
166 self.0 == 0
167 }
168
169 pub const fn next(self) -> Self {
176 Self(self.0.checked_add(1).expect("height overflow"))
177 }
178
179 pub fn previous(self) -> Option<Self> {
185 self.0.checked_sub(1).map(Self)
186 }
187
188 pub const fn saturating_add(self, delta: HeightDelta) -> Self {
190 Self(self.0.saturating_add(delta.0))
191 }
192
193 pub const fn saturating_sub(self, delta: HeightDelta) -> Self {
195 Self(self.0.saturating_sub(delta.0))
196 }
197
198 pub fn delta_from(self, other: Self) -> Option<HeightDelta> {
200 self.0.checked_sub(other.0).map(HeightDelta::new)
201 }
202
203 pub const fn range(start: Self, end: Self) -> HeightRange {
207 HeightRange {
208 inner: start.get()..end.get(),
209 }
210 }
211}
212
213impl Display for Height {
214 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
215 write!(f, "{}", self.0)
216 }
217}
218
219impl Read for Height {
220 type Cfg = ();
221
222 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
223 let value: u64 = UInt::read(buf)?.into();
224 Ok(Self(value))
225 }
226}
227
228impl Write for Height {
229 fn write(&self, buf: &mut impl BufMut) {
230 UInt(self.0).write(buf);
231 }
232}
233
234impl EncodeSize for Height {
235 fn encode_size(&self) -> usize {
236 UInt(self.0).encode_size()
237 }
238}
239
240impl From<Height> for U64 {
241 fn from(height: Height) -> Self {
242 Self::from(height.get())
243 }
244}
245
246#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
251#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
252pub struct View(u64);
253
254impl View {
255 pub const fn zero() -> Self {
257 Self(0)
258 }
259
260 pub const fn new(value: u64) -> Self {
262 Self(value)
263 }
264
265 pub const fn get(self) -> u64 {
267 self.0
268 }
269
270 pub const fn is_zero(self) -> bool {
272 self.0 == 0
273 }
274
275 pub const fn next(self) -> Self {
282 Self(self.0.checked_add(1).expect("view overflow"))
283 }
284
285 pub fn previous(self) -> Option<Self> {
291 self.0.checked_sub(1).map(Self)
292 }
293
294 pub const fn saturating_add(self, delta: ViewDelta) -> Self {
296 Self(self.0.saturating_add(delta.0))
297 }
298
299 pub const fn saturating_sub(self, delta: ViewDelta) -> Self {
301 Self(self.0.saturating_sub(delta.0))
302 }
303
304 pub const fn range(start: Self, end: Self) -> ViewRange {
308 ViewRange {
309 inner: start.get()..end.get(),
310 }
311 }
312}
313
314impl Display for View {
315 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
316 write!(f, "{}", self.0)
317 }
318}
319
320impl Read for View {
321 type Cfg = ();
322
323 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
324 let value: u64 = UInt::read(buf)?.into();
325 Ok(Self(value))
326 }
327}
328
329impl Write for View {
330 fn write(&self, buf: &mut impl BufMut) {
331 UInt(self.0).write(buf);
332 }
333}
334
335impl EncodeSize for View {
336 fn encode_size(&self) -> usize {
337 UInt(self.0).encode_size()
338 }
339}
340
341impl From<View> for U64 {
342 fn from(view: View) -> Self {
343 Self::from(view.get())
344 }
345}
346
347#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
355pub struct Delta<T>(u64, PhantomData<T>);
356
357impl<T> Delta<T> {
358 pub const fn zero() -> Self {
360 Self(0, PhantomData)
361 }
362
363 pub const fn new(value: u64) -> Self {
365 Self(value, PhantomData)
366 }
367
368 pub const fn get(self) -> u64 {
370 self.0
371 }
372
373 pub const fn is_zero(self) -> bool {
375 self.0 == 0
376 }
377}
378
379impl<T> Display for Delta<T> {
380 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
381 write!(f, "{}", self.0)
382 }
383}
384
385pub type EpochDelta = Delta<Epoch>;
390
391pub type HeightDelta = Delta<Height>;
396
397pub type ViewDelta = Delta<View>;
402
403#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
408#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
409pub struct Round {
410 epoch: Epoch,
411 view: View,
412}
413
414impl Round {
415 pub const fn new(epoch: Epoch, view: View) -> Self {
417 Self { epoch, view }
418 }
419
420 pub const fn zero() -> Self {
422 Self::new(Epoch::zero(), View::zero())
423 }
424
425 pub const fn epoch(self) -> Epoch {
427 self.epoch
428 }
429
430 pub const fn view(self) -> View {
432 self.view
433 }
434}
435
436impl Epochable for Round {
437 fn epoch(&self) -> Epoch {
438 self.epoch
439 }
440}
441
442impl Viewable for Round {
443 fn view(&self) -> View {
444 self.view
445 }
446}
447
448impl From<(Epoch, View)> for Round {
449 fn from((epoch, view): (Epoch, View)) -> Self {
450 Self { epoch, view }
451 }
452}
453
454impl From<Round> for (Epoch, View) {
455 fn from(round: Round) -> Self {
456 (round.epoch, round.view)
457 }
458}
459
460#[derive(Clone, Copy, Debug, PartialEq, Eq)]
464pub enum EpochPhase {
465 Early,
467 Midpoint,
469 Late,
471}
472
473#[derive(Clone, Copy, Debug, PartialEq, Eq)]
475pub struct EpochInfo {
476 epoch: Epoch,
477 height: Height,
478 first: Height,
479 last: Height,
480}
481
482impl EpochInfo {
483 pub const fn new(epoch: Epoch, height: Height, first: Height, last: Height) -> Self {
485 Self {
486 epoch,
487 height,
488 first,
489 last,
490 }
491 }
492
493 pub const fn epoch(&self) -> Epoch {
495 self.epoch
496 }
497
498 pub const fn height(&self) -> Height {
500 self.height
501 }
502
503 pub const fn first(&self) -> Height {
505 self.first
506 }
507
508 pub const fn last(&self) -> Height {
510 self.last
511 }
512
513 pub const fn length(&self) -> HeightDelta {
515 HeightDelta::new(self.last.get() - self.first.get() + 1)
516 }
517
518 pub const fn relative(&self) -> Height {
520 Height::new(self.height.get() - self.first.get())
521 }
522
523 pub const fn phase(&self) -> EpochPhase {
525 let relative = self.relative().get();
526 let midpoint = self.length().get() / 2;
527
528 if relative < midpoint {
529 EpochPhase::Early
530 } else if relative == midpoint {
531 EpochPhase::Midpoint
532 } else {
533 EpochPhase::Late
534 }
535 }
536}
537
538pub trait Epocher: Clone + Send + Sync + 'static {
540 fn containing(&self, height: Height) -> Option<EpochInfo>;
544
545 fn first(&self, epoch: Epoch) -> Option<Height>;
549
550 fn last(&self, epoch: Epoch) -> Option<Height>;
554}
555
556#[derive(Clone, Debug, PartialEq, Eq)]
558pub struct FixedEpocher(u64);
559
560impl FixedEpocher {
561 pub const fn new(length: NonZeroU64) -> Self {
570 Self(length.get())
571 }
572
573 fn bounds(&self, epoch: Epoch) -> Option<(Height, Height)> {
576 let first = epoch.get().checked_mul(self.0)?;
577 let last = first.checked_add(self.0 - 1)?;
578 Some((Height::new(first), Height::new(last)))
579 }
580}
581
582impl Epocher for FixedEpocher {
583 fn containing(&self, height: Height) -> Option<EpochInfo> {
584 let epoch = Epoch::new(height.get() / self.0);
585 let (first, last) = self.bounds(epoch)?;
586 Some(EpochInfo::new(epoch, height, first, last))
587 }
588
589 fn first(&self, epoch: Epoch) -> Option<Height> {
590 self.bounds(epoch).map(|(first, _)| first)
591 }
592
593 fn last(&self, epoch: Epoch) -> Option<Height> {
594 self.bounds(epoch).map(|(_, last)| last)
595 }
596}
597
598impl Read for Round {
599 type Cfg = ();
600
601 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
602 Ok(Self {
603 epoch: Epoch::read(buf)?,
604 view: View::read(buf)?,
605 })
606 }
607}
608
609impl Write for Round {
610 fn write(&self, buf: &mut impl BufMut) {
611 self.epoch.write(buf);
612 self.view.write(buf);
613 }
614}
615
616impl EncodeSize for Round {
617 fn encode_size(&self) -> usize {
618 self.epoch.encode_size() + self.view.encode_size()
619 }
620}
621
622impl Display for Round {
623 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
624 write!(f, "({}, {})", self.epoch, self.view)
625 }
626}
627
628pub struct ViewRange {
632 inner: std::ops::Range<u64>,
633}
634
635impl Iterator for ViewRange {
636 type Item = View;
637
638 fn next(&mut self) -> Option<Self::Item> {
639 self.inner.next().map(View::new)
640 }
641
642 fn size_hint(&self) -> (usize, Option<usize>) {
643 self.inner.size_hint()
644 }
645}
646
647impl DoubleEndedIterator for ViewRange {
648 fn next_back(&mut self) -> Option<Self::Item> {
649 self.inner.next_back().map(View::new)
650 }
651}
652
653impl ExactSizeIterator for ViewRange {
654 fn len(&self) -> usize {
655 self.size_hint().0
656 }
657}
658
659pub struct HeightRange {
663 inner: std::ops::Range<u64>,
664}
665
666impl Iterator for HeightRange {
667 type Item = Height;
668
669 fn next(&mut self) -> Option<Self::Item> {
670 self.inner.next().map(Height::new)
671 }
672
673 fn size_hint(&self) -> (usize, Option<usize>) {
674 self.inner.size_hint()
675 }
676}
677
678impl DoubleEndedIterator for HeightRange {
679 fn next_back(&mut self) -> Option<Self::Item> {
680 self.inner.next_back().map(Height::new)
681 }
682}
683
684impl ExactSizeIterator for HeightRange {
685 fn len(&self) -> usize {
686 self.size_hint().0
687 }
688}
689
690pub use commonware_utils::Participant;
692
693#[cfg(test)]
694mod tests {
695 use super::*;
696 use commonware_codec::{DecodeExt, Encode, EncodeSize};
697 use commonware_utils::NZU64;
698
699 #[test]
700 fn test_epoch_constructors() {
701 assert_eq!(Epoch::zero().get(), 0);
702 assert_eq!(Epoch::new(42).get(), 42);
703 assert_eq!(Epoch::default().get(), 0);
704 }
705
706 #[test]
707 fn test_epoch_is_zero() {
708 assert!(Epoch::zero().is_zero());
709 assert!(Epoch::new(0).is_zero());
710 assert!(!Epoch::new(1).is_zero());
711 assert!(!Epoch::new(100).is_zero());
712 }
713
714 #[test]
715 fn test_epoch_next() {
716 assert_eq!(Epoch::zero().next().get(), 1);
717 assert_eq!(Epoch::new(5).next().get(), 6);
718 assert_eq!(Epoch::new(999).next().get(), 1000);
719 }
720
721 #[test]
722 #[should_panic(expected = "epoch overflow")]
723 fn test_epoch_next_overflow() {
724 Epoch::new(u64::MAX).next();
725 }
726
727 #[test]
728 fn test_epoch_previous() {
729 assert_eq!(Epoch::zero().previous(), None);
730 assert_eq!(Epoch::new(1).previous(), Some(Epoch::zero()));
731 assert_eq!(Epoch::new(5).previous(), Some(Epoch::new(4)));
732 assert_eq!(Epoch::new(1000).previous(), Some(Epoch::new(999)));
733 }
734
735 #[test]
736 fn test_epoch_saturating_add() {
737 assert_eq!(Epoch::zero().saturating_add(EpochDelta::new(5)).get(), 5);
738 assert_eq!(Epoch::new(10).saturating_add(EpochDelta::new(20)).get(), 30);
739 assert_eq!(
740 Epoch::new(u64::MAX)
741 .saturating_add(EpochDelta::new(1))
742 .get(),
743 u64::MAX
744 );
745 assert_eq!(
746 Epoch::new(u64::MAX - 5)
747 .saturating_add(EpochDelta::new(10))
748 .get(),
749 u64::MAX
750 );
751 }
752
753 #[test]
754 fn test_epoch_checked_sub() {
755 assert_eq!(
756 Epoch::new(10).checked_sub(EpochDelta::new(5)),
757 Some(Epoch::new(5))
758 );
759 assert_eq!(
760 Epoch::new(5).checked_sub(EpochDelta::new(5)),
761 Some(Epoch::zero())
762 );
763 assert_eq!(Epoch::new(5).checked_sub(EpochDelta::new(10)), None);
764 assert_eq!(Epoch::zero().checked_sub(EpochDelta::new(1)), None);
765 }
766
767 #[test]
768 fn test_epoch_saturating_sub() {
769 assert_eq!(Epoch::new(10).saturating_sub(EpochDelta::new(5)).get(), 5);
770 assert_eq!(Epoch::new(5).saturating_sub(EpochDelta::new(5)).get(), 0);
771 assert_eq!(Epoch::new(5).saturating_sub(EpochDelta::new(10)).get(), 0);
772 assert_eq!(Epoch::zero().saturating_sub(EpochDelta::new(100)).get(), 0);
773 }
774
775 #[test]
776 fn test_epoch_display() {
777 assert_eq!(format!("{}", Epoch::zero()), "0");
778 assert_eq!(format!("{}", Epoch::new(42)), "42");
779 assert_eq!(format!("{}", Epoch::new(1000)), "1000");
780 }
781
782 #[test]
783 fn test_epoch_ordering() {
784 assert!(Epoch::zero() < Epoch::new(1));
785 assert!(Epoch::new(5) < Epoch::new(10));
786 assert!(Epoch::new(10) > Epoch::new(5));
787 assert_eq!(Epoch::new(42), Epoch::new(42));
788 }
789
790 #[test]
791 fn test_epoch_encode_decode() {
792 let cases = vec![0u64, 1, 127, 128, 255, 256, u64::MAX];
793 for value in cases {
794 let epoch = Epoch::new(value);
795 let encoded = epoch.encode();
796 assert_eq!(encoded.len(), epoch.encode_size());
797 let decoded = Epoch::decode(encoded).unwrap();
798 assert_eq!(epoch, decoded);
799 }
800 }
801
802 #[test]
803 fn test_height_constructors() {
804 assert_eq!(Height::zero().get(), 0);
805 assert_eq!(Height::new(42).get(), 42);
806 assert_eq!(Height::new(100).get(), 100);
807 assert_eq!(Height::default().get(), 0);
808 }
809
810 #[test]
811 fn test_height_is_zero() {
812 assert!(Height::zero().is_zero());
813 assert!(Height::new(0).is_zero());
814 assert!(!Height::new(1).is_zero());
815 assert!(!Height::new(100).is_zero());
816 }
817
818 #[test]
819 fn test_height_next() {
820 assert_eq!(Height::zero().next().get(), 1);
821 assert_eq!(Height::new(5).next().get(), 6);
822 assert_eq!(Height::new(999).next().get(), 1000);
823 }
824
825 #[test]
826 #[should_panic(expected = "height overflow")]
827 fn test_height_next_overflow() {
828 Height::new(u64::MAX).next();
829 }
830
831 #[test]
832 fn test_height_previous() {
833 assert_eq!(Height::zero().previous(), None);
834 assert_eq!(Height::new(1).previous(), Some(Height::zero()));
835 assert_eq!(Height::new(5).previous(), Some(Height::new(4)));
836 assert_eq!(Height::new(1000).previous(), Some(Height::new(999)));
837 }
838
839 #[test]
840 fn test_height_saturating_add() {
841 let delta5 = HeightDelta::new(5);
842 let delta100 = HeightDelta::new(100);
843 assert_eq!(Height::zero().saturating_add(delta5).get(), 5);
844 assert_eq!(Height::new(10).saturating_add(delta100).get(), 110);
845 assert_eq!(
846 Height::new(u64::MAX)
847 .saturating_add(HeightDelta::new(1))
848 .get(),
849 u64::MAX
850 );
851 }
852
853 #[test]
854 fn test_height_saturating_sub() {
855 let delta5 = HeightDelta::new(5);
856 let delta100 = HeightDelta::new(100);
857 assert_eq!(Height::new(10).saturating_sub(delta5).get(), 5);
858 assert_eq!(Height::new(5).saturating_sub(delta5).get(), 0);
859 assert_eq!(Height::new(5).saturating_sub(delta100).get(), 0);
860 assert_eq!(Height::zero().saturating_sub(delta100).get(), 0);
861 }
862
863 #[test]
864 fn test_height_display() {
865 assert_eq!(format!("{}", Height::zero()), "0");
866 assert_eq!(format!("{}", Height::new(42)), "42");
867 assert_eq!(format!("{}", Height::new(1000)), "1000");
868 }
869
870 #[test]
871 fn test_height_ordering() {
872 assert!(Height::zero() < Height::new(1));
873 assert!(Height::new(5) < Height::new(10));
874 assert!(Height::new(10) > Height::new(5));
875 assert_eq!(Height::new(42), Height::new(42));
876 }
877
878 #[test]
879 fn test_height_encode_decode() {
880 let cases = vec![0u64, 1, 127, 128, 255, 256, u64::MAX];
881 for value in cases {
882 let height = Height::new(value);
883 let encoded = height.encode();
884 assert_eq!(encoded.len(), height.encode_size());
885 let decoded = Height::decode(encoded).unwrap();
886 assert_eq!(height, decoded);
887 }
888 }
889
890 #[test]
891 fn test_height_delta_from() {
892 assert_eq!(
893 Height::new(10).delta_from(Height::new(3)),
894 Some(HeightDelta::new(7))
895 );
896 assert_eq!(
897 Height::new(5).delta_from(Height::new(5)),
898 Some(HeightDelta::zero())
899 );
900 assert_eq!(Height::new(3).delta_from(Height::new(10)), None);
901 assert_eq!(Height::zero().delta_from(Height::new(1)), None);
902 }
903
904 #[test]
905 fn height_range_iterates() {
906 let collected: Vec<_> = Height::range(Height::new(3), Height::new(6))
907 .map(Height::get)
908 .collect();
909 assert_eq!(collected, vec![3, 4, 5]);
910 }
911
912 #[test]
913 fn height_range_empty() {
914 let collected: Vec<_> = Height::range(Height::new(5), Height::new(5)).collect();
915 assert_eq!(collected, vec![]);
916
917 let collected: Vec<_> = Height::range(Height::new(10), Height::new(5)).collect();
918 assert_eq!(collected, vec![]);
919 }
920
921 #[test]
922 fn height_range_single() {
923 let collected: Vec<_> = Height::range(Height::new(5), Height::new(6))
924 .map(Height::get)
925 .collect();
926 assert_eq!(collected, vec![5]);
927 }
928
929 #[test]
930 fn height_range_size_hint() {
931 let range = Height::range(Height::new(3), Height::new(10));
932 assert_eq!(range.size_hint(), (7, Some(7)));
933 assert_eq!(range.len(), 7);
934
935 let empty = Height::range(Height::new(5), Height::new(5));
936 assert_eq!(empty.size_hint(), (0, Some(0)));
937 assert_eq!(empty.len(), 0);
938 }
939
940 #[test]
941 fn height_range_rev() {
942 let collected: Vec<_> = Height::range(Height::new(3), Height::new(7))
943 .rev()
944 .map(Height::get)
945 .collect();
946 assert_eq!(collected, vec![6, 5, 4, 3]);
947 }
948
949 #[test]
950 fn height_range_double_ended() {
951 let mut range = Height::range(Height::new(5), Height::new(10));
952 assert_eq!(range.next(), Some(Height::new(5)));
953 assert_eq!(range.next_back(), Some(Height::new(9)));
954 assert_eq!(range.next(), Some(Height::new(6)));
955 assert_eq!(range.next_back(), Some(Height::new(8)));
956 assert_eq!(range.len(), 1);
957 assert_eq!(range.next(), Some(Height::new(7)));
958 assert_eq!(range.next(), None);
959 assert_eq!(range.next_back(), None);
960 }
961
962 #[test]
963 fn test_view_constructors() {
964 assert_eq!(View::zero().get(), 0);
965 assert_eq!(View::new(42).get(), 42);
966 assert_eq!(View::new(100).get(), 100);
967 assert_eq!(View::default().get(), 0);
968 }
969
970 #[test]
971 fn test_view_is_zero() {
972 assert!(View::zero().is_zero());
973 assert!(View::new(0).is_zero());
974 assert!(!View::new(1).is_zero());
975 assert!(!View::new(100).is_zero());
976 }
977
978 #[test]
979 fn test_view_next() {
980 assert_eq!(View::zero().next().get(), 1);
981 assert_eq!(View::new(5).next().get(), 6);
982 assert_eq!(View::new(999).next().get(), 1000);
983 }
984
985 #[test]
986 #[should_panic(expected = "view overflow")]
987 fn test_view_next_overflow() {
988 View::new(u64::MAX).next();
989 }
990
991 #[test]
992 fn test_view_previous() {
993 assert_eq!(View::zero().previous(), None);
994 assert_eq!(View::new(1).previous(), Some(View::zero()));
995 assert_eq!(View::new(5).previous(), Some(View::new(4)));
996 assert_eq!(View::new(1000).previous(), Some(View::new(999)));
997 }
998
999 #[test]
1000 fn test_view_saturating_add() {
1001 let delta5 = ViewDelta::new(5);
1002 let delta100 = ViewDelta::new(100);
1003 assert_eq!(View::zero().saturating_add(delta5).get(), 5);
1004 assert_eq!(View::new(10).saturating_add(delta100).get(), 110);
1005 assert_eq!(
1006 View::new(u64::MAX).saturating_add(ViewDelta::new(1)).get(),
1007 u64::MAX
1008 );
1009 }
1010
1011 #[test]
1012 fn test_view_saturating_sub() {
1013 let delta5 = ViewDelta::new(5);
1014 let delta100 = ViewDelta::new(100);
1015 assert_eq!(View::new(10).saturating_sub(delta5).get(), 5);
1016 assert_eq!(View::new(5).saturating_sub(delta5).get(), 0);
1017 assert_eq!(View::new(5).saturating_sub(delta100).get(), 0);
1018 assert_eq!(View::zero().saturating_sub(delta100).get(), 0);
1019 }
1020
1021 #[test]
1022 fn test_view_display() {
1023 assert_eq!(format!("{}", View::zero()), "0");
1024 assert_eq!(format!("{}", View::new(42)), "42");
1025 assert_eq!(format!("{}", View::new(1000)), "1000");
1026 }
1027
1028 #[test]
1029 fn test_view_ordering() {
1030 assert!(View::zero() < View::new(1));
1031 assert!(View::new(5) < View::new(10));
1032 assert!(View::new(10) > View::new(5));
1033 assert_eq!(View::new(42), View::new(42));
1034 }
1035
1036 #[test]
1037 fn test_view_encode_decode() {
1038 let cases = vec![0u64, 1, 127, 128, 255, 256, u64::MAX];
1039 for value in cases {
1040 let view = View::new(value);
1041 let encoded = view.encode();
1042 assert_eq!(encoded.len(), view.encode_size());
1043 let decoded = View::decode(encoded).unwrap();
1044 assert_eq!(view, decoded);
1045 }
1046 }
1047
1048 #[test]
1049 fn test_view_delta_constructors() {
1050 assert_eq!(ViewDelta::zero().get(), 0);
1051 assert_eq!(ViewDelta::new(42).get(), 42);
1052 assert_eq!(ViewDelta::new(100).get(), 100);
1053 assert_eq!(ViewDelta::default().get(), 0);
1054 }
1055
1056 #[test]
1057 fn test_view_delta_is_zero() {
1058 assert!(ViewDelta::zero().is_zero());
1059 assert!(ViewDelta::new(0).is_zero());
1060 assert!(!ViewDelta::new(1).is_zero());
1061 assert!(!ViewDelta::new(100).is_zero());
1062 }
1063
1064 #[test]
1065 fn test_view_delta_display() {
1066 assert_eq!(format!("{}", ViewDelta::zero()), "0");
1067 assert_eq!(format!("{}", ViewDelta::new(42)), "42");
1068 assert_eq!(format!("{}", ViewDelta::new(1000)), "1000");
1069 }
1070
1071 #[test]
1072 fn test_view_delta_ordering() {
1073 assert!(ViewDelta::zero() < ViewDelta::new(1));
1074 assert!(ViewDelta::new(5) < ViewDelta::new(10));
1075 assert!(ViewDelta::new(10) > ViewDelta::new(5));
1076 assert_eq!(ViewDelta::new(42), ViewDelta::new(42));
1077 }
1078
1079 #[test]
1080 fn test_round_cmp() {
1081 assert!(Round::new(Epoch::new(1), View::new(2)) < Round::new(Epoch::new(1), View::new(3)));
1082 assert!(Round::new(Epoch::new(1), View::new(2)) < Round::new(Epoch::new(2), View::new(1)));
1083 }
1084
1085 #[test]
1086 fn test_round_encode_decode_roundtrip() {
1087 let r: Round = (Epoch::new(42), View::new(1_000_000)).into();
1088 let encoded = r.encode();
1089 assert_eq!(encoded.len(), r.encode_size());
1090 let decoded = Round::decode(encoded).unwrap();
1091 assert_eq!(r, decoded);
1092 }
1093
1094 #[test]
1095 fn test_round_conversions() {
1096 let r: Round = (Epoch::new(5), View::new(6)).into();
1097 assert_eq!(r.epoch(), Epoch::new(5));
1098 assert_eq!(r.view(), View::new(6));
1099 let tuple: (Epoch, View) = r.into();
1100 assert_eq!(tuple, (Epoch::new(5), View::new(6)));
1101 }
1102
1103 #[test]
1104 fn test_round_new() {
1105 let r = Round::new(Epoch::new(10), View::new(20));
1106 assert_eq!(r.epoch(), Epoch::new(10));
1107 assert_eq!(r.view(), View::new(20));
1108
1109 let r2 = Round::new(Epoch::new(5), View::new(15));
1110 assert_eq!(r2.epoch(), Epoch::new(5));
1111 assert_eq!(r2.view(), View::new(15));
1112 }
1113
1114 #[test]
1115 fn test_round_display() {
1116 let r = Round::new(Epoch::new(5), View::new(100));
1117 assert_eq!(format!("{r}"), "(5, 100)");
1118 }
1119
1120 #[test]
1121 fn view_range_iterates() {
1122 let collected: Vec<_> = View::range(View::new(3), View::new(6))
1123 .map(View::get)
1124 .collect();
1125 assert_eq!(collected, vec![3, 4, 5]);
1126 }
1127
1128 #[test]
1129 fn view_range_empty() {
1130 let collected: Vec<_> = View::range(View::new(5), View::new(5)).collect();
1131 assert_eq!(collected, vec![]);
1132
1133 let collected: Vec<_> = View::range(View::new(10), View::new(5)).collect();
1134 assert_eq!(collected, vec![]);
1135 }
1136
1137 #[test]
1138 fn view_range_single() {
1139 let collected: Vec<_> = View::range(View::new(5), View::new(6))
1140 .map(View::get)
1141 .collect();
1142 assert_eq!(collected, vec![5]);
1143 }
1144
1145 #[test]
1146 fn view_range_size_hint() {
1147 let range = View::range(View::new(3), View::new(10));
1148 assert_eq!(range.size_hint(), (7, Some(7)));
1149 assert_eq!(range.len(), 7);
1150
1151 let empty = View::range(View::new(5), View::new(5));
1152 assert_eq!(empty.size_hint(), (0, Some(0)));
1153 assert_eq!(empty.len(), 0);
1154 }
1155
1156 #[test]
1157 fn view_range_collect() {
1158 let views: Vec<View> = View::range(View::new(0), View::new(3)).collect();
1159 assert_eq!(views, vec![View::zero(), View::new(1), View::new(2)]);
1160 }
1161
1162 #[test]
1163 fn view_range_iterator_next() {
1164 let mut range = View::range(View::new(5), View::new(8));
1165 assert_eq!(range.next(), Some(View::new(5)));
1166 assert_eq!(range.next(), Some(View::new(6)));
1167 assert_eq!(range.next(), Some(View::new(7)));
1168 assert_eq!(range.next(), None);
1169 assert_eq!(range.next(), None); }
1171
1172 #[test]
1173 fn view_range_exact_size_iterator() {
1174 let range = View::range(View::new(10), View::new(15));
1175 assert_eq!(range.len(), 5);
1176 assert_eq!(range.size_hint(), (5, Some(5)));
1177
1178 let mut range = View::range(View::new(10), View::new(15));
1179 assert_eq!(range.len(), 5);
1180 range.next();
1181 assert_eq!(range.len(), 4);
1182 range.next();
1183 assert_eq!(range.len(), 3);
1184 }
1185
1186 #[test]
1187 fn view_range_rev() {
1188 let collected: Vec<_> = View::range(View::new(3), View::new(7))
1190 .rev()
1191 .map(View::get)
1192 .collect();
1193 assert_eq!(collected, vec![6, 5, 4, 3]);
1194 }
1195
1196 #[test]
1197 fn view_range_double_ended() {
1198 let mut range = View::range(View::new(5), View::new(10));
1200 assert_eq!(range.next(), Some(View::new(5)));
1201 assert_eq!(range.next_back(), Some(View::new(9)));
1202 assert_eq!(range.next(), Some(View::new(6)));
1203 assert_eq!(range.next_back(), Some(View::new(8)));
1204 assert_eq!(range.len(), 1);
1205 assert_eq!(range.next(), Some(View::new(7)));
1206 assert_eq!(range.next(), None);
1207 assert_eq!(range.next_back(), None);
1208 }
1209
1210 #[test]
1211 fn test_fixed_epoch_strategy() {
1212 let epocher = FixedEpocher::new(NZU64!(100));
1213
1214 let bounds = epocher.containing(Height::zero()).unwrap();
1216 assert_eq!(bounds.epoch(), Epoch::new(0));
1217 assert_eq!(bounds.first(), Height::zero());
1218 assert_eq!(bounds.last(), Height::new(99));
1219 assert_eq!(bounds.length(), HeightDelta::new(100));
1220
1221 let bounds = epocher.containing(Height::new(99)).unwrap();
1222 assert_eq!(bounds.epoch(), Epoch::new(0));
1223
1224 let bounds = epocher.containing(Height::new(100)).unwrap();
1225 assert_eq!(bounds.epoch(), Epoch::new(1));
1226 assert_eq!(bounds.first(), Height::new(100));
1227 assert_eq!(bounds.last(), Height::new(199));
1228
1229 assert_eq!(epocher.first(Epoch::new(0)), Some(Height::zero()));
1231 assert_eq!(epocher.last(Epoch::new(0)), Some(Height::new(99)));
1232 assert_eq!(epocher.first(Epoch::new(1)), Some(Height::new(100)));
1233 assert_eq!(epocher.last(Epoch::new(1)), Some(Height::new(199)));
1234 assert_eq!(epocher.first(Epoch::new(5)), Some(Height::new(500)));
1235 assert_eq!(epocher.last(Epoch::new(5)), Some(Height::new(599)));
1236 }
1237
1238 #[test]
1239 fn test_epoch_bounds_relative() {
1240 let epocher = FixedEpocher::new(NZU64!(100));
1241
1242 assert_eq!(
1244 epocher.containing(Height::zero()).unwrap().relative(),
1245 Height::zero()
1246 );
1247 assert_eq!(
1248 epocher.containing(Height::new(50)).unwrap().relative(),
1249 Height::new(50)
1250 );
1251 assert_eq!(
1252 epocher.containing(Height::new(99)).unwrap().relative(),
1253 Height::new(99)
1254 );
1255
1256 assert_eq!(
1258 epocher.containing(Height::new(100)).unwrap().relative(),
1259 Height::zero()
1260 );
1261 assert_eq!(
1262 epocher.containing(Height::new(150)).unwrap().relative(),
1263 Height::new(50)
1264 );
1265 assert_eq!(
1266 epocher.containing(Height::new(199)).unwrap().relative(),
1267 Height::new(99)
1268 );
1269
1270 assert_eq!(
1272 epocher.containing(Height::new(500)).unwrap().relative(),
1273 Height::zero()
1274 );
1275 assert_eq!(
1276 epocher.containing(Height::new(567)).unwrap().relative(),
1277 Height::new(67)
1278 );
1279 assert_eq!(
1280 epocher.containing(Height::new(599)).unwrap().relative(),
1281 Height::new(99)
1282 );
1283 }
1284
1285 #[test]
1286 fn test_epoch_bounds_phase() {
1287 let epocher = FixedEpocher::new(NZU64!(30));
1289
1290 assert_eq!(
1292 epocher.containing(Height::zero()).unwrap().phase(),
1293 EpochPhase::Early
1294 );
1295 assert_eq!(
1296 epocher.containing(Height::new(14)).unwrap().phase(),
1297 EpochPhase::Early
1298 );
1299
1300 assert_eq!(
1302 epocher.containing(Height::new(15)).unwrap().phase(),
1303 EpochPhase::Midpoint
1304 );
1305
1306 assert_eq!(
1308 epocher.containing(Height::new(16)).unwrap().phase(),
1309 EpochPhase::Late
1310 );
1311 assert_eq!(
1312 epocher.containing(Height::new(29)).unwrap().phase(),
1313 EpochPhase::Late
1314 );
1315
1316 assert_eq!(
1318 epocher.containing(Height::new(30)).unwrap().phase(),
1319 EpochPhase::Early
1320 );
1321 assert_eq!(
1322 epocher.containing(Height::new(44)).unwrap().phase(),
1323 EpochPhase::Early
1324 );
1325 assert_eq!(
1326 epocher.containing(Height::new(45)).unwrap().phase(),
1327 EpochPhase::Midpoint
1328 );
1329 assert_eq!(
1330 epocher.containing(Height::new(46)).unwrap().phase(),
1331 EpochPhase::Late
1332 );
1333
1334 let epocher = FixedEpocher::new(NZU64!(10));
1336 assert_eq!(
1337 epocher.containing(Height::zero()).unwrap().phase(),
1338 EpochPhase::Early
1339 );
1340 assert_eq!(
1341 epocher.containing(Height::new(4)).unwrap().phase(),
1342 EpochPhase::Early
1343 );
1344 assert_eq!(
1345 epocher.containing(Height::new(5)).unwrap().phase(),
1346 EpochPhase::Midpoint
1347 );
1348 assert_eq!(
1349 epocher.containing(Height::new(6)).unwrap().phase(),
1350 EpochPhase::Late
1351 );
1352 assert_eq!(
1353 epocher.containing(Height::new(9)).unwrap().phase(),
1354 EpochPhase::Late
1355 );
1356
1357 let epocher = FixedEpocher::new(NZU64!(11));
1359 assert_eq!(
1360 epocher.containing(Height::zero()).unwrap().phase(),
1361 EpochPhase::Early
1362 );
1363 assert_eq!(
1364 epocher.containing(Height::new(4)).unwrap().phase(),
1365 EpochPhase::Early
1366 );
1367 assert_eq!(
1368 epocher.containing(Height::new(5)).unwrap().phase(),
1369 EpochPhase::Midpoint
1370 );
1371 assert_eq!(
1372 epocher.containing(Height::new(6)).unwrap().phase(),
1373 EpochPhase::Late
1374 );
1375 assert_eq!(
1376 epocher.containing(Height::new(10)).unwrap().phase(),
1377 EpochPhase::Late
1378 );
1379 }
1380
1381 #[test]
1382 fn test_fixed_epocher_overflow() {
1383 let epocher = FixedEpocher::new(NZU64!(100));
1385
1386 let last_valid_first = Height::new(18446744073709551500u64);
1395 let last_valid_last = Height::new(18446744073709551599u64);
1396
1397 let result = epocher.containing(last_valid_first);
1398 assert!(result.is_some());
1399 let bounds = result.unwrap();
1400 assert_eq!(bounds.first(), last_valid_first);
1401 assert_eq!(bounds.last(), last_valid_last);
1402
1403 let result = epocher.containing(last_valid_last);
1404 assert!(result.is_some());
1405 assert_eq!(result.unwrap().last(), last_valid_last);
1406
1407 let overflow_height = last_valid_last.next();
1409 assert!(epocher.containing(overflow_height).is_none());
1410
1411 assert!(epocher.containing(Height::new(u64::MAX)).is_none());
1413
1414 let epocher = FixedEpocher::new(NZU64!(2));
1416
1417 let result = epocher.containing(Height::new(u64::MAX - 1));
1419 assert!(result.is_some());
1420 assert_eq!(result.unwrap().last(), Height::new(u64::MAX));
1421
1422 let result = epocher.containing(Height::new(u64::MAX));
1425 assert!(result.is_some());
1426 assert_eq!(result.unwrap().last(), Height::new(u64::MAX));
1427
1428 let epocher = FixedEpocher::new(NZU64!(1));
1430 let result = epocher.containing(Height::new(u64::MAX));
1431 assert!(result.is_some());
1432 assert_eq!(result.unwrap().last(), Height::new(u64::MAX));
1433
1434 let epocher = FixedEpocher::new(NZU64!(u64::MAX));
1436 assert!(epocher.containing(Height::new(u64::MAX)).is_none());
1437
1438 let epocher = FixedEpocher::new(NZU64!(100));
1440 let last_valid_epoch = Epoch::new(184467440737095515);
1441 let first_invalid_epoch = Epoch::new(184467440737095516);
1442
1443 assert!(epocher.first(last_valid_epoch).is_some());
1445 assert!(epocher.last(last_valid_epoch).is_some());
1446 let first = epocher.first(last_valid_epoch).unwrap();
1447 assert!(epocher.containing(first).is_some());
1448 assert_eq!(
1449 epocher.containing(first).unwrap().last(),
1450 epocher.last(last_valid_epoch).unwrap()
1451 );
1452
1453 assert!(epocher.first(first_invalid_epoch).is_none());
1455 assert!(epocher.last(first_invalid_epoch).is_none());
1456 assert!(epocher.containing(last_valid_last.next()).is_none());
1457 }
1458
1459 #[cfg(feature = "arbitrary")]
1460 mod conformance {
1461 use super::*;
1462 use commonware_codec::conformance::CodecConformance;
1463
1464 commonware_conformance::conformance_tests! {
1465 CodecConformance<Epoch>,
1466 CodecConformance<Height>,
1467 CodecConformance<View>,
1468 CodecConformance<Round>,
1469 }
1470 }
1471}