//! Internal (local) queue implementation for PMOControl. //! //! This module provides a concrete implementation of the generic //! `QueueBackend` trait for queues that are fully managed inside the //! ControlPoint, without delegating playlist management to a remote //! backend (like OpenHome). //! //! In this design, each queue instance is associated to exactly one //! renderer. The queue does not need to know the renderer identifier: //! it is "bound" to the renderer by construction, and will be stored //! directly in the runtime (inside a higher-level `MusicQueue` enum). //! //! This internal queue: //! - owns its list of `PlaybackItem`s, //! - maintains a `current_index`, //! - never starts playback (transport control is handled elsewhere). use anyhow::Result; use crate::queue_backend::{PlaybackItem, QueueBackend, QueueSnapshot}; /// Internal/local queue implementation. /// /// This is the simplest possible queue backend: /// - a `Vec` /// - plus an optional `current_index`. /// /// It does not talk to any remote service. All operations are pure /// structural mutations on in-memory data. #[derive(Clone, Debug, Default)] pub struct InternalQueue { items: Vec, current_index: Option, } impl InternalQueue { /// Creates an empty internal queue. pub fn new() -> Self { Self { items: Vec::new(), current_index: None, } } /// Creates an internal queue from an initial list of items. /// /// If `set_current_to_first` is `true` and the list is non-empty, /// the current index is set to `Some(0)`. Otherwise, it is `None`. pub fn from_items(items: Vec, set_current_to_first: bool) -> Self { let current_index = if set_current_to_first && !items.is_empty() { Some(0) } else { None }; Self { items, current_index } } /// Exposes a read-only view of the underlying items. pub fn items(&self) -> &[PlaybackItem] { &self.items } /// Exposes the current index (read-only). pub fn current_index(&self) -> Option { self.current_index } } impl QueueBackend for InternalQueue { fn queue_snapshot(&self) -> Result { Ok(QueueSnapshot { items: self.items.clone(), current_index: self.current_index, }) } fn set_index(&mut self, index: Option) -> Result<()> { match index { None => { self.current_index = None; } Some(i) => { if i < self.items.len() { self.current_index = Some(i); } else { self.current_index = None; } } } Ok(()) } fn replace_queue( &mut self, items: Vec, current_index: Option, ) -> Result<()> { self.items = items; self.current_index = current_index.filter(|&i| i < self.items.len()); Ok(()) } fn get_item(&self, index: usize) -> Result> { Ok(self.items.get(index).cloned()) } fn replace_item(&mut self, index: usize, item: PlaybackItem) -> Result<()> { if index < self.items.len() { self.items[index] = item; } Ok(()) } }