use crate::metadata_cache::CacheMode;
use crate::server::ServerError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamCaptureState {
NoCapture,
Prepare,
Capture,
}
impl StreamCaptureState {
pub fn is_recording(&self) -> bool {
matches!(self, StreamCaptureState::Capture)
}
pub fn cache_mode(&self) -> CacheMode {
match self {
StreamCaptureState::NoCapture => CacheMode::Normal,
StreamCaptureState::Prepare | StreamCaptureState::Capture => CacheMode::Capture,
}
}
pub fn prepare(&mut self) -> Result<(), ServerError> {
match self {
StreamCaptureState::NoCapture => {
*self = StreamCaptureState::Prepare;
Ok(())
}
StreamCaptureState::Prepare => Err(ServerError::graph_state(
"graph_prepare: a graph capture is already prepared on this stream",
)),
StreamCaptureState::Capture => Err(ServerError::graph_state(
"graph_prepare: a graph capture is already recording on this stream",
)),
}
}
pub fn begin(&mut self) -> Result<(), ServerError> {
match self {
StreamCaptureState::Prepare => {
*self = StreamCaptureState::Capture;
Ok(())
}
StreamCaptureState::NoCapture => Err(ServerError::graph_state(
"begin_capture: call graph_prepare before starting a capture",
)),
StreamCaptureState::Capture => Err(ServerError::graph_state(
"begin_capture: a graph capture is already recording on this stream",
)),
}
}
pub fn end(&mut self) -> Result<(), ServerError> {
match self {
StreamCaptureState::Capture => {
*self = StreamCaptureState::NoCapture;
Ok(())
}
StreamCaptureState::NoCapture | StreamCaptureState::Prepare => {
Err(ServerError::graph_state(
"end_capture: no graph capture is recording on this stream",
))
}
}
}
pub fn abort(&mut self) {
*self = StreamCaptureState::NoCapture;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn transitions_follow_the_capture_order() {
let mut state = StreamCaptureState::NoCapture;
assert!(state.begin().is_err(), "a capture must be prepared first");
assert!(state.end().is_err(), "nothing is recording yet");
assert_eq!(state, StreamCaptureState::NoCapture);
state.prepare().unwrap();
assert_eq!(state, StreamCaptureState::Prepare);
assert!(state.prepare().is_err(), "one prepare per capture");
assert!(state.end().is_err(), "the window never opened");
state.begin().unwrap();
assert_eq!(state, StreamCaptureState::Capture);
assert!(state.begin().is_err(), "captures may not overlap");
assert!(state.prepare().is_err(), "captures may not overlap");
state.end().unwrap();
assert_eq!(state, StreamCaptureState::NoCapture);
}
#[test]
fn a_rejected_transition_changes_nothing() {
let mut state = StreamCaptureState::Prepare;
assert!(state.prepare().is_err());
assert_eq!(state, StreamCaptureState::Prepare);
state.begin().unwrap();
}
#[test]
fn abort_recovers_a_window_that_never_opened() {
for state in [StreamCaptureState::Prepare, StreamCaptureState::Capture] {
let mut state = state;
state.abort();
assert_eq!(state, StreamCaptureState::NoCapture);
state.prepare().expect("the stream is re-capturable");
}
}
#[test]
fn the_cache_captures_across_the_whole_window() {
assert_eq!(
StreamCaptureState::NoCapture.cache_mode(),
CacheMode::Normal
);
assert_eq!(StreamCaptureState::Prepare.cache_mode(), CacheMode::Capture);
assert_eq!(StreamCaptureState::Capture.cache_mode(), CacheMode::Capture);
}
}