use core::fmt;
pub const MAX_STREAM_SOURCE_ID_BYTES: usize = 256;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum StreamSourceIdError {
Empty,
TooLong,
}
impl_static_error!(StreamSourceIdError,
Self::Empty => "stream source identity is empty",
Self::TooLong => "stream source identity is too long",
);
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct StreamSourceId<'a>(&'a [u8]);
impl<'a> StreamSourceId<'a> {
pub const fn new(value: &'a [u8]) -> Result<Self, StreamSourceIdError> {
if value.is_empty() {
return Err(StreamSourceIdError::Empty);
}
if value.len() > MAX_STREAM_SOURCE_ID_BYTES {
return Err(StreamSourceIdError::TooLong);
}
Ok(Self(value))
}
#[must_use]
pub const fn as_bytes(self) -> &'a [u8] {
self.0
}
}
impl fmt::Debug for StreamSourceId<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("StreamSourceId([redacted])")
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum StreamReplayability<'a> {
NotReplayable,
Replayable(StreamSourceId<'a>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum StreamReplayError {
NonReplayable,
SourceChanged,
}
impl_static_error!(StreamReplayError,
Self::NonReplayable => "stream source is not replayable",
Self::SourceChanged => "stream source changed between attempts",
);
pub fn validate_stream_replay(
initial: StreamReplayability<'_>,
replay: StreamReplayability<'_>,
) -> Result<(), StreamReplayError> {
let (StreamReplayability::Replayable(initial), StreamReplayability::Replayable(replay)) =
(initial, replay)
else {
return Err(StreamReplayError::NonReplayable);
};
if initial.as_bytes() != replay.as_bytes() {
return Err(StreamReplayError::SourceChanged);
}
Ok(())
}