use std::fmt;
macro_rules! string_id {
($(#[$meta:meta])* $name:ident) => {
$(#[$meta])*
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct $name(String);
impl $name {
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn into_string(self) -> String {
self.0
}
}
impl From<String> for $name {
fn from(value: String) -> Self {
Self(value)
}
}
impl From<&str> for $name {
fn from(value: &str) -> Self {
Self(value.to_owned())
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, concat!(stringify!($name), "({:?})"), self.0)
}
}
};
}
string_id! {
PartitionId
}
string_id! {
ClusterId
}
string_id! {
IndexName
}
string_id! {
PrincipalId
}
string_id! {
RequestId
}
string_id! {
FieldName
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct Epoch(u64);
impl Epoch {
pub const ZERO: Self = Self(0);
#[must_use]
pub fn new(generation: u64) -> Self {
Self(generation)
}
#[must_use]
pub fn get(self) -> u64 {
self.0
}
#[must_use]
pub fn next(self) -> Self {
Self(self.0.saturating_add(1))
}
}
impl fmt::Display for Epoch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn string_id_roundtrips_through_str_and_string() {
let from_str = PartitionId::from("tenant-7");
let from_string = PartitionId::from("tenant-7".to_owned());
assert_eq!(from_str, from_string);
assert_eq!(from_str.as_str(), "tenant-7");
assert_eq!(from_str.clone().into_string(), "tenant-7");
}
#[test]
fn distinct_id_types_do_not_compare_but_display_plainly() {
let cluster = ClusterId::from("eu-1");
assert_eq!(cluster.to_string(), "eu-1");
assert_eq!(format!("{cluster:?}"), r#"ClusterId("eu-1")"#);
}
#[test]
fn epoch_is_monotonic_and_saturates() {
assert_eq!(Epoch::ZERO.get(), 0);
assert_eq!(Epoch::ZERO.next(), Epoch::new(1));
assert!(Epoch::new(1) > Epoch::ZERO);
assert_eq!(Epoch::new(u64::MAX).next(), Epoch::new(u64::MAX));
assert_eq!(Epoch::new(42).to_string(), "42");
}
}