Skip to main content

pagers_core/
error.rs

1use std::{num::TryFromIntError, path::PathBuf};
2
3#[derive(Debug, thiserror::Error)]
4pub enum Error {
5    #[error("{context}: {source}")]
6    Io {
7        context: String,
8        source: std::io::Error,
9    },
10
11    #[error("{0}")]
12    Syscall(#[from] nix::errno::Errno),
13
14    #[error("{0}")]
15    TryFromInt(#[from] TryFromIntError),
16
17    #[cfg(feature = "rayon")]
18    #[error("{0}")]
19    ThreadPool(#[from] rayon::ThreadPoolBuildError),
20
21    #[error("{path}: offset {offset} beyond file size {file_len}")]
22    OffsetBeyondFile {
23        path: PathBuf,
24        offset: u64,
25        file_len: u64,
26    },
27}
28
29impl Error {
30    pub fn io(context: impl Into<String>, source: std::io::Error) -> Self {
31        Self::Io {
32            context: context.into(),
33            source,
34        }
35    }
36}
37
38impl From<std::io::Error> for Error {
39    fn from(source: std::io::Error) -> Self {
40        Self::Io {
41            context: String::new(),
42            source,
43        }
44    }
45}
46
47pub type Result<T> = std::result::Result<T, Error>;
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn test_io_error_display_with_context() {
55        let err = Error::io(
56            "/tmp/test.dat",
57            std::io::Error::new(std::io::ErrorKind::NotFound, "file not found"),
58        );
59        let msg = err.to_string();
60        assert!(msg.contains("/tmp/test.dat"), "msg: {msg}");
61        assert!(msg.contains("file not found"), "msg: {msg}");
62    }
63
64    #[test]
65    fn test_io_error_from_std() {
66        let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "denied");
67        let err: Error = io_err.into();
68        assert!(matches!(err, Error::Io { .. }));
69    }
70
71    #[test]
72    fn test_syscall_error_from_errno() {
73        let err: Error = nix::errno::Errno::EBADF.into();
74        assert!(matches!(err, Error::Syscall(_)));
75        assert!(err.to_string().contains("EBADF"));
76    }
77
78    #[test]
79    fn test_offset_beyond_file_display() {
80        let err = Error::OffsetBeyondFile {
81            path: PathBuf::from("/data/big.bin"),
82            offset: 1000,
83            file_len: 500,
84        };
85        let msg = err.to_string();
86        assert!(msg.contains("/data/big.bin"), "msg: {msg}");
87        assert!(msg.contains("1000"), "msg: {msg}");
88        assert!(msg.contains("500"), "msg: {msg}");
89    }
90}