use mineral_model::{DirectMedia, PlaybackMediaInfo, Song, SongId};
use mineral_protocol::PlaybackOrigin;
use crate::playback_instance::{PlaybackInstanceId, PlaybackSlot};
pub(crate) struct Queued {
pub(crate) song: Song,
pub(crate) media_info: PlaybackMediaInfo,
pub(crate) direct_media: Option<DirectMedia>,
pub(crate) origin: PlaybackOrigin,
}
#[derive(Default)]
pub(crate) enum PrefetchState {
#[default]
Idle,
Opening(PlaybackSlot),
Armed {
slot: PlaybackSlot,
queued: Box<Queued>,
},
}
impl PrefetchState {
pub(crate) fn is_armed(&self) -> bool {
matches!(self, Self::Armed { .. })
}
pub(crate) fn slot(&self) -> Option<&PlaybackSlot> {
match self {
Self::Idle => None,
Self::Opening(slot) | Self::Armed { slot, .. } => Some(slot),
}
}
pub(crate) fn slot_mut(&mut self) -> Option<&mut PlaybackSlot> {
match self {
Self::Idle => None,
Self::Opening(slot) | Self::Armed { slot, .. } => Some(slot),
}
}
pub(crate) fn song_id(&self) -> Option<&SongId> {
self.slot().map(|slot| &slot.song_id)
}
#[cfg(test)]
pub(crate) fn queued_mut(&mut self) -> Option<&mut Queued> {
match self {
Self::Armed { queued, .. } => Some(queued),
Self::Idle | Self::Opening(_) => None,
}
}
pub(crate) fn replace_opening(&mut self, slot: PlaybackSlot) {
drop(self.invalidate());
*self = Self::Opening(slot);
}
pub(crate) fn take_opening(
&mut self,
instance_id: PlaybackInstanceId,
song_id: &SongId,
) -> Option<PlaybackSlot> {
if !matches!(self, Self::Opening(slot) if slot.matches(instance_id, song_id)) {
return None;
}
let Self::Opening(slot) = std::mem::take(self) else {
return None;
};
Some(slot)
}
pub(crate) fn arm(&mut self, slot: PlaybackSlot, queued: Queued) {
*self = Self::Armed {
slot,
queued: Box::new(queued),
};
}
pub(crate) fn take_armed(&mut self) -> Option<(PlaybackSlot, Queued)> {
let Self::Armed { slot, queued } = std::mem::take(self) else {
return None;
};
Some((slot, *queued))
}
pub(crate) fn invalidate(&mut self) -> Option<Queued> {
match std::mem::take(self) {
Self::Idle => None,
Self::Opening(slot) => {
slot.cancel();
None
}
Self::Armed { slot, queued } => {
slot.cancel();
Some(*queued)
}
}
}
}