Skip to main content

zenith_linux/
error.rs

1//! Zenith Linux 错误类型
2//!
3//! 统一的错误处理体系,覆盖 AF_XDP、UMEM、Ring、描述符校验等操作
4
5use std::fmt;
6
7/// Linux 平台操作错误
8#[derive(Debug)]
9pub enum LinuxError {
10    /// AF_XDP 操作错误
11    Xsk(XskError),
12    /// UMEM 操作错误
13    Umem(UmemError),
14    /// Ring 操作错误
15    Ring(RingError),
16    /// 描述符校验错误
17    Descriptor(DescriptorError),
18    /// 系统调用错误
19    Syscall {
20        /// 系统调用名称
21        syscall: &'static str,
22        /// errno
23        errno: i32,
24    },
25    /// 资源不足
26    InsufficientResources(String),
27    /// 不支持的操作
28    Unsupported(String),
29}
30
31impl fmt::Display for LinuxError {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        match self {
34            LinuxError::Xsk(e) => write!(f, "AF_XDP error: {}", e),
35            LinuxError::Umem(e) => write!(f, "UMEM error: {}", e),
36            LinuxError::Ring(e) => write!(f, "Ring error: {}", e),
37            LinuxError::Descriptor(e) => write!(f, "Descriptor error: {}", e),
38            LinuxError::Syscall { syscall, errno } => {
39                write!(f, "Syscall '{}' failed with errno {}", syscall, errno)
40            }
41            LinuxError::InsufficientResources(msg) => {
42                write!(f, "Insufficient resources: {}", msg)
43            }
44            LinuxError::Unsupported(msg) => write!(f, "Unsupported: {}", msg),
45        }
46    }
47}
48
49impl std::error::Error for LinuxError {}
50
51impl From<XskError> for LinuxError {
52    fn from(e: XskError) -> Self {
53        LinuxError::Xsk(e)
54    }
55}
56
57impl From<UmemError> for LinuxError {
58    fn from(e: UmemError) -> Self {
59        LinuxError::Umem(e)
60    }
61}
62
63impl From<RingError> for LinuxError {
64    fn from(e: RingError) -> Self {
65        LinuxError::Ring(e)
66    }
67}
68
69impl From<DescriptorError> for LinuxError {
70    fn from(e: DescriptorError) -> Self {
71        LinuxError::Descriptor(e)
72    }
73}
74
75/// AF_XDP 操作错误
76#[derive(Debug)]
77pub enum XskError {
78    /// Socket 创建失败
79    SocketCreate(String),
80    /// Socket 选项设置失败
81    SocketOption(String),
82    /// Bind 失败
83    BindFailed(String),
84    /// 队列不存在
85    QueueNotFound(u32),
86    /// XSK 已绑定
87    AlreadyBound,
88    /// XSK 未绑定
89    NotBound,
90    /// XSK 关闭失败
91    CloseFailed(String),
92    /// 唤醒内核轮询失败(XDP_RING_NEED_WAKEUP 路径的 sendto/notify 失败)
93    NotifyFailed(String),
94    /// 描述符无效
95    InvalidDescriptor(u64),
96    /// 状态迁移非法(当前状态 → 期望状态)
97    InvalidState(String),
98}
99
100impl fmt::Display for XskError {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        match self {
103            XskError::SocketCreate(msg) => write!(f, "Socket creation failed: {}", msg),
104            XskError::SocketOption(msg) => write!(f, "Socket option failed: {}", msg),
105            XskError::BindFailed(msg) => write!(f, "Bind failed: {}", msg),
106            XskError::QueueNotFound(q) => write!(f, "Queue not found: {}", q),
107            XskError::AlreadyBound => write!(f, "XSK already bound"),
108            XskError::NotBound => write!(f, "XSK not bound"),
109            XskError::CloseFailed(msg) => write!(f, "Close failed: {}", msg),
110            XskError::NotifyFailed(msg) => write!(f, "XSK wakeup notify failed: {}", msg),
111            XskError::InvalidDescriptor(d) => write!(f, "Invalid descriptor: {}", d),
112            XskError::InvalidState(msg) => write!(f, "Invalid XSK state: {}", msg),
113        }
114    }
115}
116
117impl std::error::Error for XskError {}
118
119/// UMEM 操作错误
120#[derive(Debug)]
121pub enum UmemError {
122    /// mmap 失败
123    MmapFailed(String),
124    /// 内存锁定失败
125    LockFailed(String),
126    /// 内存地址未对齐
127    NotAligned {
128        /// 实际对齐
129        actual: usize,
130        /// 期望对齐
131        expected: usize,
132    },
133    /// 内存大小不足
134    InsufficientSize {
135        /// 实际大小
136        actual: usize,
137        /// 需要大小
138        required: usize,
139    },
140    /// HugePage 不可用
141    HugePageNotAvailable,
142    /// UMEM 已创建
143    AlreadyCreated,
144    /// UMEM 未创建
145    NotCreated,
146    /// munmap 失败
147    MunmapFailed(String),
148}
149
150impl fmt::Display for UmemError {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        match self {
153            UmemError::MmapFailed(msg) => write!(f, "mmap failed: {}", msg),
154            UmemError::LockFailed(msg) => write!(f, "mlock failed: {}", msg),
155            UmemError::NotAligned { actual, expected } => {
156                write!(f, "Memory not aligned: actual {}, expected {}", actual, expected)
157            }
158            UmemError::InsufficientSize { actual, required } => {
159                write!(
160                    f,
161                    "Insufficient memory: actual {} bytes, required {} bytes",
162                    actual, required
163                )
164            }
165            UmemError::HugePageNotAvailable => write!(f, "HugePage not available"),
166            UmemError::AlreadyCreated => write!(f, "UMEM already created"),
167            UmemError::NotCreated => write!(f, "UMEM not created"),
168            UmemError::MunmapFailed(msg) => write!(f, "munmap failed: {}", msg),
169        }
170    }
171}
172
173impl std::error::Error for UmemError {}
174
175/// Ring 操作错误
176#[derive(Debug)]
177pub enum RingError {
178    /// Ring 已满
179    RingFull,
180    /// Ring 已空
181    RingEmpty,
182    /// 描述符无效
183    InvalidDescriptor(u64),
184    /// 索引越界
185    IndexOutOfBounds {
186        /// 索引
187        index: u32,
188        /// 容量
189        capacity: u32,
190    },
191    /// 生产者/消费者冲突
192    ProducerConsumerConflict,
193    /// 批量大小超出
194    BatchSizeExceeded {
195        /// 请求大小
196        requested: u32,
197        /// 最大允许
198        maximum: u32,
199    },
200    /// Ring 偏移/长度非法
201    InvalidOffsets(String),
202}
203
204impl fmt::Display for RingError {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        match self {
207            RingError::RingFull => write!(f, "Ring is full"),
208            RingError::RingEmpty => write!(f, "Ring is empty"),
209            RingError::InvalidDescriptor(d) => write!(f, "Invalid descriptor: {}", d),
210            RingError::IndexOutOfBounds { index, capacity } => {
211                write!(
212                    f,
213                    "Ring index {} out of bounds (capacity {})",
214                    index, capacity
215                )
216            }
217            RingError::ProducerConsumerConflict => {
218                write!(f, "Producer-consumer conflict")
219            }
220            RingError::BatchSizeExceeded { requested, maximum } => {
221                write!(
222                    f,
223                    "Batch size {} exceeded maximum {}",
224                    requested, maximum
225                )
226            }
227            RingError::InvalidOffsets(msg) => write!(f, "Invalid ring offsets: {}", msg),
228        }
229    }
230}
231
232impl std::error::Error for RingError {}
233
234/// 描述符校验错误
235#[derive(Debug)]
236pub enum DescriptorError {
237    /// 描述符为零(无效)
238    ZeroDescriptor,
239    /// 描述符超出范围
240    OutOfRange {
241        /// 描述符值
242        descriptor: u64,
243        /// 最大值
244        max_valid: u64,
245    },
246    /// 描述符已释放
247    AlreadyFreed(u64),
248    /// 描述符已在使用
249    AlreadyInUse(u64),
250    /// 帧已被引擎分配(位图已置位),重复分配会破坏守恒等式(fail-closed)
251    AlreadyAllocated(u64),
252    /// 帧容量超出 20-bit 帧索引域(> 2^20),构造期 fail-closed
253    InvalidCapacity(u64),
254    /// 所有权不匹配
255    OwnershipMismatch {
256        /// 期望所有者
257        expected: u32,
258        /// 实际所有者
259        actual: u32,
260    },
261    /// 代际不匹配
262    GenerationMismatch {
263        /// 期望代际
264        expected: u64,
265        /// 实际代际
266        actual: u64,
267    },
268    /// 帧移位(log2(frame_size))非法
269    ///
270    /// 合法区间 11..=15(帧大小 2048..=32768 字节)。超出区间的移位会使
271    /// `frame_index << frame_shift` 在 debug 触发 shift-overflow panic、
272    /// 在 release 触发移位掩码静默产生错误地址,故必须构造期拒绝(fail-closed)。
273    InvalidFrameShift(u32),
274    /// 事务失败
275    TransactionFailed(String),
276}
277
278impl fmt::Display for DescriptorError {
279    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280        match self {
281            DescriptorError::ZeroDescriptor => write!(f, "Zero descriptor (invalid)"),
282            DescriptorError::OutOfRange {
283                descriptor,
284                max_valid,
285            } => write!(
286                f,
287                "Descriptor {} out of range (max valid: {})",
288                descriptor, max_valid
289            ),
290            DescriptorError::AlreadyFreed(d) => write!(f, "Descriptor {} already freed", d),
291            DescriptorError::AlreadyInUse(d) => write!(f, "Descriptor {} already in use", d),
292            // 字段名不能与 formatter 形参 `f` 同名:别名绑定避免 write! 把
293            // `&u64` 当成输出目标(E0599),也防止数字被静默吞掉。
294            DescriptorError::AlreadyAllocated(frame) => {
295                write!(f, "Frame {} already allocated", frame)
296            }
297            DescriptorError::InvalidCapacity(c) => write!(
298                f,
299                "Descriptor capacity {c} exceeds 20-bit frame index domain (max 2^20 frames)"
300            ),
301            DescriptorError::OwnershipMismatch { expected, actual } => {
302                write!(
303                    f,
304                    "Ownership mismatch: expected {}, actual {}",
305                    expected, actual
306                )
307            }
308            DescriptorError::InvalidFrameShift(shift) => write!(
309                f,
310                "Invalid frame_shift {shift}: must be in 11..=15 (frame size 2048..=32768 bytes)"
311            ),
312            DescriptorError::GenerationMismatch { expected, actual } => {
313                write!(
314                    f,
315                    "Generation mismatch: expected {}, actual {}",
316                    expected, actual
317                )
318            }
319            DescriptorError::TransactionFailed(msg) => {
320                write!(f, "Transaction failed: {}", msg)
321            }
322        }
323    }
324}
325
326impl std::error::Error for DescriptorError {}
327
328/// 结果类型别名
329pub type Result<T> = std::result::Result<T, LinuxError>;
330
331// 错误严重级别统一以 zenith-core 为正统(全 workspace 唯一定义):
332// 本 crate 不再自有定义,re-export 保持 `zenith_linux::error::ErrorSeverity` 路径兼容。
333// 语义映射:原 `Fatal`(致命级,系统不可用)→ `ErrorSeverity::Critical`。
334pub use zenith_foundation::error::ErrorSeverity;
335
336impl LinuxError {
337    /// 获取错误严重级别
338    pub fn severity(&self) -> ErrorSeverity {
339        match self {
340            LinuxError::Syscall { .. } => ErrorSeverity::Error,
341            LinuxError::InsufficientResources(_) => ErrorSeverity::Critical,
342            LinuxError::Unsupported(_) => ErrorSeverity::Critical,
343            LinuxError::Xsk(e) => e.severity(),
344            LinuxError::Umem(e) => e.severity(),
345            LinuxError::Ring(e) => e.severity(),
346            LinuxError::Descriptor(e) => e.severity(),
347        }
348    }
349
350    /// 是否为系统调用错误
351    pub fn is_syscall_error(&self) -> bool {
352        matches!(self, LinuxError::Syscall { .. })
353    }
354
355    /// 是否为配置错误
356    pub fn is_config_error(&self) -> bool {
357        matches!(
358            self,
359            LinuxError::Xsk(XskError::SocketOption(_))
360                | LinuxError::Umem(UmemError::NotAligned { .. })
361                | LinuxError::Umem(UmemError::InsufficientSize { .. })
362                | LinuxError::Ring(RingError::BatchSizeExceeded { .. })
363                | LinuxError::Descriptor(DescriptorError::OutOfRange { .. })
364        )
365    }
366
367    /// 是否为资源错误
368    pub fn is_resource_error(&self) -> bool {
369        matches!(
370            self,
371            LinuxError::InsufficientResources(_)
372                | LinuxError::Umem(UmemError::MmapFailed(_))
373                | LinuxError::Umem(UmemError::LockFailed(_))
374                | LinuxError::Ring(RingError::RingFull)
375                | LinuxError::Ring(RingError::RingEmpty)
376        )
377    }
378}
379
380impl XskError {
381    /// 获取错误严重级别
382    pub fn severity(&self) -> ErrorSeverity {
383        match self {
384            XskError::SocketCreate(_) => ErrorSeverity::Critical,
385            XskError::SocketOption(_) => ErrorSeverity::Error,
386            XskError::BindFailed(_) => ErrorSeverity::Error,
387            XskError::QueueNotFound(_) => ErrorSeverity::Warning,
388            XskError::AlreadyBound => ErrorSeverity::Warning,
389            XskError::NotBound => ErrorSeverity::Warning,
390            XskError::CloseFailed(_) => ErrorSeverity::Warning,
391            XskError::NotifyFailed(_) => ErrorSeverity::Error,
392            XskError::InvalidDescriptor(_) => ErrorSeverity::Error,
393            XskError::InvalidState(_) => ErrorSeverity::Warning,
394        }
395    }
396}
397
398impl UmemError {
399    /// 获取错误严重级别
400    pub fn severity(&self) -> ErrorSeverity {
401        match self {
402            UmemError::MmapFailed(_) => ErrorSeverity::Critical,
403            UmemError::LockFailed(_) => ErrorSeverity::Error,
404            UmemError::NotAligned { .. } => ErrorSeverity::Error,
405            UmemError::InsufficientSize { .. } => ErrorSeverity::Error,
406            UmemError::HugePageNotAvailable => ErrorSeverity::Warning,
407            UmemError::AlreadyCreated => ErrorSeverity::Warning,
408            UmemError::NotCreated => ErrorSeverity::Warning,
409            UmemError::MunmapFailed(_) => ErrorSeverity::Warning,
410        }
411    }
412}
413
414impl RingError {
415    /// 获取错误严重级别
416    pub fn severity(&self) -> ErrorSeverity {
417        match self {
418            RingError::RingFull => ErrorSeverity::Warning,
419            RingError::RingEmpty => ErrorSeverity::Info,
420            RingError::InvalidDescriptor(_) => ErrorSeverity::Error,
421            RingError::IndexOutOfBounds { .. } => ErrorSeverity::Error,
422            RingError::ProducerConsumerConflict => ErrorSeverity::Critical,
423            RingError::BatchSizeExceeded { .. } => ErrorSeverity::Warning,
424            RingError::InvalidOffsets(_) => ErrorSeverity::Error,
425        }
426    }
427}
428
429impl DescriptorError {
430    /// 获取错误严重级别
431    pub fn severity(&self) -> ErrorSeverity {
432        match self {
433            DescriptorError::ZeroDescriptor => ErrorSeverity::Error,
434            DescriptorError::OutOfRange { .. } => ErrorSeverity::Error,
435            DescriptorError::AlreadyFreed(_) => ErrorSeverity::Warning,
436            DescriptorError::AlreadyInUse(_) => ErrorSeverity::Warning,
437            DescriptorError::AlreadyAllocated(_) => ErrorSeverity::Warning,
438            DescriptorError::InvalidCapacity(_) => ErrorSeverity::Error,
439            DescriptorError::OwnershipMismatch { .. } => ErrorSeverity::Error,
440            DescriptorError::InvalidFrameShift(_) => ErrorSeverity::Error,
441            DescriptorError::GenerationMismatch { .. } => ErrorSeverity::Warning,
442            DescriptorError::TransactionFailed(_) => ErrorSeverity::Error,
443        }
444    }
445}
446
447impl From<LinuxError> for std::io::Error {
448    fn from(err: LinuxError) -> Self {
449        match err {
450            LinuxError::Syscall { errno, .. } => std::io::Error::from_raw_os_error(errno),
451            LinuxError::Umem(UmemError::MmapFailed(msg)) => {
452                std::io::Error::new(std::io::ErrorKind::OutOfMemory, msg)
453            }
454            LinuxError::Umem(UmemError::LockFailed(msg)) => {
455                std::io::Error::new(std::io::ErrorKind::PermissionDenied, msg)
456            }
457            LinuxError::InsufficientResources(msg) => {
458                std::io::Error::new(std::io::ErrorKind::OutOfMemory, msg)
459            }
460            other => std::io::Error::other(other.to_string()),
461        }
462    }
463}
464
465#[cfg(test)]
466mod tests {
467    use super::*;
468
469    #[test]
470    fn test_linux_error_xsk_display() {
471        let err = LinuxError::Xsk(XskError::SocketCreate("test error".to_string()));
472        let display = format!("{}", err);
473        assert!(display.contains("AF_XDP error"));
474        assert!(display.contains("Socket creation failed"));
475        assert!(display.contains("test error"));
476    }
477
478    #[test]
479    fn test_linux_error_umem_display() {
480        let err = LinuxError::Umem(UmemError::MmapFailed("mmap test".to_string()));
481        let display = format!("{}", err);
482        assert!(display.contains("UMEM error"));
483        assert!(display.contains("mmap failed"));
484        assert!(display.contains("mmap test"));
485    }
486
487    #[test]
488    fn test_linux_error_ring_display() {
489        let err = LinuxError::Ring(RingError::RingFull);
490        let display = format!("{}", err);
491        assert!(display.contains("Ring error"));
492        assert!(display.contains("Ring is full"));
493    }
494
495    #[test]
496    fn test_linux_error_descriptor_display() {
497        let err = LinuxError::Descriptor(DescriptorError::ZeroDescriptor);
498        let display = format!("{}", err);
499        assert!(display.contains("Descriptor error"));
500        assert!(display.contains("Zero descriptor"));
501    }
502
503    #[test]
504    fn test_linux_error_syscall_display() {
505        let err = LinuxError::Syscall {
506            syscall: "socket",
507            errno: 13,
508        };
509        let display = format!("{}", err);
510        assert!(display.contains("Syscall 'socket' failed"));
511        assert!(display.contains("errno 13"));
512    }
513
514    #[test]
515    fn test_linux_error_insufficient_resources_display() {
516        let err = LinuxError::InsufficientResources("out of memory".to_string());
517        let display = format!("{}", err);
518        assert!(display.contains("Insufficient resources"));
519        assert!(display.contains("out of memory"));
520    }
521
522    #[test]
523    fn test_linux_error_unsupported_display() {
524        let err = LinuxError::Unsupported("feature not available".to_string());
525        let display = format!("{}", err);
526        assert!(display.contains("Unsupported"));
527        assert!(display.contains("feature not available"));
528    }
529
530    #[test]
531    fn test_xsk_error_variants_display() {
532        let cases = vec![
533            (
534                XskError::SocketCreate("a".to_string()),
535                "Socket creation failed",
536            ),
537            (
538                XskError::SocketOption("b".to_string()),
539                "Socket option failed",
540            ),
541            (XskError::BindFailed("c".to_string()), "Bind failed"),
542            (XskError::QueueNotFound(5), "Queue not found: 5"),
543            (XskError::AlreadyBound, "XSK already bound"),
544            (XskError::NotBound, "XSK not bound"),
545            (XskError::CloseFailed("d".to_string()), "Close failed"),
546            (
547                XskError::NotifyFailed("e".to_string()),
548                "XSK wakeup notify failed",
549            ),
550            (XskError::InvalidDescriptor(42), "Invalid descriptor: 42"),
551        ];
552
553        for (err, expected) in cases {
554            let display = format!("{}", err);
555            assert!(display.contains(expected), "Expected '{}' in '{}'", expected, display);
556        }
557    }
558
559    #[test]
560    fn test_umem_error_variants_display() {
561        let cases = vec![
562            (UmemError::MmapFailed("a".to_string()), "mmap failed"),
563            (UmemError::LockFailed("b".to_string()), "mlock failed"),
564            (
565                UmemError::NotAligned {
566                    actual: 100,
567                    expected: 4096,
568                },
569                "Memory not aligned",
570            ),
571            (
572                UmemError::InsufficientSize {
573                    actual: 100,
574                    required: 200,
575                },
576                "Insufficient memory",
577            ),
578            (UmemError::HugePageNotAvailable, "HugePage not available"),
579            (UmemError::AlreadyCreated, "UMEM already created"),
580            (UmemError::NotCreated, "UMEM not created"),
581            (UmemError::MunmapFailed("c".to_string()), "munmap failed"),
582        ];
583
584        for (err, expected) in cases {
585            let display = format!("{}", err);
586            assert!(display.contains(expected), "Expected '{}' in '{}'", expected, display);
587        }
588    }
589
590    #[test]
591    fn test_ring_error_variants_display() {
592        let cases = vec![
593            (RingError::RingFull, "Ring is full"),
594            (RingError::RingEmpty, "Ring is empty"),
595            (RingError::InvalidDescriptor(123), "Invalid descriptor: 123"),
596            (
597                RingError::IndexOutOfBounds {
598                    index: 10,
599                    capacity: 5,
600                },
601                "Ring index 10 out of bounds",
602            ),
603            (RingError::ProducerConsumerConflict, "Producer-consumer conflict"),
604            (
605                RingError::BatchSizeExceeded {
606                    requested: 100,
607                    maximum: 50,
608                },
609                "Batch size 100 exceeded maximum 50",
610            ),
611        ];
612
613        for (err, expected) in cases {
614            let display = format!("{}", err);
615            assert!(display.contains(expected), "Expected '{}' in '{}'", expected, display);
616        }
617    }
618
619    #[test]
620    fn test_descriptor_error_variants_display() {
621        let cases = vec![
622            (DescriptorError::ZeroDescriptor, "Zero descriptor"),
623            (
624                DescriptorError::OutOfRange {
625                    descriptor: 100,
626                    max_valid: 50,
627                },
628                "Descriptor 100 out of range",
629            ),
630            (DescriptorError::AlreadyFreed(42), "Descriptor 42 already freed"),
631            (DescriptorError::AlreadyInUse(99), "Descriptor 99 already in use"),
632            (
633                DescriptorError::AlreadyAllocated(7),
634                "Frame 7 already allocated",
635            ),
636            (
637                DescriptorError::InvalidCapacity(1 << 21),
638                "exceeds 20-bit frame index domain",
639            ),
640            (
641                DescriptorError::OwnershipMismatch {
642                    expected: 1,
643                    actual: 2,
644                },
645                "Ownership mismatch",
646            ),
647            (
648                DescriptorError::GenerationMismatch {
649                    expected: 3,
650                    actual: 5,
651                },
652                "Generation mismatch",
653            ),
654            (
655                DescriptorError::TransactionFailed("tx fail".to_string()),
656                "Transaction failed",
657            ),
658        ];
659
660        for (err, expected) in cases {
661            let display = format!("{}", err);
662            assert!(display.contains(expected), "Expected '{}' in '{}'", expected, display);
663        }
664    }
665
666    #[test]
667    fn test_error_from_conversions() {
668        let xsk_err = XskError::AlreadyBound;
669        let linux_err: LinuxError = xsk_err.into();
670        assert!(matches!(linux_err, LinuxError::Xsk(XskError::AlreadyBound)));
671
672        let umem_err = UmemError::NotCreated;
673        let linux_err: LinuxError = umem_err.into();
674        assert!(matches!(linux_err, LinuxError::Umem(UmemError::NotCreated)));
675
676        let ring_err = RingError::RingFull;
677        let linux_err: LinuxError = ring_err.into();
678        assert!(matches!(linux_err, LinuxError::Ring(RingError::RingFull)));
679
680        let desc_err = DescriptorError::ZeroDescriptor;
681        let linux_err: LinuxError = desc_err.into();
682        assert!(matches!(
683            linux_err,
684            LinuxError::Descriptor(DescriptorError::ZeroDescriptor)
685        ));
686    }
687
688    #[test]
689    fn test_error_severity() {
690        assert_eq!(
691            LinuxError::Syscall {
692                syscall: "test",
693                errno: 1
694            }
695            .severity(),
696            ErrorSeverity::Error
697        );
698        assert_eq!(
699            LinuxError::InsufficientResources("x".to_string()).severity(),
700            ErrorSeverity::Critical
701        );
702        assert_eq!(
703            LinuxError::Unsupported("x".to_string()).severity(),
704            ErrorSeverity::Critical
705        );
706        assert_eq!(
707            LinuxError::Xsk(XskError::SocketCreate("x".to_string())).severity(),
708            ErrorSeverity::Critical
709        );
710        assert_eq!(
711            LinuxError::Xsk(XskError::QueueNotFound(0)).severity(),
712            ErrorSeverity::Warning
713        );
714        assert_eq!(
715            LinuxError::Umem(UmemError::MmapFailed("x".to_string())).severity(),
716            ErrorSeverity::Critical
717        );
718        assert_eq!(
719            LinuxError::Umem(UmemError::HugePageNotAvailable).severity(),
720            ErrorSeverity::Warning
721        );
722        assert_eq!(
723            LinuxError::Ring(RingError::RingEmpty).severity(),
724            ErrorSeverity::Info
725        );
726        assert_eq!(
727            LinuxError::Ring(RingError::ProducerConsumerConflict).severity(),
728            ErrorSeverity::Critical
729        );
730        assert_eq!(
731            LinuxError::Descriptor(DescriptorError::ZeroDescriptor).severity(),
732            ErrorSeverity::Error
733        );
734        assert_eq!(
735            LinuxError::Descriptor(DescriptorError::AlreadyFreed(0)).severity(),
736            ErrorSeverity::Warning
737        );
738    }
739
740    #[test]
741    fn test_error_classification() {
742        let syscall_err = LinuxError::Syscall {
743            syscall: "socket",
744            errno: 1,
745        };
746        assert!(syscall_err.is_syscall_error());
747        assert!(!syscall_err.is_config_error());
748        assert!(!syscall_err.is_resource_error());
749
750        let config_err = LinuxError::Umem(UmemError::NotAligned {
751            actual: 100,
752            expected: 4096,
753        });
754        assert!(!config_err.is_syscall_error());
755        assert!(config_err.is_config_error());
756        assert!(!config_err.is_resource_error());
757
758        let resource_err = LinuxError::InsufficientResources("oom".to_string());
759        assert!(!resource_err.is_syscall_error());
760        assert!(!resource_err.is_config_error());
761        assert!(resource_err.is_resource_error());
762
763        let ring_full = LinuxError::Ring(RingError::RingFull);
764        assert!(ring_full.is_resource_error());
765    }
766
767    #[test]
768    fn test_linux_error_to_io_error() {
769        let syscall_err = LinuxError::Syscall {
770            syscall: "test",
771            errno: 12, // ENOMEM
772        };
773        let io_err: std::io::Error = syscall_err.into();
774        assert_eq!(io_err.raw_os_error(), Some(12));
775
776        let mmap_err = LinuxError::Umem(UmemError::MmapFailed("failed".to_string()));
777        let io_err: std::io::Error = mmap_err.into();
778        assert_eq!(io_err.kind(), std::io::ErrorKind::OutOfMemory);
779
780        let lock_err = LinuxError::Umem(UmemError::LockFailed("denied".to_string()));
781        let io_err: std::io::Error = lock_err.into();
782        assert_eq!(io_err.kind(), std::io::ErrorKind::PermissionDenied);
783
784        let oom_err = LinuxError::InsufficientResources("oom".to_string());
785        let io_err: std::io::Error = oom_err.into();
786        assert_eq!(io_err.kind(), std::io::ErrorKind::OutOfMemory);
787
788        let other_err = LinuxError::Xsk(XskError::AlreadyBound);
789        let io_err: std::io::Error = other_err.into();
790        assert_eq!(io_err.kind(), std::io::ErrorKind::Other);
791    }
792
793    #[test]
794    fn test_error_trait_implementation() {
795        let err: Box<dyn std::error::Error> =
796            Box::new(LinuxError::Syscall {
797                syscall: "test",
798                errno: 1,
799            });
800        assert!(err.source().is_none());
801
802        let err: Box<dyn std::error::Error> = Box::new(XskError::AlreadyBound);
803        assert!(err.source().is_none());
804
805        let err: Box<dyn std::error::Error> = Box::new(UmemError::NotCreated);
806        assert!(err.source().is_none());
807
808        let err: Box<dyn std::error::Error> = Box::new(RingError::RingEmpty);
809        assert!(err.source().is_none());
810
811        let err: Box<dyn std::error::Error> = Box::new(DescriptorError::ZeroDescriptor);
812        assert!(err.source().is_none());
813    }
814
815    #[test]
816    fn test_result_type_alias() {
817        let ok: Result<i32> = Ok(42);
818        assert!(ok.is_ok());
819
820        let err: Result<i32> = Err(LinuxError::Unsupported("test".to_string()));
821        assert!(err.is_err());
822    }
823
824    #[test]
825    fn test_error_debug_format() {
826        let err = LinuxError::Syscall {
827            syscall: "mmap",
828            errno: 12,
829        };
830        let debug = format!("{:?}", err);
831        assert!(debug.contains("Syscall"));
832        assert!(debug.contains("mmap"));
833        assert!(debug.contains("12"));
834    }
835}