Skip to main content

moqtap_client/
namespace.rs

1/// SUBSCRIBE_NAMESPACE lifecycle states.
2#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum SubscribeNamespaceState {
4    Idle,
5    Pending,
6    Active,
7    Done,
8}
9
10/// PUBLISH_NAMESPACE lifecycle states.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum PublishNamespaceState {
13    Idle,
14    Pending,
15    Active,
16    Done,
17}
18
19#[derive(Debug, thiserror::Error, PartialEq, Eq)]
20pub enum NamespaceError {
21    #[error("invalid transition from {from} on event {event}")]
22    InvalidTransition { from: String, event: String },
23}
24
25/// State machine for SUBSCRIBE_NAMESPACE flow.
26/// Idle → Pending → Active → Done.
27pub struct SubscribeNamespaceStateMachine {
28    state: SubscribeNamespaceState,
29}
30
31impl Default for SubscribeNamespaceStateMachine {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37impl SubscribeNamespaceStateMachine {
38    pub fn new() -> Self {
39        Self { state: SubscribeNamespaceState::Idle }
40    }
41
42    pub fn state(&self) -> SubscribeNamespaceState {
43        self.state
44    }
45
46    /// Idle → Pending.
47    pub fn on_subscribe_namespace_sent(&mut self) -> Result<(), NamespaceError> {
48        if self.state == SubscribeNamespaceState::Idle {
49            self.state = SubscribeNamespaceState::Pending;
50            Ok(())
51        } else {
52            Err(NamespaceError::InvalidTransition {
53                from: format!("{:?}", self.state),
54                event: "on_subscribe_namespace_sent".to_string(),
55            })
56        }
57    }
58
59    /// Pending → Active.
60    pub fn on_subscribe_namespace_ok(&mut self) -> Result<(), NamespaceError> {
61        if self.state == SubscribeNamespaceState::Pending {
62            self.state = SubscribeNamespaceState::Active;
63            Ok(())
64        } else {
65            Err(NamespaceError::InvalidTransition {
66                from: format!("{:?}", self.state),
67                event: "on_subscribe_namespace_ok".to_string(),
68            })
69        }
70    }
71
72    /// Pending → Done.
73    pub fn on_subscribe_namespace_error(&mut self) -> Result<(), NamespaceError> {
74        if self.state == SubscribeNamespaceState::Pending {
75            self.state = SubscribeNamespaceState::Done;
76            Ok(())
77        } else {
78            Err(NamespaceError::InvalidTransition {
79                from: format!("{:?}", self.state),
80                event: "on_subscribe_namespace_error".to_string(),
81            })
82        }
83    }
84
85    /// Active → Done.
86    pub fn on_unsubscribe_namespace(&mut self) -> Result<(), NamespaceError> {
87        if self.state == SubscribeNamespaceState::Active {
88            self.state = SubscribeNamespaceState::Done;
89            Ok(())
90        } else {
91            Err(NamespaceError::InvalidTransition {
92                from: format!("{:?}", self.state),
93                event: "on_unsubscribe_namespace".to_string(),
94            })
95        }
96    }
97}
98
99/// State machine for PUBLISH_NAMESPACE flow.
100/// Idle → Pending → Active → Done.
101pub struct PublishNamespaceStateMachine {
102    state: PublishNamespaceState,
103}
104
105impl Default for PublishNamespaceStateMachine {
106    fn default() -> Self {
107        Self::new()
108    }
109}
110
111impl PublishNamespaceStateMachine {
112    pub fn new() -> Self {
113        Self { state: PublishNamespaceState::Idle }
114    }
115
116    pub fn state(&self) -> PublishNamespaceState {
117        self.state
118    }
119
120    /// Idle → Pending.
121    pub fn on_publish_namespace_sent(&mut self) -> Result<(), NamespaceError> {
122        if self.state == PublishNamespaceState::Idle {
123            self.state = PublishNamespaceState::Pending;
124            Ok(())
125        } else {
126            Err(NamespaceError::InvalidTransition {
127                from: format!("{:?}", self.state),
128                event: "on_publish_namespace_sent".to_string(),
129            })
130        }
131    }
132
133    /// Pending → Active.
134    pub fn on_publish_namespace_ok(&mut self) -> Result<(), NamespaceError> {
135        if self.state == PublishNamespaceState::Pending {
136            self.state = PublishNamespaceState::Active;
137            Ok(())
138        } else {
139            Err(NamespaceError::InvalidTransition {
140                from: format!("{:?}", self.state),
141                event: "on_publish_namespace_ok".to_string(),
142            })
143        }
144    }
145
146    /// Pending → Done.
147    pub fn on_publish_namespace_error(&mut self) -> Result<(), NamespaceError> {
148        if self.state == PublishNamespaceState::Pending {
149            self.state = PublishNamespaceState::Done;
150            Ok(())
151        } else {
152            Err(NamespaceError::InvalidTransition {
153                from: format!("{:?}", self.state),
154                event: "on_publish_namespace_error".to_string(),
155            })
156        }
157    }
158
159    /// Active → Done (publisher withdrawing).
160    pub fn on_publish_namespace_done(&mut self) -> Result<(), NamespaceError> {
161        if self.state == PublishNamespaceState::Active {
162            self.state = PublishNamespaceState::Done;
163            Ok(())
164        } else {
165            Err(NamespaceError::InvalidTransition {
166                from: format!("{:?}", self.state),
167                event: "on_publish_namespace_done".to_string(),
168            })
169        }
170    }
171
172    /// Active → Done (subscriber cancelling).
173    pub fn on_publish_namespace_cancel(&mut self) -> Result<(), NamespaceError> {
174        if self.state == PublishNamespaceState::Active {
175            self.state = PublishNamespaceState::Done;
176            Ok(())
177        } else {
178            Err(NamespaceError::InvalidTransition {
179                from: format!("{:?}", self.state),
180                event: "on_publish_namespace_cancel".to_string(),
181            })
182        }
183    }
184}