use std::fmt;
const RECORD_BITS: u32 = 40;
const ORDINAL_BITS: u32 = 23;
const RECORD_MASK: i64 = (1 << RECORD_BITS) - 1;
pub(crate) const MAX_ORDINAL: u32 = (1 << ORDINAL_BITS) - 1;
pub(crate) const MAX_RECORD_INDEX: u64 = RECORD_MASK as u64 - 1;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct Position {
pub(crate) ordinal: u32,
pub(crate) record: u64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct OffsetOverflow {
what: &'static str,
at: Position,
}
impl fmt::Display for OffsetOverflow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"composite offset overflow: {} exhausted at ordinal {} record {} \
(limits: {} objects per lane, {} records per object)",
self.what,
self.at.ordinal,
self.at.record,
MAX_ORDINAL as u64 + 1,
MAX_RECORD_INDEX + 1,
)
}
}
impl std::error::Error for OffsetOverflow {}
impl Position {
pub(crate) fn encode(self) -> Result<i64, OffsetOverflow> {
if self.ordinal > MAX_ORDINAL {
return Err(OffsetOverflow {
what: "object ordinal space",
at: self,
});
}
if self.record > MAX_RECORD_INDEX + 1 {
return Err(OffsetOverflow {
what: "record index space",
at: self,
});
}
Ok(((self.ordinal as i64) << RECORD_BITS) | self.record as i64)
}
pub(crate) fn decode(offset: i64) -> Position {
debug_assert!(offset >= 0, "composite offsets are non-negative");
Position {
ordinal: (offset >> RECORD_BITS) as u32,
record: (offset & RECORD_MASK) as u64,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
#[test]
fn origin_is_zero_and_roundtrips() {
let origin = Position {
ordinal: 0,
record: 0,
};
assert_eq!(origin.encode().unwrap(), 0);
assert_eq!(Position::decode(0), origin);
}
#[test]
fn watermark_after_last_emittable_record_stays_in_its_object() {
let last = Position {
ordinal: 7,
record: MAX_RECORD_INDEX,
};
let watermark = last.encode().unwrap() + 1;
let decoded = Position::decode(watermark);
assert_eq!(decoded.ordinal, 7, "no carry into the ordinal field");
assert_eq!(decoded.record, MAX_RECORD_INDEX + 1, "reserved index");
}
#[test]
fn out_of_range_fields_refuse_to_encode() {
assert!(
Position {
ordinal: MAX_ORDINAL + 1,
record: 0,
}
.encode()
.is_err()
);
assert!(
Position {
ordinal: 0,
record: MAX_RECORD_INDEX + 2,
}
.encode()
.is_err(),
"one past the reserved watermark index is unencodable"
);
}
#[test]
fn maximum_watermark_is_i64_max() {
let max = Position {
ordinal: MAX_ORDINAL,
record: MAX_RECORD_INDEX + 1,
};
assert_eq!(max.encode().unwrap(), i64::MAX);
}
proptest! {
#[test]
fn encode_decode_roundtrips(
ordinal in 0..=MAX_ORDINAL,
record in 0..=MAX_RECORD_INDEX + 1,
) {
let pos = Position { ordinal, record };
let encoded = pos.encode().unwrap();
prop_assert!(encoded >= 0);
prop_assert_eq!(Position::decode(encoded), pos);
}
#[test]
fn encoding_orders_exactly_like_positions(
a_ord in 0..=MAX_ORDINAL, a_rec in 0..=MAX_RECORD_INDEX + 1,
b_ord in 0..=MAX_ORDINAL, b_rec in 0..=MAX_RECORD_INDEX + 1,
) {
let a = Position { ordinal: a_ord, record: a_rec };
let b = Position { ordinal: b_ord, record: b_rec };
prop_assert_eq!(
a.encode().unwrap().cmp(&b.encode().unwrap()),
a.cmp(&b),
"i64 ordering must match (ordinal, record) ordering"
);
}
#[test]
fn watermark_decode_is_the_inverse_of_plus_one(
ordinal in 0..=MAX_ORDINAL,
record in 0..=MAX_RECORD_INDEX,
) {
let emitted = Position { ordinal, record };
let watermark = Position::decode(emitted.encode().unwrap() + 1);
prop_assert_eq!(watermark.ordinal, ordinal);
prop_assert_eq!(watermark.record, record + 1);
}
#[test]
fn crossing_an_object_boundary_is_strictly_monotonic(
ordinal in 0..MAX_ORDINAL,
record in 0..=MAX_RECORD_INDEX + 1,
) {
let in_prev = Position { ordinal, record };
let next = Position { ordinal: ordinal + 1, record: 0 };
prop_assert!(next.encode().unwrap() > in_prev.encode().unwrap());
}
}
}