ruvix_queue/lib.rs
1//! io_uring-style Ring Buffer IPC for RuVix Cognition Kernel.
2//!
3//! This crate implements the Queue primitive from ADR-087 Section 7. All inter-task
4//! communication in RuVix goes through queues. There are no synchronous IPC calls,
5//! no shared memory without explicit region grants, and no signals.
6//!
7//! # Architecture
8//!
9//! Queues use io_uring-style ring buffers with separate submission (SQ) and
10//! completion (CQ) queues. This enables:
11//!
12//! - **Lock-free operation**: Using atomic head/tail pointers
13//! - **Zero-copy semantics**: When sender and receiver share a region
14//! - **Typed messages**: WIT schema validation at send time
15//! - **Priority support**: Higher priority messages are delivered first
16//!
17//! # Zero-Copy Semantics
18//!
19//! When sender and receiver share a region, `queue_send` places a descriptor
20//! (offset + length) in the ring rather than copying bytes. This is critical
21//! for high-throughput vector streaming where copying 768-dimensional f32
22//! vectors would be prohibitive.
23//!
24//! **TOCTOU Protection**: Only Immutable or AppendOnly regions can use descriptors
25//! (ADR-087 Section 20.5). The kernel rejects descriptors pointing into Slab
26//! regions to prevent time-of-check-to-time-of-use attacks.
27//!
28//! # Example
29//!
30//! ```rust,ignore
31//! use ruvix_queue::{KernelQueue, QueueConfig};
32//! use ruvix_types::MsgPriority;
33//!
34//! // Create a queue
35//! let config = QueueConfig::new(64, 4096); // 64 entries, 4KB max message
36//! let mut queue = KernelQueue::new(config, region_handle)?;
37//!
38//! // Send a message
39//! queue.send(b"hello", MsgPriority::Normal)?;
40//!
41//! // Receive with timeout
42//! let mut buf = [0u8; 4096];
43//! let len = queue.recv(&mut buf, Duration::from_millis(100))?;
44//! ```
45
46#![cfg_attr(not(feature = "std"), no_std)]
47#![deny(unsafe_op_in_unsafe_fn)]
48#![warn(missing_docs)]
49
50#[cfg(feature = "alloc")]
51extern crate alloc;
52
53mod descriptor;
54mod kernel_queue;
55mod ring;
56mod ring_optimized;
57
58pub use descriptor::{MessageDescriptor, DescriptorValidator};
59pub use kernel_queue::{KernelQueue, QueueConfig};
60pub use ring::{RingBuffer, RingEntry, RingStats};
61pub use ring_optimized::{OptimizedRingBuffer, OptimizedRingEntry, OptimizedRingSlot};
62
63use ruvix_types::KernelError;
64
65/// Result type for queue operations.
66pub type Result<T> = core::result::Result<T, KernelError>;
67
68/// Duration type for timeouts (re-export for convenience).
69#[cfg(feature = "std")]
70pub type Duration = std::time::Duration;
71
72/// Duration in nanoseconds for no_std environments.
73#[cfg(not(feature = "std"))]
74#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
75pub struct Duration(u64);
76
77#[cfg(not(feature = "std"))]
78impl Duration {
79 /// Zero duration.
80 pub const ZERO: Self = Self(0);
81
82 /// Maximum duration.
83 pub const MAX: Self = Self(u64::MAX);
84
85 /// Create from nanoseconds.
86 pub const fn from_nanos(nanos: u64) -> Self {
87 Self(nanos)
88 }
89
90 /// Create from microseconds.
91 pub const fn from_micros(micros: u64) -> Self {
92 Self(micros.saturating_mul(1_000))
93 }
94
95 /// Create from milliseconds.
96 pub const fn from_millis(millis: u64) -> Self {
97 Self(millis.saturating_mul(1_000_000))
98 }
99
100 /// Create from seconds.
101 pub const fn from_secs(secs: u64) -> Self {
102 Self(secs.saturating_mul(1_000_000_000))
103 }
104
105 /// Get nanoseconds.
106 pub const fn as_nanos(&self) -> u64 {
107 self.0
108 }
109
110 /// Check if zero.
111 pub const fn is_zero(&self) -> bool {
112 self.0 == 0
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 #[test]
119 fn test_module_compiles() {
120 assert!(true);
121 }
122}