round_pipers 0.2.0

A way to pipe ndarrays using circular buffers
Documentation
//! Error types for the round_pipers library
//!
//! This module defines all error types using thiserror

use thiserror::Error;
use uuid::Uuid;

/// Main error type for round_pipers operations
#[derive(Error, Debug)]
pub enum PipeError {
    /// Resource management errors
    #[error("Writer already acquired for pipe '{pipe_name}' - only one writer allowed")]
    WriterAlreadyAcquired { pipe_name: String },

    #[error("Reader {reader_id} not registered with pipe '{pipe_name}'")]
    ReaderNotRegistered { reader_id: Uuid, pipe_name: String },

    #[error("Reader {reader_id} not registered with read-only pipe")]
    ReadOnlyReaderNotRegistered { reader_id: Uuid },

    /// Capacity and bounds errors
    #[error("Buffer capacity exceeded on pipe '{pipe_name}': trying to write {requested} elements into buffer capable of holding {capacity}")]
    WriteCapacityExceeded {
        pipe_name: String,
        requested: usize,
        capacity: usize,
    },

    #[error("Buffer capacity exceeded on pipe '{pipe_name}': trying to read {requested} elements into buffer capable of holding {capacity}")]
    ReadCapacityExceeded {
        pipe_name: String,
        requested: usize,
        capacity: usize,
    },

    #[error("{context}: not enough data. Requested {requested} elements from position {position}, but only {available} elements total")]
    InsufficientData {
        context: String,
        requested: usize,
        position: usize,
        available: usize,
    },

    #[error("Array bounds error: trying to access indices {start_idx}..{end_idx} in slice of length {slice_len}")]
    ArrayBoundsError {
        start_idx: usize,
        end_idx: usize,
        slice_len: usize,
    },

    /// Type size errors
    #[error(
        "Buffer size {buffer_size} is not divisible by type size {type_size} for type {type_name}"
    )]
    TypeSizeMismatch {
        buffer_size: usize,
        type_size: usize,
        type_name: String,
    },

    /// Pipeline state errors
    #[error("Writer dropped on pipe '{pipe_name}' and there isn't enough data to meet the request of {requested} elements")]
    WriterDroppedInsufficientData { pipe_name: String, requested: usize },

    #[error("Writer dropped on pipe '{pipe_name}'. Pipe shouldn't be written to any more")]
    WriterDroppedStillWriting { pipe_name: String },

    #[error("Not enough data remaining")]
    NotEnoughDataRemaining,

    /// System-level and external errors
    #[error("Memory mapping error")]
    MemoryMappingError(#[from] nix::Error),

    #[error("I/O error")]
    IoError(#[from] std::io::Error),

    #[error("Array shape error")]
    ArrayShapeError(#[from] ndarray::ShapeError),

    #[error("String conversion error")]
    StringConversionError(#[from] std::ffi::NulError),

    #[error("Integer conversion error")]
    IntegerConversionError(#[from] std::num::TryFromIntError),

    /// Generic error for unknown cases during migration
    #[error("Other error: {message}")]
    Other { message: String },
}

/// Result type alias for round_pipers operations
pub type Result<T> = std::result::Result<T, PipeError>;

impl PipeError {
    /// Create an InsufficientData error with context
    pub fn insufficient_data(
        context: impl Into<String>,
        requested: usize,
        position: usize,
        available: usize,
    ) -> Self {
        Self::InsufficientData {
            context: context.into(),
            requested,
            position,
            available,
        }
    }

    /// Create an ArrayBoundsError
    pub fn array_bounds_error(start_idx: usize, end_idx: usize, slice_len: usize) -> Self {
        Self::ArrayBoundsError {
            start_idx,
            end_idx,
            slice_len,
        }
    }

    /// Create a TypeSizeMismatch error
    pub fn type_size_mismatch(
        buffer_size: usize,
        type_size: usize,
        type_name: impl Into<String>,
    ) -> Self {
        Self::TypeSizeMismatch {
            buffer_size,
            type_size,
            type_name: type_name.into(),
        }
    }

    /// Check if this error indicates end-of-stream (writer dropped or no more data)
    pub fn is_end_of_stream(&self) -> bool {
        matches!(
            self,
            PipeError::WriterDroppedInsufficientData { .. } | PipeError::NotEnoughDataRemaining
        )
    }

    /// Check if this error indicates insufficient data
    pub fn is_insufficient_data(&self) -> bool {
        matches!(
            self,
            PipeError::InsufficientData { .. }
                | PipeError::WriterDroppedInsufficientData { .. }
                | PipeError::NotEnoughDataRemaining
        )
    }
}