ruvix_queue/
descriptor.rs1use ruvix_types::{KernelError, MsgPriority, RegionHandle, RegionPolicy};
8
9use crate::Result;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23#[repr(C)]
24pub struct MessageDescriptor {
25 pub region: RegionHandle,
27 pub offset: u64,
29 pub length: u32,
31 _padding: u32,
33}
34
35impl MessageDescriptor {
36 pub const SIZE: usize = core::mem::size_of::<Self>();
38
39 #[inline]
41 pub const fn new(region: RegionHandle, offset: u64, length: u32) -> Self {
42 Self {
43 region,
44 offset,
45 length,
46 _padding: 0,
47 }
48 }
49
50 #[inline]
52 pub fn is_valid(&self) -> bool {
53 !self.region.is_null() && self.length > 0
54 }
55
56 #[inline]
58 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
59 unsafe { core::mem::transmute(*self) }
61 }
62
63 #[inline]
65 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
66 if bytes.len() < Self::SIZE {
67 return None;
68 }
69
70 let mut arr = [0u8; Self::SIZE];
71 arr.copy_from_slice(&bytes[..Self::SIZE]);
72
73 Some(unsafe { core::mem::transmute(arr) })
75 }
76}
77
78pub struct DescriptorValidator {
83 allow_immutable: bool,
85 allow_append_only: bool,
87}
88
89impl DescriptorValidator {
90 pub const fn new() -> Self {
92 Self {
93 allow_immutable: true,
94 allow_append_only: true,
95 }
96 }
97
98 pub const fn immutable_only() -> Self {
100 Self {
101 allow_immutable: true,
102 allow_append_only: false,
103 }
104 }
105
106 pub fn validate_policy(&self, policy: &RegionPolicy) -> Result<()> {
112 match policy {
113 RegionPolicy::Immutable if self.allow_immutable => Ok(()),
114 RegionPolicy::AppendOnly { .. } if self.allow_append_only => Ok(()),
115 RegionPolicy::Slab { .. } => {
116 Err(KernelError::InvalidDescriptorRegion)
118 }
119 _ => Err(KernelError::InvalidDescriptorRegion),
120 }
121 }
122
123 pub fn validate_bounds(&self, descriptor: &MessageDescriptor, region_size: usize) -> Result<()> {
134 let end = descriptor
135 .offset
136 .checked_add(descriptor.length as u64)
137 .ok_or(KernelError::InvalidArgument)?;
138
139 if end > region_size as u64 {
140 return Err(KernelError::InvalidArgument);
141 }
142
143 Ok(())
144 }
145
146 pub fn validate(
153 &self,
154 descriptor: &MessageDescriptor,
155 policy: &RegionPolicy,
156 region_size: usize,
157 ) -> Result<()> {
158 if !descriptor.is_valid() {
159 return Err(KernelError::InvalidArgument);
160 }
161
162 self.validate_policy(policy)?;
163 self.validate_bounds(descriptor, region_size)?;
164
165 Ok(())
166 }
167}
168
169impl Default for DescriptorValidator {
170 fn default() -> Self {
171 Self::new()
172 }
173}
174
175#[derive(Debug, Clone, Copy)]
177pub struct PrioritizedDescriptor {
178 pub descriptor: MessageDescriptor,
180 pub priority: MsgPriority,
182}
183
184impl PrioritizedDescriptor {
185 #[inline]
187 pub const fn new(descriptor: MessageDescriptor, priority: MsgPriority) -> Self {
188 Self {
189 descriptor,
190 priority,
191 }
192 }
193
194 #[inline]
196 pub const fn with_normal_priority(descriptor: MessageDescriptor) -> Self {
197 Self {
198 descriptor,
199 priority: MsgPriority::Normal,
200 }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use ruvix_types::Handle;
208
209 fn test_region() -> RegionHandle {
210 RegionHandle(Handle::new(1, 0))
211 }
212
213 #[test]
214 fn test_descriptor_size() {
215 assert_eq!(MessageDescriptor::SIZE, 24);
217 }
218
219 #[test]
220 fn test_descriptor_roundtrip() {
221 let desc = MessageDescriptor::new(test_region(), 100, 256);
222 let bytes = desc.to_bytes();
223 let recovered = MessageDescriptor::from_bytes(&bytes).unwrap();
224
225 assert_eq!(desc.region, recovered.region);
226 assert_eq!(desc.offset, recovered.offset);
227 assert_eq!(desc.length, recovered.length);
228 }
229
230 #[test]
231 fn test_descriptor_validation_null() {
232 let desc = MessageDescriptor::new(RegionHandle::null(), 0, 100);
233 assert!(!desc.is_valid());
234 }
235
236 #[test]
237 fn test_descriptor_validation_zero_length() {
238 let desc = MessageDescriptor::new(test_region(), 0, 0);
239 assert!(!desc.is_valid());
240 }
241
242 #[test]
243 fn test_validator_immutable_ok() {
244 let validator = DescriptorValidator::new();
245 let result = validator.validate_policy(&RegionPolicy::Immutable);
246 assert!(result.is_ok());
247 }
248
249 #[test]
250 fn test_validator_append_only_ok() {
251 let validator = DescriptorValidator::new();
252 let result = validator.validate_policy(&RegionPolicy::AppendOnly { max_size: 1024 });
253 assert!(result.is_ok());
254 }
255
256 #[test]
257 fn test_validator_slab_rejected() {
258 let validator = DescriptorValidator::new();
259 let result = validator.validate_policy(&RegionPolicy::Slab {
260 slot_size: 64,
261 slot_count: 16,
262 });
263 assert!(matches!(result, Err(KernelError::InvalidDescriptorRegion)));
264 }
265
266 #[test]
267 fn test_validator_bounds() {
268 let validator = DescriptorValidator::new();
269 let desc = MessageDescriptor::new(test_region(), 100, 256);
270
271 assert!(validator.validate_bounds(&desc, 500).is_ok());
273
274 assert!(validator.validate_bounds(&desc, 356).is_ok());
276
277 assert!(validator.validate_bounds(&desc, 355).is_err());
279 }
280
281 #[test]
282 fn test_validator_bounds_overflow() {
283 let validator = DescriptorValidator::new();
284 let desc = MessageDescriptor::new(test_region(), u64::MAX - 10, 100);
285
286 assert!(validator.validate_bounds(&desc, 1000).is_err());
288 }
289
290 #[test]
291 fn test_full_validation() {
292 let validator = DescriptorValidator::new();
293 let desc = MessageDescriptor::new(test_region(), 100, 256);
294
295 assert!(validator
297 .validate(&desc, &RegionPolicy::Immutable, 500)
298 .is_ok());
299
300 assert!(validator
302 .validate(
303 &desc,
304 &RegionPolicy::Slab {
305 slot_size: 64,
306 slot_count: 16
307 },
308 500
309 )
310 .is_err());
311 }
312
313 #[test]
314 fn test_immutable_only_validator() {
315 let validator = DescriptorValidator::immutable_only();
316
317 assert!(validator.validate_policy(&RegionPolicy::Immutable).is_ok());
319
320 assert!(validator
322 .validate_policy(&RegionPolicy::AppendOnly { max_size: 1024 })
323 .is_err());
324 }
325}