Skip to main content

rust_stdf/
stdf_error.rs

1//
2// stdf_error.rs
3// Author: noonchen - chennoon233@foxmail.com
4// Created Date: October 3rd 2022
5// -----
6// Last Modified: Mon Nov 14 2022
7// Modified By: noonchen
8// -----
9// Copyright (c) 2022 noonchen
10//
11
12use std::fmt;
13use std::io::{self, ErrorKind};
14#[cfg(feature = "zipfile")]
15use zip::result::ZipError;
16
17#[derive(Debug)]
18pub struct StdfError {
19    pub code: u8,
20    pub msg: String,
21}
22
23/// Category of an [`StdfError`], returned by [`StdfError::kind`].
24///
25/// `#[non_exhaustive]`: `match` arms must include a `_` fallback.
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27#[repr(u8)]
28#[non_exhaustive]
29pub enum StdfErrorKind {
30    InvalidStdfFile = 1,
31    InvalidRecordType = 2,
32    Io = 3,
33    Eof = 4,
34    UnexpectedEof = 5,
35    NonAscii = 6,
36    InvalidAtdfFile = 7,
37    #[cfg(feature = "zipfile")]
38    Zip = 8,
39    InvalidLength = 9,
40    CountMismatch = 10,
41    WidthMismatch = 11,
42    InvalidOptionalOrder = 12,
43    InvalidValue = 13,
44    RecordTooLarge = 14,
45    ByteOrderMismatch = 15,
46    Unknown = 255,
47}
48
49impl StdfErrorKind {
50    pub(crate) fn from_u8(code: u8) -> Self {
51        match code {
52            1 => Self::InvalidStdfFile,
53            2 => Self::InvalidRecordType,
54            3 => Self::Io,
55            4 => Self::Eof,
56            5 => Self::UnexpectedEof,
57            6 => Self::NonAscii,
58            7 => Self::InvalidAtdfFile,
59            #[cfg(feature = "zipfile")]
60            8 => Self::Zip,
61            9 => Self::InvalidLength,
62            10 => Self::CountMismatch,
63            11 => Self::WidthMismatch,
64            12 => Self::InvalidOptionalOrder,
65            13 => Self::InvalidValue,
66            14 => Self::RecordTooLarge,
67            15 => Self::ByteOrderMismatch,
68            _ => Self::Unknown,
69        }
70    }
71}
72
73impl StdfError {
74    pub(crate) fn new(kind: StdfErrorKind, msg: impl Into<String>) -> Self {
75        Self {
76            code: kind as u8,
77            msg: msg.into(),
78        }
79    }
80
81    /// Returns the structured [`StdfErrorKind`] category for this error,
82    /// falling back to [`StdfErrorKind::Unknown`] for an unrecognized code.
83    pub fn kind(&self) -> StdfErrorKind {
84        StdfErrorKind::from_u8(self.code)
85    }
86}
87
88impl fmt::Display for StdfError {
89    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90        let short_msg = match StdfErrorKind::from_u8(self.code) {
91            StdfErrorKind::InvalidStdfFile => "Invalid STDF File",
92            StdfErrorKind::InvalidRecordType => "Invalid Record Type",
93            StdfErrorKind::Io => "IO Error",
94            StdfErrorKind::Eof => "EOF",
95            StdfErrorKind::UnexpectedEof => "Unexpected EOF",
96            StdfErrorKind::NonAscii => "Non-ASCII Found",
97            StdfErrorKind::InvalidAtdfFile => "Invalid ATDF File",
98            #[cfg(feature = "zipfile")]
99            StdfErrorKind::Zip => "Zip related",
100            StdfErrorKind::InvalidLength => "Invalid Length",
101            StdfErrorKind::CountMismatch => "Field Count Mismatch",
102            StdfErrorKind::WidthMismatch => "Field Width Mismatch",
103            StdfErrorKind::InvalidOptionalOrder => "Invalid Optional Field Order",
104            StdfErrorKind::InvalidValue => "Invalid Value",
105            StdfErrorKind::RecordTooLarge => "Record Too Large",
106            StdfErrorKind::ByteOrderMismatch => "Byte Order Mismatch",
107            StdfErrorKind::Unknown => "Unknown error",
108        };
109        write!(f, "{}, {}", short_msg, self.msg)
110    }
111}
112
113impl From<io::Error> for StdfError {
114    fn from(error: io::Error) -> Self {
115        match error.kind() {
116            ErrorKind::UnexpectedEof => {
117                StdfError::new(StdfErrorKind::Eof, String::from("End of file detected"))
118            }
119            _ => StdfError::new(StdfErrorKind::Io, format!("{}, {}", error.kind(), error)),
120        }
121    }
122}
123
124#[cfg(feature = "zipfile")]
125impl From<ZipError> for StdfError {
126    fn from(error: ZipError) -> Self {
127        match error {
128            ZipError::Io(err) => StdfError::new(StdfErrorKind::Io, err.to_string()),
129            _ => StdfError::new(StdfErrorKind::Zip, error.to_string()),
130        }
131    }
132}