#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CheckpointId(String);
impl CheckpointId {
#[must_use]
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AtLeastOnce(CheckpointId);
impl AtLeastOnce {
#[must_use]
pub(crate) fn new(checkpoint_id: CheckpointId) -> Self {
Self(checkpoint_id)
}
#[must_use]
pub(crate) fn from_cursor_callback(raw: impl Into<String>) -> Self {
Self::new(CheckpointId::new(raw))
}
#[must_use]
pub fn checkpoint_id(&self) -> &CheckpointId {
&self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct IdempotencyKey([u8; 32]);
impl IdempotencyKey {
#[must_use]
pub const fn from_bytes(bytes: [u8; 32]) -> Self {
Self(bytes)
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
#[must_use = "ObservedOnce must be consumed via into_parts() to retain the exactly-once witness"]
pub struct ObservedOnce {
_seal: seal::Token,
at_least_once: AtLeastOnce,
idempotency_key: IdempotencyKey,
}
mod seal {
pub(super) struct Token;
}
impl ObservedOnce {
pub fn new(at_least_once: AtLeastOnce, idempotency_key: IdempotencyKey) -> Self {
Self {
_seal: seal::Token,
at_least_once,
idempotency_key,
}
}
#[must_use]
pub fn into_parts(self) -> (AtLeastOnce, IdempotencyKey) {
(self.at_least_once, self.idempotency_key)
}
}
#[cfg(test)]
mod tests {
use super::{AtLeastOnce, CheckpointId, IdempotencyKey, ObservedOnce};
#[test]
fn observed_once_round_trips_into_parts() {
let at_least_once = AtLeastOnce::new(CheckpointId::new("cursor-checkpoint"));
let idempotency = IdempotencyKey::from_bytes([7; 32]);
let observed = ObservedOnce::new(at_least_once.clone(), idempotency);
let (actual_at_least_once, actual_idempotency) = observed.into_parts();
assert_eq!(actual_at_least_once, at_least_once);
assert_eq!(actual_idempotency, idempotency);
}
#[test]
fn at_least_once_from_cursor_callback_wraps_checkpoint_identity() {
let at_least_once = AtLeastOnce::from_cursor_callback("cursor-checkpoint");
assert_eq!(at_least_once.checkpoint_id().as_str(), "cursor-checkpoint");
}
}