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