Skip to main content

dbase/
error.rs

1use crate::{CodePageMark, FieldConversionError, FieldInfo};
2use std::string::FromUtf8Error;
3
4#[derive(Debug)]
5#[non_exhaustive]
6pub enum ErrorKind {
7    /// Wrapper of `std::io::Error` to forward any reading/writing error
8    IoError(std::io::Error),
9    /// Wrapper to forward errors whe trying to parse a float from the file
10    ParseFloatError(std::num::ParseFloatError),
11    /// Wrapper to forward errors whe trying to parse an integer value from the file
12    ParseIntError(std::num::ParseIntError),
13    /// The Field as an invalid FieldType
14    InvalidFieldType(char),
15    /// Happens when at least one field is a Memo type
16    /// and the that additional memo file could not be found / was not given
17    MissingMemoFile,
18    /// Something went wrong when we tried to open the associated memo file
19    ErrorOpeningMemoFile(std::io::Error),
20    /// The conversion from a FieldValue to another type could not be made
21    BadConversion(FieldConversionError),
22    /// End of the record, there are no more fields
23    EndOfRecord,
24    /// Not all the fields declared to the writer were given
25    NotEnoughFields,
26    /// More fields than expected were given to the writer
27    TooManyFields,
28    /// The type of the value for the field is not compatible with the
29    /// dbase field's type
30    IncompatibleType,
31    /// The Code Page is not supported
32    UnsupportedCodePage(CodePageMark),
33    /// A string from the database could not be decoded
34    StringDecodeError(DecodeError),
35    /// A string from the database could not be encoded
36    StringEncodeError(EncodeError),
37    Message(String),
38}
39
40/// The error type for this crate
41#[derive(Debug)]
42pub struct Error {
43    pub(crate) record_num: usize,
44    pub(crate) field: Option<FieldInfo>,
45    pub(crate) kind: ErrorKind,
46}
47
48impl Error {
49    pub(crate) fn new(field_error: FieldIOError, current_record: usize) -> Self {
50        Self {
51            record_num: current_record,
52            field: field_error.field,
53            kind: field_error.kind,
54        }
55    }
56
57    pub(crate) fn io_error(error: std::io::Error, current_record: usize) -> Self {
58        Self {
59            record_num: current_record,
60            field: None,
61            kind: ErrorKind::IoError(error),
62        }
63    }
64
65    /// Returns the kind of error that happened
66    pub fn kind(&self) -> &ErrorKind {
67        &self.kind
68    }
69
70    /// Returns the index of record index for which the error occurred
71    ///
72    /// 0 may be the first record or an error that occurred before
73    /// handling the first record (eg: an error reading the header)
74    pub fn record_num(&self) -> usize {
75        self.record_num
76    }
77
78    /// Returns the information of the record field for which the error occurred
79    pub fn field(&self) -> &Option<FieldInfo> {
80        &self.field
81    }
82}
83
84#[derive(Debug)]
85pub struct FieldIOError {
86    pub(crate) field: Option<FieldInfo>,
87    pub(crate) kind: ErrorKind,
88}
89
90impl FieldIOError {
91    pub fn new(kind: ErrorKind, field: Option<FieldInfo>) -> Self {
92        Self { field, kind }
93    }
94
95    pub(crate) fn end_of_record() -> Self {
96        Self {
97            field: None,
98            kind: ErrorKind::EndOfRecord,
99        }
100    }
101
102    pub fn kind(&self) -> &ErrorKind {
103        &self.kind
104    }
105}
106
107impl From<std::io::Error> for ErrorKind {
108    fn from(e: std::io::Error) -> Self {
109        ErrorKind::IoError(e)
110    }
111}
112
113impl From<std::num::ParseFloatError> for ErrorKind {
114    fn from(p: std::num::ParseFloatError) -> Self {
115        ErrorKind::ParseFloatError(p)
116    }
117}
118
119impl From<std::num::ParseIntError> for ErrorKind {
120    fn from(p: std::num::ParseIntError) -> Self {
121        ErrorKind::ParseIntError(p)
122    }
123}
124
125impl From<FieldConversionError> for ErrorKind {
126    fn from(e: FieldConversionError) -> Self {
127        ErrorKind::BadConversion(e)
128    }
129}
130
131impl From<DecodeError> for ErrorKind {
132    fn from(e: DecodeError) -> Self {
133        ErrorKind::StringDecodeError(e)
134    }
135}
136
137impl From<EncodeError> for ErrorKind {
138    fn from(e: EncodeError) -> Self {
139        ErrorKind::StringEncodeError(e)
140    }
141}
142
143impl From<FieldConversionError> for FieldIOError {
144    fn from(e: FieldConversionError) -> Self {
145        FieldIOError::new(ErrorKind::BadConversion(e), None)
146    }
147}
148
149impl std::fmt::Display for Error {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        if let Some(field_info) = &self.field {
152            write!(
153                f,
154                "Error {{ record_num: {}, kind: {}, {} }}",
155                self.record_num, self.kind, field_info
156            )
157        } else {
158            write!(
159                f,
160                "Error {{ record_num: {}, kind: {} }}",
161                self.record_num, self.kind
162            )
163        }
164    }
165}
166
167// impl std::fmt::Display for Error {
168//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169//         write!(f, "{:?}", self)
170//     }
171// }
172
173impl std::error::Error for Error {}
174
175impl std::fmt::Display for ErrorKind {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        match self {
178            ErrorKind::IoError(err) => write!(f, "An I/O error happened: {err}"),
179            ErrorKind::ParseFloatError(err) => {
180                write!(f, "Float value could not be obtained: {err}")
181            }
182            ErrorKind::ParseIntError(err) => {
183                write!(f, "Integer value could not be obtained: {err}")
184            }
185            ErrorKind::InvalidFieldType(c) => {
186                write!(f, "The FieldType code '{c}' is note a valid one")
187            }
188            ErrorKind::MissingMemoFile => write!(f, "The memo file could not be found"),
189            ErrorKind::ErrorOpeningMemoFile(err) => {
190                write!(
191                    f,
192                    "An error occurred when trying to open the memo file: {err}"
193                )
194            }
195            ErrorKind::BadConversion(err) => write!(f, "The convertion cannot be made: {err}"),
196            ErrorKind::EndOfRecord => write!(f, "End of record reached, no more fields left"),
197            ErrorKind::NotEnoughFields => {
198                write!(
199                    f,
200                    "The writer did not expected that many fields for the record"
201                )
202            }
203            ErrorKind::TooManyFields => {
204                write!(f, "The writer expected to write more fields for the record")
205            }
206            ErrorKind::IncompatibleType => write!(f, "The types are not compatible"),
207            ErrorKind::StringDecodeError(err) => {
208                write!(f, "A string from the database could not be decoded: {err}")
209            }
210            ErrorKind::StringEncodeError(err) => {
211                write!(f, "A string from the database could not be encoded: {err}")
212            }
213            ErrorKind::UnsupportedCodePage(code) => {
214                write!(f, "The code page '{code:?}' is not supported")
215            }
216            ErrorKind::Message(ref msg) => write!(f, "{msg}"),
217        }
218    }
219}
220
221impl std::fmt::Display for FieldIOError {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        if let Some(field_info) = &self.field {
224            write!(f, "FieldIOError {{ kind: {}, {} }}", self.kind, field_info)
225        } else {
226            write!(f, "FieldIOError {{ kind: {:?} }}", self.kind)
227        }
228    }
229}
230
231impl std::error::Error for FieldIOError {}
232
233#[derive(Debug)]
234#[non_exhaustive]
235pub enum DecodeError {
236    Message(String),
237    FromUtf8(FromUtf8Error),
238    NotAscii,
239    #[cfg(feature = "yore")]
240    Yore(yore::DecodeError),
241}
242
243impl From<String> for DecodeError {
244    fn from(msg: String) -> Self {
245        Self::Message(msg)
246    }
247}
248
249#[cfg(feature = "yore")]
250impl From<yore::DecodeError> for DecodeError {
251    fn from(e: yore::DecodeError) -> Self {
252        DecodeError::Yore(e)
253    }
254}
255
256impl std::fmt::Display for DecodeError {
257    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258        write!(f, "{self:?}")
259    }
260}
261
262impl std::error::Error for DecodeError {}
263
264#[derive(Debug)]
265#[non_exhaustive]
266pub enum EncodeError {
267    Message(String),
268    #[cfg(feature = "yore")]
269    Yore(yore::EncodeError),
270}
271
272impl From<String> for EncodeError {
273    fn from(msg: String) -> Self {
274        Self::Message(msg)
275    }
276}
277
278#[cfg(feature = "yore")]
279impl From<yore::EncodeError> for EncodeError {
280    fn from(e: yore::EncodeError) -> Self {
281        EncodeError::Yore(e)
282    }
283}
284
285impl std::fmt::Display for EncodeError {
286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287        write!(f, "{self:?}")
288    }
289}
290
291impl std::error::Error for EncodeError {}