use bincode::{
de::{BorrowDecoder, Decoder},
enc::Encoder,
error::{DecodeError, EncodeError},
BorrowDecode, Decode, Encode,
};
use serde::{Deserialize, Serialize};
use super::hlc::HlcStamp;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Encode, Decode)]
pub struct SpaceId(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RevisionId(HlcStamp);
impl RevisionId {
pub const ZERO: RevisionId = RevisionId(HlcStamp::ZERO);
pub const fn legacy(sequence: u64) -> Self {
RevisionId(HlcStamp::legacy(sequence))
}
pub const fn from_stamp(stamp: HlcStamp) -> Self {
RevisionId(stamp)
}
pub fn stamp(self) -> HlcStamp {
self.0
}
pub fn legacy_sequence(self) -> u64 {
self.0.legacy_sequence()
}
pub fn session(self) -> u32 {
self.0.session
}
pub fn sequence(self) -> u32 {
self.0.sequence
}
pub fn physical_ms(self) -> u64 {
self.0.physical_ms
}
pub fn logical(self) -> u16 {
self.0.logical
}
pub fn is_global_legacy(self) -> bool {
self.0.is_legacy_embedded()
}
pub fn next_global(self) -> RevisionId {
debug_assert!(self.is_global_legacy());
RevisionId::legacy(self.legacy_sequence().saturating_add(1))
}
pub fn predecessor(self) -> RevisionId {
if self.is_global_legacy() {
RevisionId::legacy(self.legacy_sequence().saturating_sub(1))
} else {
RevisionId(HlcStamp {
sequence: self.0.sequence.saturating_sub(1),
..self.0
})
}
}
pub fn global_sequence_gap(self, earlier: RevisionId) -> u64 {
debug_assert!(self.is_global_legacy() && earlier.is_global_legacy());
self.legacy_sequence()
.saturating_sub(earlier.legacy_sequence())
}
}
impl PartialOrd for RevisionId {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RevisionId {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl Serialize for RevisionId {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.legacy_sequence().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for RevisionId {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let seq = u64::deserialize(deserializer)?;
Ok(RevisionId::legacy(seq))
}
}
impl Encode for RevisionId {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.legacy_sequence().encode(encoder)
}
}
impl<Context> Decode<Context> for RevisionId {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let seq = u64::decode(decoder)?;
Ok(RevisionId::legacy(seq))
}
}
impl<'de, Context> BorrowDecode<'de, Context> for RevisionId {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let seq = u64::borrow_decode(decoder)?;
Ok(RevisionId::legacy(seq))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)]
pub struct DimensionVector {
pub coords: Vec<u32>,
}
impl DimensionVector {
pub fn new(coords: Vec<u32>) -> Self {
assert!(
coords.len() <= 16,
"DimensionVector exceeds maximum of 16 dimensions"
);
Self { coords }
}
pub fn dims(&self) -> usize {
self.coords.len()
}
pub fn coord(&self, idx: usize) -> u32 {
self.coords[idx]
}
pub fn within(&self, min: &DimensionVector, max: &DimensionVector) -> bool {
assert_eq!(self.dims(), min.dims());
assert_eq!(self.dims(), max.dims());
self.coords
.iter()
.zip(min.coords.iter().zip(max.coords.iter()))
.all(|(&v, (&lo, &hi))| v >= lo && v <= hi)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)]
pub struct Address {
pub space: SpaceId,
pub point: DimensionVector,
}
impl Address {
pub fn new(space: SpaceId, point: DimensionVector) -> Self {
Self { space, point }
}
}
#[cfg(test)]
mod revision_bincode_tests {
use super::*;
use bincode::{config::standard, decode_from_slice, encode_to_vec};
#[test]
fn legacy_revision_bincode_roundtrip() {
let rev = RevisionId::legacy(1);
let bytes = encode_to_vec(rev, standard()).unwrap();
let (decoded, consumed) = decode_from_slice::<RevisionId, _>(&bytes, standard()).unwrap();
assert_eq!(consumed, bytes.len());
assert_eq!(decoded, rev);
}
}