use core::{
cmp::Ordering,
ops::{Add, AddAssign, Sub},
};
use derive_more::{Display, From, Into};
use serde::{Deserialize, Serialize};
pub use self::kafka_uuid::{KafkaUuid, KafkaUuidError};
mod kafka_uuid;
#[derive(
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
From,
Into,
Serialize,
Deserialize,
)]
#[serde(transparent)]
pub struct Offset(pub i64);
impl Offset {
pub const ZERO: Self = Offset(0);
#[must_use]
pub const fn get(self) -> i64 {
self.0
}
}
impl Add<i64> for Offset {
type Output = Offset;
fn add(self, count: i64) -> Offset {
Offset(self.0 + count)
}
}
impl Sub<i64> for Offset {
type Output = Offset;
fn sub(self, count: i64) -> Offset {
Offset(self.0 - count)
}
}
impl AddAssign<i64> for Offset {
fn add_assign(&mut self, count: i64) {
self.0 += count;
}
}
#[derive(
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
From,
Into,
Serialize,
Deserialize,
)]
#[serde(transparent)]
pub struct PartitionIndex(pub i32);
impl PartitionIndex {
#[must_use]
pub const fn get(self) -> i32 {
self.0
}
}
#[derive(
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
From,
Into,
Serialize,
Deserialize,
)]
#[serde(transparent)]
pub struct NodeId(pub u64);
impl NodeId {
#[must_use]
pub const fn get(self) -> u64 {
self.0
}
}
#[derive(
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
From,
Into,
Serialize,
Deserialize,
)]
#[serde(transparent)]
pub struct ProducerId(pub i64);
impl ProducerId {
pub const NONE: Self = ProducerId(-1);
#[must_use]
pub const fn get(self) -> i64 {
self.0
}
#[must_use]
pub const fn is_none(self) -> bool {
self.0 == Self::NONE.0
}
}
#[derive(
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
From,
Into,
Serialize,
Deserialize,
)]
#[serde(transparent)]
pub struct LeaderEpoch(pub i32);
impl LeaderEpoch {
pub const UNKNOWN: Self = LeaderEpoch(-1);
pub const INITIAL: Self = LeaderEpoch(0);
#[must_use]
pub const fn get(self) -> i32 {
self.0
}
#[must_use]
pub const fn is_known(self) -> bool {
self.0 >= 0
}
#[must_use]
pub const fn next(self) -> Self {
LeaderEpoch(self.0 + 1)
}
}
#[derive(
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
From,
Into,
Serialize,
Deserialize,
)]
#[serde(transparent)]
pub struct ApiKey(pub i16);
impl ApiKey {
#[must_use]
pub const fn get(self) -> i16 {
self.0
}
}
#[derive(
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
From,
Into,
Serialize,
Deserialize,
)]
#[serde(transparent)]
pub struct ApiVersion(pub i16);
impl ApiVersion {
#[must_use]
pub const fn get(self) -> i16 {
self.0
}
}
macro_rules! impl_primitive_cmp {
($ty:ty, $inner:ty) => {
impl PartialEq<$inner> for $ty {
#[inline]
fn eq(&self, other: &$inner) -> bool {
self.0 == *other
}
}
impl PartialEq<$ty> for $inner {
#[inline]
fn eq(&self, other: &$ty) -> bool {
*self == other.0
}
}
impl PartialOrd<$inner> for $ty {
#[inline]
fn partial_cmp(&self, other: &$inner) -> Option<Ordering> {
self.0.partial_cmp(other)
}
}
impl PartialOrd<$ty> for $inner {
#[inline]
fn partial_cmp(&self, other: &$ty) -> Option<Ordering> {
self.partial_cmp(&other.0)
}
}
};
}
impl_primitive_cmp!(Offset, i64);
impl_primitive_cmp!(PartitionIndex, i32);
impl_primitive_cmp!(NodeId, u64);
impl_primitive_cmp!(ProducerId, i64);
impl_primitive_cmp!(LeaderEpoch, i32);
impl_primitive_cmp!(ApiKey, i16);
impl_primitive_cmp!(ApiVersion, i16);
#[cfg(test)]
mod tests {
use super::{ApiKey, ApiVersion, LeaderEpoch, NodeId, Offset, PartitionIndex, ProducerId};
#[test]
fn offset_arithmetic_moves_by_the_operand() {
assert2::check!(Offset(10) + 3 == Offset(13));
assert2::check!(Offset(10) - 3 == Offset(7));
let mut offset = Offset(10);
offset += 3;
assert2::check!(offset == Offset(13));
assert2::check!(Offset(2) - 5 == Offset(-3));
assert2::check!(Offset::ZERO + 1 == Offset(1));
}
#[test]
fn accessors_and_advance_return_the_inner_value() {
assert2::assert!(Offset(9).get() == 9);
assert2::assert!(PartitionIndex(4).get() == 4);
assert2::assert!(NodeId(7).get() == 7);
assert2::assert!(ProducerId(42).get() == 42);
assert2::assert!(LeaderEpoch(3).get() == 3);
assert2::assert!(ApiKey(18).get() == 18);
assert2::assert!(ApiVersion(2).get() == 2);
assert2::assert!(LeaderEpoch(4).next() == LeaderEpoch(5));
}
#[test]
fn compares_against_raw_primitive_in_both_directions() {
assert2::assert!(Offset(5) == 5);
assert2::assert!(5 == Offset(5));
assert2::assert!(Offset(5) != 6);
assert2::assert!(Offset(5) > 3);
assert2::assert!(3 < Offset(5));
assert2::assert!(Offset::ZERO >= 0);
assert2::assert!(NodeId(7) == 7);
assert2::assert!(ApiKey(18) == 18);
}
#[test]
fn newtype_to_newtype_comparison_still_holds() {
assert2::assert!(Offset(1) < Offset(2));
assert2::assert!(Offset(2) == Offset(2));
let mut xs = [Offset(3), Offset(1), Offset(2)];
xs.sort();
assert2::assert!(xs == [Offset(1), Offset(2), Offset(3)]);
}
#[test]
fn sentinels_carry_kafka_meaning() {
assert2::assert!(LeaderEpoch::UNKNOWN == -1);
assert2::assert!(!LeaderEpoch::UNKNOWN.is_known());
assert2::assert!(LeaderEpoch::INITIAL == 0);
assert2::assert!(LeaderEpoch::INITIAL.is_known());
assert2::assert!(ProducerId::NONE == -1);
assert2::assert!(ProducerId::NONE.is_none());
assert2::assert!(!ProducerId(0).is_none());
assert2::assert!(Offset::ZERO == 0);
}
}