#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Cursor(u64);
const PART_SHIFT: u32 = 40;
const PARTS_SHIFT: u32 = 52;
const PART_MASK: u64 = 0xFFF;
const IDX_MASK: u64 = (1 << PART_SHIFT) - 1;
pub const MAX_PARTS: u32 = (PART_MASK as u32 + 1) >> 1;
impl Cursor {
pub const START: Cursor = Cursor(0);
pub const END: Cursor = Cursor(0);
#[inline]
#[must_use]
pub const fn from_raw(raw: u64) -> Cursor {
Cursor(raw)
}
#[inline]
#[must_use]
pub const fn raw(self) -> u64 {
self.0
}
#[inline]
#[must_use]
pub const fn is_end(self) -> bool {
self.0 == 0
}
#[must_use]
pub const fn at(parts: u32, part: u32, idx: u64) -> Cursor {
Cursor(pack(parts, part, (idx + 1) & IDX_MASK))
}
#[must_use]
pub const fn top(parts: u32, part: u32) -> Cursor {
Cursor(pack(parts, part, 0))
}
#[inline]
#[must_use]
pub const fn parts(self) -> u32 {
let p = ((self.0 >> PARTS_SHIFT) & PART_MASK) as u32;
if p == 0 { 1 } else { p }
}
#[inline]
#[must_use]
pub const fn part(self) -> u32 {
((self.0 >> PART_SHIFT) & PART_MASK) as u32
}
#[inline]
#[must_use]
pub const fn idx(self) -> Option<u64> {
let i = self.0 & IDX_MASK;
if i == 0 { None } else { Some(i - 1) }
}
#[must_use]
pub const fn rebase(self, parts_now: u32) -> Cursor {
let was = self.parts();
if was == parts_now || self.is_end() {
return self;
}
if parts_now < was {
return Cursor::top(parts_now, parts_now.saturating_sub(1));
}
Cursor::top(parts_now, self.part() + (parts_now - was))
}
}
const fn pack(parts: u32, part: u32, idx_plus_one: u64) -> u64 {
let parts = if parts > MAX_PARTS {
MAX_PARTS as u64
} else {
parts as u64
};
let part = if part >= MAX_PARTS {
(MAX_PARTS - 1) as u64
} else {
part as u64
};
(parts << PARTS_SHIFT) | (part << PART_SHIFT) | idx_plus_one
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_is_the_start_and_the_end() {
assert!(Cursor::START.is_end());
assert_eq!(Cursor::START, Cursor::END);
assert_eq!(Cursor::START.parts(), 1);
assert_eq!(Cursor::START.part(), 0);
assert_eq!(Cursor::START.idx(), None);
}
#[test]
fn the_three_fields_survive_the_wire() {
let c = Cursor::at(8, 5, 1234);
let back = Cursor::from_raw(c.raw());
assert_eq!(back.parts(), 8);
assert_eq!(back.part(), 5);
assert_eq!(back.idx(), Some(1234));
assert!(!back.is_end());
}
#[test]
fn the_layout_is_the_one_the_spec_names() {
let c = Cursor::at(4, 3, 41);
assert_eq!(c.raw(), (4 << 52) | (3 << 40) | 42);
}
#[test]
fn the_top_of_a_partition_has_no_row_yet() {
let c = Cursor::top(16, 9);
assert_eq!(c.parts(), 16);
assert_eq!(c.part(), 9);
assert_eq!(c.idx(), None);
assert!(!c.is_end(), "the top of a partition is not the end");
}
#[test]
fn growing_the_partitions_does_not_skip_any() {
let stopped = Cursor::at(4, 2, 500);
let now = stopped.rebase(8);
assert_eq!(now.parts(), 8);
assert_eq!(now.part(), 6);
assert_eq!(
now.idx(),
None,
"the split moved the rows, so start at the top"
);
for n in 0..8u32 {
let done = (n & 3) > 2;
assert!(
done || n <= now.part(),
"new partition {n} would be skipped"
);
}
}
#[test]
fn a_cursor_from_the_same_layout_is_left_alone() {
let c = Cursor::at(8, 5, 77);
assert_eq!(c.rebase(8), c);
assert_eq!(Cursor::END.rebase(64), Cursor::END);
}
#[test]
fn a_cursor_from_a_bigger_layout_starts_again_at_the_top() {
let c = Cursor::at(64, 40, 9).rebase(4);
assert_eq!(c.parts(), 4);
assert_eq!(c.part(), 3);
assert_eq!(c.idx(), None);
}
#[test]
fn a_partition_count_past_the_field_is_clamped_and_not_wrapped() {
let c = Cursor::at(MAX_PARTS * 4, MAX_PARTS * 4, 1);
assert!(c.parts() <= MAX_PARTS);
assert!(c.part() < MAX_PARTS);
assert_eq!(c.idx(), Some(1));
}
}