cloud_sdk/transport/streaming/
replay.rs1use core::fmt;
4
5pub const MAX_STREAM_SOURCE_ID_BYTES: usize = 256;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum StreamSourceIdError {
11 Empty,
13 TooLong,
15}
16
17impl_static_error!(StreamSourceIdError,
18 Self::Empty => "stream source identity is empty",
19 Self::TooLong => "stream source identity is too long",
20);
21
22#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
24pub struct StreamSourceId<'a>(&'a [u8]);
25
26impl<'a> StreamSourceId<'a> {
27 pub const fn new(value: &'a [u8]) -> Result<Self, StreamSourceIdError> {
29 if value.is_empty() {
30 return Err(StreamSourceIdError::Empty);
31 }
32 if value.len() > MAX_STREAM_SOURCE_ID_BYTES {
33 return Err(StreamSourceIdError::TooLong);
34 }
35 Ok(Self(value))
36 }
37
38 #[must_use]
40 pub const fn as_bytes(self) -> &'a [u8] {
41 self.0
42 }
43}
44
45impl fmt::Debug for StreamSourceId<'_> {
46 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
47 formatter.write_str("StreamSourceId([redacted])")
48 }
49}
50
51#[derive(Clone, Copy, Debug, Eq, PartialEq)]
53pub enum StreamReplayability<'a> {
54 NotReplayable,
56 Replayable(StreamSourceId<'a>),
58}
59
60#[derive(Clone, Copy, Debug, Eq, PartialEq)]
62pub enum StreamReplayError {
63 NonReplayable,
65 SourceChanged,
67}
68
69impl_static_error!(StreamReplayError,
70 Self::NonReplayable => "stream source is not replayable",
71 Self::SourceChanged => "stream source changed between attempts",
72);
73
74pub fn validate_stream_replay(
76 initial: StreamReplayability<'_>,
77 replay: StreamReplayability<'_>,
78) -> Result<(), StreamReplayError> {
79 let (StreamReplayability::Replayable(initial), StreamReplayability::Replayable(replay)) =
80 (initial, replay)
81 else {
82 return Err(StreamReplayError::NonReplayable);
83 };
84 if initial.as_bytes() != replay.as_bytes() {
85 return Err(StreamReplayError::SourceChanged);
86 }
87 Ok(())
88}