vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
//! Specification and CPU reference for `workgroup.queue_fifo`.

use crate::ir::DataType;
use crate::ops::{AlgebraicLaw, Backend, IntrinsicDescriptor, OpSpec};
use std::collections::VecDeque;

pub const INPUTS: &[DataType] = &[DataType::U32, DataType::U32];
pub const OUTPUTS: &[DataType] = &[DataType::U32, DataType::U32];
pub const LAWS: &[AlgebraicLaw] = &[];

pub const SPEC: OpSpec = OpSpec::intrinsic(
    "workgroup.queue_fifo",
    INPUTS,
    OUTPUTS,
    LAWS,
    wgsl_only,
    IntrinsicDescriptor::new(
        "workgroup_queue_fifo_enqueue",
        "workgroup-sram-atomic-tail",
        crate::ops::cpu_op::structured_intrinsic_cpu,
    ),
);
/// FIFO command status word shared by the CPU oracle and WGSL lowering.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FifoStatus {
    /// Operation completed.
    Ok = 0,
    /// The queue was full before enqueue could reserve a slot.
    Overflow = 1,
    /// The queue was empty before dequeue.
    Underflow = 2,
}
/// Error returned by fallible FIFO operations.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FifoError {
    /// The bounded queue has no remaining capacity.
    Overflow,
    /// The queue contains no value to read.
    Underflow,
}
/// Bounded FIFO queue used as the CPU reference for `workgroup.queue_fifo`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkgroupQueueFifo<T> {
    capacity: usize,
    values: VecDeque<T>,
}
impl<T: Copy> WorkgroupQueueFifo<T> {
    /// Create an empty FIFO queue with a fixed capacity.
    #[must_use]
    pub fn new(capacity: usize) -> Self {
        Self {
            capacity,
            values: VecDeque::with_capacity(capacity),
        }
    }

    /// Enqueue one value at the tail.
    ///
    /// # Errors
    ///
    /// Returns [`FifoError::Overflow`] when `len() == capacity`.
    pub fn enqueue(&mut self, value: T) -> Result<FifoStatus, FifoError> {
        if self.values.len() >= self.capacity {
            return Err(FifoError::Overflow);
        }
        self.values.push_back(value);
        Ok(FifoStatus::Ok)
    }

    /// Dequeue the oldest value from the head.
    ///
    /// # Errors
    ///
    /// Returns [`FifoError::Underflow`] when the queue is empty.
    pub fn dequeue(&mut self) -> Result<T, FifoError> {
        self.values.pop_front().ok_or(FifoError::Underflow)
    }

    /// Return the number of live elements.
    #[must_use]
    pub fn len(&self) -> usize {
        self.values.len()
    }

    /// Return true when the queue contains no values.
    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.values.is_empty()
    }

    /// Return the fixed capacity.
    #[must_use]
    pub fn capacity(&self) -> usize {
        self.capacity
    }
}
pub fn wgsl_only(backend: &Backend) -> bool {
    matches!(backend, Backend::Wgsl)
}