use std::sync::{Arc, Mutex};
use serde::de::DeserializeOwned;
use crate::wire::item::WrappedItem;
pub(super) struct MapSequence {
state: Mutex<SequenceState>,
}
struct SequenceState {
awaiting_snapshot: bool,
next: u64,
}
impl MapSequence {
pub(super) const fn new() -> Self {
Self {
state: Mutex::new(SequenceState {
awaiting_snapshot: true,
next: 0,
}),
}
}
pub(super) fn reset_epoch(&self) {
self.state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.awaiting_snapshot = true;
}
pub(super) fn accept(&self, sequence: u64) -> bool {
let mut state = self
.state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if state.awaiting_snapshot {
if sequence != 0 {
return false;
}
state.awaiting_snapshot = false;
state.next = 1;
return true;
}
if sequence != state.next {
return false;
}
let Some(next) = state.next.checked_add(1) else {
return false;
};
state.next = next;
true
}
}
pub(super) type DecodedMapUpserts<T> = Vec<(Arc<str>, Arc<T>)>;
pub(super) fn decode_map_upserts<T, F>(
upserts: Vec<WrappedItem>,
id: F,
) -> Result<DecodedMapUpserts<T>, serde_json::Error>
where
T: DeserializeOwned,
F: Fn(&T) -> Arc<str>,
{
upserts
.into_iter()
.map(|wrapped| {
let item = Arc::new(serde_json::from_value::<T>(wrapped.item)?);
let item_id = id(&item);
Ok((item_id, item))
})
.collect()
}
#[cfg(test)]
mod tests {
use super::MapSequence;
#[test]
fn reconnect_rejects_delayed_old_epoch_and_duplicate_sequences() {
let sequences = MapSequence::new();
assert!(sequences.accept(0));
assert!(sequences.accept(1));
assert!(!sequences.accept(1));
sequences.reset_epoch();
assert!(!sequences.accept(2));
assert!(sequences.accept(0));
assert!(!sequences.accept(0));
assert!(!sequences.accept(2));
assert!(sequences.accept(1));
}
}