use std::collections::HashSet;
use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
use crate::error::KinesisError;
#[derive(Debug, Default)]
pub(crate) struct ReadStreams {
streams: Mutex<HashSet<String>>,
}
impl ReadStreams {
pub(crate) fn claim(self: &Arc<Self>, stream: &str) -> Result<StreamClaim, KinesisError> {
if !self.lock().insert(stream.to_owned()) {
return Err(KinesisError::AlreadySubscribed {
stream: stream.to_owned(),
});
}
Ok(StreamClaim {
streams: Arc::clone(self),
stream: stream.to_owned(),
})
}
fn lock(&self) -> MutexGuard<'_, HashSet<String>> {
self.streams.lock().unwrap_or_else(PoisonError::into_inner)
}
}
#[derive(Debug)]
pub(crate) struct StreamClaim {
streams: Arc<ReadStreams>,
stream: String,
}
impl Drop for StreamClaim {
fn drop(&mut self) {
self.streams.lock().remove(&self.stream);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_stream_is_claimed_once_until_its_claim_is_dropped() {
let streams = Arc::new(ReadStreams::default());
let first = streams.claim("orders").expect("the first claim holds");
assert!(matches!(
streams.claim("orders"),
Err(KinesisError::AlreadySubscribed { stream }) if stream == "orders"
));
let other = streams
.claim("audit")
.expect("another stream is claimed on its own");
drop(first);
let again = streams
.claim("orders")
.expect("a dropped claim frees the stream");
drop((other, again));
}
}