v4l2r 0.0.7

Safe and flexible abstraction over V4L2
Documentation
use crate::{
    device::queue::{
        direction::{Capture, Direction, Output},
        private,
        qbuf::{QBuffer, QueueResult},
        BuffersAllocated, CaptureQueueable, OutputQueueable, Queue, TryGetBufferError,
    },
    memory::DmaBufHandle,
};
use crate::{
    memory::MmapHandle,
    memory::{BufferHandles, MemoryType, UserPtrHandle},
};
use std::{fmt::Debug, fs::File, ops::Deref};

/// Supported memory types for `GenericBufferHandles`.
/// TODO: This should be renamed to "DynamicBufferHandles", and be constructed
/// on-the-fly using a macro.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GenericSupportedMemoryType {
    Mmap,
    UserPtr,
    DmaBuf,
}

impl From<GenericSupportedMemoryType> for MemoryType {
    fn from(mem_type: GenericSupportedMemoryType) -> Self {
        match mem_type {
            GenericSupportedMemoryType::Mmap => MemoryType::Mmap,
            GenericSupportedMemoryType::UserPtr => MemoryType::UserPtr,
            GenericSupportedMemoryType::DmaBuf => MemoryType::DmaBuf,
        }
    }
}

/// Buffer handle capable of holding either MMAP or UserPtr handles. Useful
/// for cases when we want to decide the memory type of a queue at runtime.
#[derive(Debug)]
pub enum GenericBufferHandles {
    Mmap(Vec<MmapHandle>),
    User(Vec<UserPtrHandle<Vec<u8>>>),
    DmaBuf(Vec<DmaBufHandle<File>>),
}

impl From<Vec<MmapHandle>> for GenericBufferHandles {
    fn from(m: Vec<MmapHandle>) -> Self {
        Self::Mmap(m)
    }
}

impl From<Vec<UserPtrHandle<Vec<u8>>>> for GenericBufferHandles {
    fn from(u: Vec<UserPtrHandle<Vec<u8>>>) -> Self {
        Self::User(u)
    }
}

impl From<Vec<DmaBufHandle<File>>> for GenericBufferHandles {
    fn from(d: Vec<DmaBufHandle<File>>) -> Self {
        Self::DmaBuf(d)
    }
}

impl BufferHandles for GenericBufferHandles {
    type SupportedMemoryType = GenericSupportedMemoryType;

    fn len(&self) -> usize {
        match self {
            GenericBufferHandles::Mmap(m) => m.len(),
            GenericBufferHandles::User(u) => u.len(),
            GenericBufferHandles::DmaBuf(d) => d.len(),
        }
    }

    fn fill_v4l2_plane(&self, index: usize, plane: &mut crate::bindings::v4l2_plane) {
        match self {
            GenericBufferHandles::Mmap(m) => m.fill_v4l2_plane(index, plane),
            GenericBufferHandles::User(u) => u.fill_v4l2_plane(index, plane),
            GenericBufferHandles::DmaBuf(d) => d.fill_v4l2_plane(index, plane),
        }
    }
}

/// A QBuffer that holds either MMAP or UserPtr handles, depending on which
/// memory type has been selected for the queue at runtime.
pub enum GenericQBuffer<
    D: Direction,
    Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
> {
    Mmap(QBuffer<D, Vec<MmapHandle>, GenericBufferHandles, Q>),
    User(QBuffer<D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles, Q>),
    DmaBuf(QBuffer<D, Vec<DmaBufHandle<File>>, GenericBufferHandles, Q>),
}

impl<D, Q> From<QBuffer<D, Vec<MmapHandle>, GenericBufferHandles, Q>> for GenericQBuffer<D, Q>
where
    D: Direction,
    Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
{
    fn from(qb: QBuffer<D, Vec<MmapHandle>, GenericBufferHandles, Q>) -> Self {
        GenericQBuffer::Mmap(qb)
    }
}

impl<D, Q> From<QBuffer<D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles, Q>>
    for GenericQBuffer<D, Q>
where
    D: Direction,
    Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
{
    fn from(qb: QBuffer<D, Vec<UserPtrHandle<Vec<u8>>>, GenericBufferHandles, Q>) -> Self {
        GenericQBuffer::User(qb)
    }
}

impl<D, Q> From<QBuffer<D, Vec<DmaBufHandle<File>>, GenericBufferHandles, Q>>
    for GenericQBuffer<D, Q>
where
    D: Direction,
    Q: Deref<Target = Queue<D, BuffersAllocated<GenericBufferHandles>>>,
{
    fn from(qb: QBuffer<D, Vec<DmaBufHandle<File>>, GenericBufferHandles, Q>) -> Self {
        GenericQBuffer::DmaBuf(qb)
    }
}

impl<'a, D: Direction> private::QueueableProvider<'a>
    for Queue<D, BuffersAllocated<GenericBufferHandles>>
{
    type Queueable = GenericQBuffer<D, &'a Self>;
}

impl<'a, D: Direction> private::GetBufferByIndex<'a>
    for Queue<D, BuffersAllocated<GenericBufferHandles>>
{
    fn try_get_buffer(&'a self, index: usize) -> Result<Self::Queueable, TryGetBufferError> {
        let buffer_info = self.try_obtain_buffer(index)?;

        Ok(match self.state.memory_type {
            GenericSupportedMemoryType::Mmap => {
                GenericQBuffer::Mmap(QBuffer::new(self, buffer_info))
            }
            GenericSupportedMemoryType::UserPtr => {
                GenericQBuffer::User(QBuffer::new(self, buffer_info))
            }
            GenericSupportedMemoryType::DmaBuf => {
                GenericQBuffer::DmaBuf(QBuffer::new(self, buffer_info))
            }
        })
    }
}

/// Any CAPTURE GenericQBuffer implements CaptureQueueable.
impl<Q> CaptureQueueable<GenericBufferHandles> for GenericQBuffer<Capture, Q>
where
    Q: Deref<Target = Queue<Capture, BuffersAllocated<GenericBufferHandles>>>,
{
    fn queue_with_handles(
        self,
        handles: GenericBufferHandles,
    ) -> QueueResult<(), GenericBufferHandles> {
        match self {
            GenericQBuffer::Mmap(m) => m.queue_with_handles(handles),
            GenericQBuffer::User(u) => u.queue_with_handles(handles),
            GenericQBuffer::DmaBuf(d) => d.queue_with_handles(handles),
        }
    }
}

/// Any OUTPUT GenericQBuffer implements OutputQueueable.
impl<Q> OutputQueueable<GenericBufferHandles> for GenericQBuffer<Output, Q>
where
    Q: Deref<Target = Queue<Output, BuffersAllocated<GenericBufferHandles>>>,
{
    fn queue_with_handles(
        self,
        handles: GenericBufferHandles,
        bytes_used: &[usize],
    ) -> QueueResult<(), GenericBufferHandles> {
        match self {
            GenericQBuffer::Mmap(m) => m.queue_with_handles(handles, bytes_used),
            GenericQBuffer::User(u) => u.queue_with_handles(handles, bytes_used),
            GenericQBuffer::DmaBuf(d) => d.queue_with_handles(handles, bytes_used),
        }
    }
}