1 pub mod buffer;
2 pub mod direction;
3 pub mod dqbuf;
4 pub mod generic;
5 pub mod handles_provider;
6 pub mod qbuf;
7 
8 use self::qbuf::{get_free::GetFreeOutputBuffer, get_indexed::GetOutputBufferByIndex};
9 
10 use super::{AllocatedQueue, Device, FreeBuffersResult, Stream, TryDequeue};
11 use crate::ioctl::{DqBufResult, QueryBufError, V4l2BufferFromError};
12 use crate::{bindings, memory::*};
13 use crate::{
14     ioctl::{
15         self, GFmtError, QueryBuffer, ReqbufsError, SFmtError, SelectionTarget, SelectionType,
16         StreamOffError, StreamOnError, TryFmtError,
17     },
18     PlaneLayout, Rect,
19 };
20 use crate::{Format, PixelFormat, QueueType};
21 use buffer::*;
22 use direction::*;
23 use dqbuf::*;
24 use generic::{GenericBufferHandles, GenericQBuffer, GenericSupportedMemoryType};
25 use log::debug;
26 use qbuf::{
27     get_free::{GetFreeBufferError, GetFreeCaptureBuffer},
28     get_indexed::{GetCaptureBufferByIndex, TryGetBufferError},
29     *,
30 };
31 
32 use std::convert::{Infallible, TryFrom};
33 use std::os::unix::io::{AsRawFd, RawFd};
34 use std::sync::{Arc, Weak};
35 use thiserror::Error;
36 
37 /// Base values of a queue, that are always value no matter the state the queue
38 /// is in. This base object remains alive as long as the queue is borrowed from
39 /// the `Device`.
40 pub struct QueueBase {
41     // Reference to the device, so we can perform operations on its `fd` and to let us mark the
42     // queue as free again upon destruction.
43     device: Arc<Device>,
44     type_: QueueType,
45     capabilities: ioctl::BufferCapabilities,
46 }
47 
48 impl AsRawFd for QueueBase {
as_raw_fd(&self) -> RawFd49     fn as_raw_fd(&self) -> RawFd {
50         self.device.as_raw_fd()
51     }
52 }
53 
54 impl Drop for QueueBase {
55     /// Make the queue available again.
drop(&mut self)56     fn drop(&mut self) {
57         assert!(self.device.used_queues.lock().unwrap().remove(&self.type_));
58     }
59 }
60 
61 /// Trait for the different states a queue can be in. This allows us to limit
62 /// the available queue methods to the one that make sense at a given point of
63 /// the queue's lifecycle.
64 pub trait QueueState {}
65 
66 /// V4L2 queue object. Specialized according to its configuration state so that
67 /// only valid methods can be called from a given point.
68 pub struct Queue<D, S>
69 where
70     D: Direction,
71     S: QueueState,
72 {
73     inner: QueueBase,
74     _d: std::marker::PhantomData<D>,
75     state: S,
76 }
77 
78 /// Methods of `Queue` that are available no matter the state.
79 impl<D, S> Queue<D, S>
80 where
81     D: Direction,
82     S: QueueState,
83 {
get_capabilities(&self) -> ioctl::BufferCapabilities84     pub fn get_capabilities(&self) -> ioctl::BufferCapabilities {
85         self.inner.capabilities
86     }
87 
get_type(&self) -> QueueType88     pub fn get_type(&self) -> QueueType {
89         self.inner.type_
90     }
91 
get_format<T: TryFrom<bindings::v4l2_format>>(&self) -> Result<T, GFmtError>92     pub fn get_format<T: TryFrom<bindings::v4l2_format>>(&self) -> Result<T, GFmtError> {
93         ioctl::g_fmt(&self.inner, self.inner.type_)
94     }
95 
96     /// This method can invalidate any current format iterator, hence it requires
97     /// the queue to be mutable. This way of doing is not perfect though, as setting
98     /// the format on one queue can change the options available on another.
set_format(&mut self, format: Format) -> Result<Format, SFmtError>99     pub fn set_format(&mut self, format: Format) -> Result<Format, SFmtError> {
100         let type_ = self.inner.type_;
101         ioctl::s_fmt(&mut self.inner, (type_, &format))
102     }
103 
104     /// Performs exactly as `set_format`, but does not actually apply `format`.
105     /// Useful to check what modifications need to be done to a format before it
106     /// can be used.
try_format(&self, format: Format) -> Result<Format, TryFmtError>107     pub fn try_format(&self, format: Format) -> Result<Format, TryFmtError> {
108         ioctl::try_fmt(&self.inner, (self.inner.type_, &format))
109     }
110 
111     /// Returns a `FormatBuilder` which is set to the currently active format
112     /// and can be modified and eventually applied. The `FormatBuilder` holds
113     /// a mutable reference to this `Queue`.
change_format(&mut self) -> Result<FormatBuilder, GFmtError>114     pub fn change_format(&mut self) -> Result<FormatBuilder, GFmtError> {
115         FormatBuilder::new(&mut self.inner)
116     }
117 
118     /// Returns an iterator over all the formats currently supported by this queue.
format_iter(&self) -> ioctl::FormatIterator<QueueBase>119     pub fn format_iter(&self) -> ioctl::FormatIterator<QueueBase> {
120         ioctl::FormatIterator::new(&self.inner, self.inner.type_)
121     }
122 
get_selection(&self, target: SelectionTarget) -> Result<Rect, ioctl::GSelectionError>123     pub fn get_selection(&self, target: SelectionTarget) -> Result<Rect, ioctl::GSelectionError> {
124         let selection = match self.get_type() {
125             QueueType::VideoCapture | QueueType::VideoCaptureMplane => SelectionType::Capture,
126             QueueType::VideoOutput | QueueType::VideoOutputMplane => SelectionType::Output,
127             _ => return Err(ioctl::GSelectionError::Invalid),
128         };
129 
130         ioctl::g_selection(&self.inner, selection, target)
131     }
132 }
133 
134 /// Builder for a V4L2 format. This takes a mutable reference on the queue, so
135 /// it is supposed to be short-lived: get one, adjust the format, and apply.
136 pub struct FormatBuilder<'a> {
137     queue: &'a mut QueueBase,
138     format: Format,
139 }
140 
141 impl<'a> FormatBuilder<'a> {
new(queue: &'a mut QueueBase) -> Result<Self, GFmtError>142     fn new(queue: &'a mut QueueBase) -> Result<Self, GFmtError> {
143         let format = ioctl::g_fmt(queue, queue.type_)?;
144         Ok(Self { queue, format })
145     }
146 
147     /// Get a reference to the format built so far. Useful for checking the
148     /// currently set format after getting a builder, or the actual settings
149     /// that will be applied by the kernel after a `try_apply()`.
format(&self) -> &Format150     pub fn format(&self) -> &Format {
151         &self.format
152     }
153 
set_size(mut self, width: usize, height: usize) -> Self154     pub fn set_size(mut self, width: usize, height: usize) -> Self {
155         self.format.width = width as u32;
156         self.format.height = height as u32;
157         self
158     }
159 
set_pixelformat(mut self, pixel_format: impl Into<PixelFormat>) -> Self160     pub fn set_pixelformat(mut self, pixel_format: impl Into<PixelFormat>) -> Self {
161         self.format.pixelformat = pixel_format.into();
162         self
163     }
164 
set_planes_layout<P: IntoIterator<Item = PlaneLayout>>(mut self, planes: P) -> Self165     pub fn set_planes_layout<P: IntoIterator<Item = PlaneLayout>>(mut self, planes: P) -> Self {
166         self.format.plane_fmt = planes.into_iter().collect();
167         self
168     }
169 
170     /// Apply the format built so far. The kernel will adjust the format to fit
171     /// the driver's capabilities if needed, and the format actually applied will
172     /// be returned.
apply<O: TryFrom<bindings::v4l2_format>>(self) -> Result<O, SFmtError>173     pub fn apply<O: TryFrom<bindings::v4l2_format>>(self) -> Result<O, SFmtError> {
174         ioctl::s_fmt(self.queue, (self.queue.type_, &self.format))
175     }
176 
177     /// Try to apply the format built so far. The kernel will adjust the format
178     /// to fit the driver's capabilities if needed, so make sure to check important
179     /// parameters upon return.
180     ///
181     /// Calling `apply()` right after this method is guaranteed to successfully
182     /// apply the format without further change.
try_apply(&mut self) -> Result<(), TryFmtError>183     pub fn try_apply(&mut self) -> Result<(), TryFmtError> {
184         let new_format = ioctl::try_fmt(self.queue, (self.queue.type_, &self.format))?;
185 
186         self.format = new_format;
187         Ok(())
188     }
189 }
190 
191 /// Initial state of the queue when created. Streaming and queuing are not
192 /// supported since buffers have not been allocated yet.
193 /// Allocating buffers makes the queue switch to the `BuffersAllocated` state.
194 pub struct QueueInit;
195 impl QueueState for QueueInit {}
196 
197 #[derive(Debug, Error)]
198 pub enum CreateQueueError {
199     #[error("queue is already in use")]
200     AlreadyBorrowed,
201     #[error("error while querying queue capabilities")]
202     ReqbufsError(#[from] ioctl::ReqbufsError),
203 }
204 
205 #[derive(Debug, Error)]
206 pub enum RequestBuffersError {
207     #[error("error while requesting buffers")]
208     ReqbufsError(#[from] ioctl::ReqbufsError),
209     #[error("error while querying buffer")]
210     QueryBufferError(#[from] QueryBufError<Infallible>),
211 }
212 
213 impl<D: Direction> Queue<D, QueueInit> {
214     /// Create a queue for type `queue_type` on `device`. A queue of a specific type
215     /// can be requested only once.
216     ///
217     /// Not all devices support all kinds of queue. To test whether the queue is supported,
218     /// a REQBUFS(0) is issued on the device. If it is not successful, the device is
219     /// deemed to not support this kind of queue and this method will fail.
create( device: Arc<Device>, queue_type: QueueType, ) -> Result<Queue<D, QueueInit>, CreateQueueError>220     fn create(
221         device: Arc<Device>,
222         queue_type: QueueType,
223     ) -> Result<Queue<D, QueueInit>, CreateQueueError> {
224         let mut used_queues = device.used_queues.lock().unwrap();
225 
226         if used_queues.contains(&queue_type) {
227             return Err(CreateQueueError::AlreadyBorrowed);
228         }
229 
230         // Check that the queue is valid for this device by doing a dummy REQBUFS.
231         // Obtain its capacities while we are at it.
232         let capabilities: ioctl::BufferCapabilities =
233             ioctl::reqbufs(&*device, queue_type, MemoryType::Mmap, 0)
234                 // In the unlikely case that MMAP buffers are not supported, try DMABUF.
235                 .or_else(|e| match e {
236                     ReqbufsError::InvalidBufferType(_, _) => {
237                         ioctl::reqbufs(&*device, queue_type, MemoryType::DmaBuf, 0)
238                     }
239                     _ => Err(e),
240                 })?;
241 
242         used_queues.insert(queue_type);
243 
244         drop(used_queues);
245 
246         Ok(Queue::<D, QueueInit> {
247             inner: QueueBase {
248                 device,
249                 type_: queue_type,
250                 capabilities,
251             },
252             _d: std::marker::PhantomData,
253             state: QueueInit {},
254         })
255     }
256 
request_buffers_generic<P: BufferHandles>( self, memory_type: P::SupportedMemoryType, count: u32, ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError>257     pub fn request_buffers_generic<P: BufferHandles>(
258         self,
259         memory_type: P::SupportedMemoryType,
260         count: u32,
261     ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError> {
262         let type_ = self.inner.type_;
263         let num_buffers: usize = ioctl::reqbufs(&self.inner, type_, memory_type.into(), count)?;
264 
265         debug!(
266             "Requested {} buffers on {} queue, obtained {}",
267             count, type_, num_buffers
268         );
269 
270         // The buffers have been allocated, now let's get their features.
271         // We cannot use functional programming here because we need to return
272         // the error from ioctl::querybuf(), if any.
273         let mut buffer_features = Vec::new();
274         for i in 0..num_buffers {
275             buffer_features.push(ioctl::querybuf(&self.inner, self.inner.type_, i)?);
276         }
277 
278         let buffer_stats = Arc::new(BufferStats::new());
279 
280         let buffer_info = buffer_features
281             .into_iter()
282             .map(|features: QueryBuffer| {
283                 Arc::new(BufferInfo::new(features, Arc::clone(&buffer_stats)))
284             })
285             .collect();
286 
287         Ok(Queue {
288             inner: self.inner,
289             _d: std::marker::PhantomData,
290             state: BuffersAllocated {
291                 memory_type,
292                 buffer_info,
293                 buffer_stats,
294             },
295         })
296     }
297 
298     /// Allocate `count` buffers for this queue and make it transition to the
299     /// `BuffersAllocated` state.
request_buffers<P: PrimitiveBufferHandles>( self, count: u32, ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError>300     pub fn request_buffers<P: PrimitiveBufferHandles>(
301         self,
302         count: u32,
303     ) -> Result<Queue<D, BuffersAllocated<P>>, RequestBuffersError> {
304         self.request_buffers_generic(P::MEMORY_TYPE, count)
305     }
306 }
307 
308 impl Queue<Output, QueueInit> {
309     /// Acquires the OUTPUT queue from `device`.
310     ///
311     /// This method will fail if the queue has already been obtained and has not
312     /// yet been released.
get_output_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>313     pub fn get_output_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
314         Queue::<Output, QueueInit>::create(device, QueueType::VideoOutput)
315     }
316 
317     /// Acquires the OUTPUT_MPLANE queue from `device`.
318     ///
319     /// This method will fail if the queue has already been obtained and has not
320     /// yet been released.
get_output_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>321     pub fn get_output_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
322         Queue::<Output, QueueInit>::create(device, QueueType::VideoOutputMplane)
323     }
324 }
325 
326 impl Queue<Capture, QueueInit> {
327     /// Acquires the CAPTURE queue from `device`.
328     ///
329     /// This method will fail if the queue has already been obtained and has not
330     /// yet been released.
get_capture_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>331     pub fn get_capture_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
332         Queue::<Capture, QueueInit>::create(device, QueueType::VideoCapture)
333     }
334 
335     /// Acquires the CAPTURE_MPLANE queue from `device`.
336     ///
337     /// This method will fail if the queue has already been obtained and has not
338     /// yet been released.
get_capture_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError>339     pub fn get_capture_mplane_queue(device: Arc<Device>) -> Result<Self, CreateQueueError> {
340         Queue::<Capture, QueueInit>::create(device, QueueType::VideoCaptureMplane)
341     }
342 }
343 
344 /// Allocated state for a queue. A queue with its buffers allocated can be
345 /// streamed on and off, and buffers can be queued and dequeued.
346 pub struct BuffersAllocated<P: BufferHandles> {
347     memory_type: P::SupportedMemoryType,
348     /// Keep one `Arc` per buffer. This allows us to invalidate this buffer only in case it gets
349     /// deallocated alone (V4L2 currently does not allow this, but might in the future).
350     buffer_info: Vec<Arc<BufferInfo<P>>>,
351     buffer_stats: Arc<BufferStats>,
352 }
353 impl<P: BufferHandles> QueueState for BuffersAllocated<P> {}
354 
355 impl<D: Direction, P: BufferHandles> Queue<D, BuffersAllocated<P>> {
356     /// Return all the currently queued buffers as CanceledBuffers. This can
357     /// be called after a explicit or implicit streamoff to inform the client
358     /// of which buffers have been canceled and return their handles.
cancel_queued_buffers(&self) -> Vec<CanceledBuffer<P>>359     fn cancel_queued_buffers(&self) -> Vec<CanceledBuffer<P>> {
360         let canceled_buffers: Vec<_> = self
361             .state
362             .buffer_info
363             .iter()
364             .filter_map(|buffer_info| {
365                 // Take the handles of queued entries and make them free again.
366                 // Skip entries in any other state.
367                 let plane_handles = buffer_info.update_state(|state| {
368                     match *state {
369                         // Set queued entry to `Free` state and steal its handles.
370                         BufferState::Queued(_) => {
371                             // We just matched the state but need to do it again in order to take
372                             // the handles since `state` is a reference...
373                             match std::mem::replace(state, BufferState::Free) {
374                                 BufferState::Queued(handles) => Some(handles),
375                                 _ => unreachable!(),
376                             }
377                         }
378                         // Filter out entries not in queued state.
379                         _ => None,
380                     }
381                 })?;
382 
383                 Some(CanceledBuffer {
384                     index: buffer_info.features.index as u32,
385                     plane_handles,
386                 })
387             })
388             .collect();
389 
390         debug!(
391             "{} buffers canceled on {} queue",
392             canceled_buffers.len(),
393             self.get_type()
394         );
395 
396         assert_eq!(self.state.buffer_stats.num_queued(), 0);
397 
398         canceled_buffers
399     }
400 
401     /// Try to obtain a buffer to pass to userspace so it can be queued. `index` must be the index
402     /// of a buffer in the `Free` state, otherwise an `AlreadyUsed` error is returned.
try_obtain_buffer(&self, index: usize) -> Result<&Arc<BufferInfo<P>>, TryGetBufferError>403     fn try_obtain_buffer(&self, index: usize) -> Result<&Arc<BufferInfo<P>>, TryGetBufferError> {
404         let buffer_info = self
405             .state
406             .buffer_info
407             .get(index)
408             .ok_or(TryGetBufferError::InvalidIndex(index))?;
409 
410         buffer_info.update_state(|state| match *state {
411             BufferState::Free => {
412                 *state = BufferState::PreQueue;
413                 Ok(())
414             }
415             _ => Err(TryGetBufferError::AlreadyUsed),
416         })?;
417 
418         Ok(buffer_info)
419     }
420 }
421 
422 impl<'a, D: Direction, P: BufferHandles + 'a> AllocatedQueue<'a, D>
423     for Queue<D, BuffersAllocated<P>>
424 {
num_buffers(&self) -> usize425     fn num_buffers(&self) -> usize {
426         self.state.buffer_info.len()
427     }
428 
num_queued_buffers(&self) -> usize429     fn num_queued_buffers(&self) -> usize {
430         self.state.buffer_stats.num_queued()
431     }
432 
num_free_buffers(&self) -> usize433     fn num_free_buffers(&self) -> usize {
434         self.state.buffer_stats.num_free()
435     }
436 
free_buffers(self) -> Result<FreeBuffersResult<D, Self>, ioctl::ReqbufsError>437     fn free_buffers(self) -> Result<FreeBuffersResult<D, Self>, ioctl::ReqbufsError> {
438         let type_ = self.inner.type_;
439         ioctl::reqbufs::<()>(&self.inner, type_, self.state.memory_type.into(), 0)?;
440 
441         debug!("Freed all buffers on {} queue", type_);
442 
443         // reqbufs also performs an implicit streamoff, so return the cancelled
444         // buffers.
445         let canceled_buffers = self.cancel_queued_buffers();
446 
447         Ok(FreeBuffersResult {
448             queue: Queue {
449                 inner: self.inner,
450                 _d: std::marker::PhantomData,
451                 state: QueueInit {},
452             },
453             canceled_buffers,
454         })
455     }
456 }
457 
458 /// Represents a queued buffer which has not been processed due to `streamoff`
459 /// being called on a queue.
460 pub struct CanceledBuffer<P: BufferHandles> {
461     /// Index of the buffer,
462     pub index: u32,
463     /// Plane handles that were passed when the buffer has been queued.
464     pub plane_handles: P,
465 }
466 
467 impl<D: Direction, P: BufferHandles> Stream for Queue<D, BuffersAllocated<P>> {
468     type Canceled = CanceledBuffer<P>;
469 
stream_on(&self) -> Result<(), StreamOnError>470     fn stream_on(&self) -> Result<(), StreamOnError> {
471         debug!("{} queue streaming on", self.get_type());
472         let type_ = self.inner.type_;
473         ioctl::streamon(&self.inner, type_)
474     }
475 
stream_off(&self) -> Result<Vec<Self::Canceled>, StreamOffError>476     fn stream_off(&self) -> Result<Vec<Self::Canceled>, StreamOffError> {
477         debug!("{} queue streaming off", self.get_type());
478         let type_ = self.inner.type_;
479         ioctl::streamoff(&self.inner, type_)?;
480 
481         Ok(self.cancel_queued_buffers())
482     }
483 }
484 
485 impl<D: Direction, P: BufferHandles> TryDequeue for Queue<D, BuffersAllocated<P>> {
486     type Dequeued = DqBuffer<D, P>;
487 
try_dequeue(&self) -> DqBufResult<Self::Dequeued, V4l2BufferFromError>488     fn try_dequeue(&self) -> DqBufResult<Self::Dequeued, V4l2BufferFromError> {
489         let dqbuf: ioctl::V4l2Buffer = ioctl::dqbuf(&self.inner, self.inner.type_)?;
490 
491         let id = dqbuf.index() as usize;
492 
493         let buffer_info = self
494             .state
495             .buffer_info
496             .get(id)
497             .expect("Inconsistent buffer state!");
498 
499         let plane_handles = buffer_info.update_state(|state| match *state {
500             BufferState::Queued(_) => {
501                 // We just matched the state but need to do it again in order to take the handles
502                 // since `state` is a reference...
503                 match std::mem::replace(state, BufferState::Dequeued) {
504                     BufferState::Queued(handles) => handles,
505                     _ => unreachable!(),
506                 }
507             }
508             _ => unreachable!("Inconsistent buffer state!"),
509         });
510 
511         let fuse = BufferStateFuse::new(Arc::downgrade(buffer_info));
512 
513         let dqbuffer = DqBuffer::new(self, buffer_info, plane_handles, dqbuf, fuse);
514 
515         Ok(dqbuffer)
516     }
517 }
518 
519 mod private {
520     use super::*;
521 
522     /// Private trait for providing a Queuable regardless of the queue's
523     /// direction. Avoids duplicating the same code in
524     /// Capture/OutputQueueableProvider's implementations.
525     pub trait GetBufferByIndex<'a> {
526         type Queueable: 'a;
527 
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>528         fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>;
529     }
530 
531     /// Same as `GetBufferByIndex` but for providing any free buffer.
532     pub trait GetFreeBuffer<'a, ErrorType = GetFreeBufferError>: GetBufferByIndex<'a> {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, ErrorType>533         fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, ErrorType>;
534     }
535 
536     impl<'a, D: Direction, P: PrimitiveBufferHandles> GetBufferByIndex<'a>
537         for Queue<D, BuffersAllocated<P>>
538     {
539         type Queueable = QBuffer<'a, D, P, P>;
540 
541         // Take buffer `id` in order to prepare it for queueing, provided it is available.
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>542         fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
543             Ok(QBuffer::new(self, self.try_obtain_buffer(index)?))
544         }
545     }
546 
547     impl<'a, D: Direction> GetBufferByIndex<'a> for Queue<D, BuffersAllocated<GenericBufferHandles>> {
548         type Queueable = GenericQBuffer<'a, D>;
549 
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>550         fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
551             let buffer_info = self.try_obtain_buffer(index)?;
552 
553             Ok(match self.state.memory_type {
554                 GenericSupportedMemoryType::Mmap => {
555                     GenericQBuffer::Mmap(QBuffer::new(self, buffer_info))
556                 }
557                 GenericSupportedMemoryType::UserPtr => {
558                     GenericQBuffer::User(QBuffer::new(self, buffer_info))
559                 }
560                 GenericSupportedMemoryType::DmaBuf => {
561                     GenericQBuffer::DmaBuf(QBuffer::new(self, buffer_info))
562                 }
563             })
564         }
565     }
566 
567     impl<'a, D, P> GetFreeBuffer<'a> for Queue<D, BuffersAllocated<P>>
568     where
569         D: Direction,
570         P: BufferHandles,
571         Self: GetBufferByIndex<'a>,
572     {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>573         fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError> {
574             let res = self
575                 .state
576                 .buffer_info
577                 .iter()
578                 .enumerate()
579                 .find(|(_, s)| s.do_with_state(|s| matches!(s, BufferState::Free)));
580 
581             match res {
582                 None => Err(GetFreeBufferError::NoFreeBuffer),
583                 Some((i, _)) => Ok(self.try_get_buffer(i).unwrap()),
584             }
585         }
586     }
587 }
588 
589 impl<'a, P: PrimitiveBufferHandles> CaptureQueueableProvider<'a, P>
590     for Queue<Capture, BuffersAllocated<P>>
591 where
592     Self: private::GetBufferByIndex<'a>,
593     <Self as private::GetBufferByIndex<'a>>::Queueable: CaptureQueueable<P>,
594 {
595     type Queueable = <Self as private::GetBufferByIndex<'a>>::Queueable;
596 }
597 
598 impl<'a, P: PrimitiveBufferHandles> OutputQueueableProvider<'a, P>
599     for Queue<Output, BuffersAllocated<P>>
600 where
601     Self: private::GetBufferByIndex<'a>,
602     <Self as private::GetBufferByIndex<'a>>::Queueable: OutputQueueable<P>,
603 {
604     type Queueable = <Self as private::GetBufferByIndex<'a>>::Queueable;
605 }
606 
607 impl<'a, P: BufferHandles, R> GetOutputBufferByIndex<'a, P> for Queue<Output, BuffersAllocated<P>>
608 where
609     Self: private::GetBufferByIndex<'a, Queueable = R>,
610     Self: OutputQueueableProvider<'a, P, Queueable = R>,
611 {
612     // Take buffer `id` in order to prepare it for queueing, provided it is available.
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>613     fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
614         <Self as private::GetBufferByIndex<'a>>::try_get_buffer(self, index)
615     }
616 }
617 
618 impl<'a, P: BufferHandles, R> GetCaptureBufferByIndex<'a, P> for Queue<Capture, BuffersAllocated<P>>
619 where
620     Self: private::GetBufferByIndex<'a, Queueable = R>,
621     Self: CaptureQueueableProvider<'a, P, Queueable = R>,
622 {
623     // Take buffer `id` in order to prepare it for queueing, provided it is available.
try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError>624     fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
625         <Self as private::GetBufferByIndex<'a>>::try_get_buffer(self, index)
626     }
627 }
628 
629 impl<'a, P: BufferHandles, R> GetFreeOutputBuffer<'a, P> for Queue<Output, BuffersAllocated<P>>
630 where
631     Self: private::GetFreeBuffer<'a, Queueable = R>,
632     Self: OutputQueueableProvider<'a, P, Queueable = R>,
633 {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>634     fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError> {
635         <Self as private::GetFreeBuffer<'a>>::try_get_free_buffer(self)
636     }
637 }
638 
639 impl<'a, P: BufferHandles, R> GetFreeCaptureBuffer<'a, P> for Queue<Capture, BuffersAllocated<P>>
640 where
641     Self: private::GetFreeBuffer<'a, Queueable = R>,
642     Self: CaptureQueueableProvider<'a, P, Queueable = R>,
643 {
try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError>644     fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetFreeBufferError> {
645         <Self as private::GetFreeBuffer<'a>>::try_get_free_buffer(self)
646     }
647 }
648 
649 /// A fuse that will return the buffer to the Free state when destroyed, unless
650 /// it has been disarmed.
651 struct BufferStateFuse<P: BufferHandles> {
652     buffer_info: Weak<BufferInfo<P>>,
653 }
654 
655 impl<P: BufferHandles> BufferStateFuse<P> {
656     /// Create a new fuse that will set `state` to `BufferState::Free` if
657     /// destroyed before `disarm()` has been called.
new(buffer_info: Weak<BufferInfo<P>>) -> Self658     fn new(buffer_info: Weak<BufferInfo<P>>) -> Self {
659         BufferStateFuse { buffer_info }
660     }
661 
662     /// Disarm this fuse, e.g. the monitored state will be left untouched when
663     /// the fuse is destroyed.
disarm(&mut self)664     fn disarm(&mut self) {
665         // Drop our weak reference.
666         self.buffer_info = Weak::new();
667     }
668 
669     /// Trigger the fuse, i.e. make the buffer return to the Free state, unless the fuse has been
670     /// `disarm`ed or the buffer freed. This method should only be called when the reference to the
671     /// buffer is being dropped, otherwise inconsistent state may ensue. The fuse will be disarmed
672     /// after this call.
trigger(&mut self)673     fn trigger(&mut self) {
674         match self.buffer_info.upgrade() {
675             None => (),
676             Some(buffer_info) => {
677                 buffer_info.update_state(|state| *state = BufferState::Free);
678                 self.disarm();
679             }
680         };
681     }
682 }
683 
684 impl<P: BufferHandles> Drop for BufferStateFuse<P> {
drop(&mut self)685     fn drop(&mut self) {
686         self.trigger();
687     }
688 }
689