1use std::error::Error;
4use std::fmt;
5use std::io;
6use std::num::{ParseFloatError, ParseIntError};
7
8pub type ObjResult<T> = Result<T, ObjError>;
14
15#[derive(Debug)]
17pub enum ObjError {
18 Io(io::Error),
20 ParseInt(ParseIntError),
22 ParseFloat(ParseFloatError),
24 Load(LoadError),
26}
27
28macro_rules! implmnt {
29 ($name:ident, $error:path) => {
30 impl From<$error> for ObjError {
31 fn from(err: $error) -> Self {
32 ObjError::$name(err)
33 }
34 }
35 };
36}
37
38impl fmt::Display for ObjError {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 ObjError::Io(ref e) => e.fmt(f),
42 ObjError::ParseInt(ref e) => e.fmt(f),
43 ObjError::ParseFloat(ref e) => e.fmt(f),
44 ObjError::Load(ref e) => e.fmt(f),
45 }
46 }
47}
48
49impl Error for ObjError {
50 fn cause(&self) -> Option<&dyn Error> {
51 match *self {
52 ObjError::Io(ref err) => Some(err),
53 ObjError::ParseInt(ref err) => Some(err),
54 ObjError::ParseFloat(ref err) => Some(err),
55 ObjError::Load(ref err) => Some(err),
56 }
57 }
58}
59
60implmnt!(Io, io::Error);
61implmnt!(ParseInt, ParseIntError);
62implmnt!(ParseFloat, ParseFloatError);
63implmnt!(Load, LoadError);
64
65#[derive(PartialEq, Eq, Clone, Debug)]
67pub struct LoadError {
68 kind: LoadErrorKind,
69 message: String,
70}
71
72impl LoadError {
73 pub fn kind(&self) -> &LoadErrorKind {
75 &self.kind
76 }
77}
78
79#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
81pub enum LoadErrorKind {
82 UnexpectedStatement,
84 WrongNumberOfArguments,
86 WrongTypeOfArguments,
88 UntriangulatedModel,
90 InsufficientData,
92 IndexOutOfRange,
94 BackslashAtEOF,
96 TooBigGroupNumber,
98}
99
100impl LoadError {
101 #[deprecated(
103 since = "0.7.4",
104 note = "You shouldn’t need to create a LoadError instance on your own."
105 )]
106 pub fn new(kind: LoadErrorKind, message: &'static str) -> Self {
107 let message = message.to_string();
108 LoadError { kind, message }
109 }
110
111 pub(crate) fn new_internal(kind: LoadErrorKind, message: String) -> Self {
112 LoadError { kind, message }
113 }
114}
115
116impl Error for LoadError {}
117
118impl fmt::Display for LoadError {
119 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
120 use LoadErrorKind::*;
121
122 let msg = match self.kind {
123 UnexpectedStatement => "Met unexpected statement",
124 WrongNumberOfArguments => "Received wrong number of arguments",
125 WrongTypeOfArguments => "Received unexpected type of arguments",
126 UntriangulatedModel => "Model should be triangulated first to be loaded properly",
127 InsufficientData => "Model cannot be transformed into requested form",
128 IndexOutOfRange => "Received index value out of range",
129 BackslashAtEOF => r"A line is expected after the backslash (\)",
130 TooBigGroupNumber => "Group number exceeded limitation.",
131 };
132
133 write!(fmt, "{}: {}", msg, self.message)
134 }
135}
136
137macro_rules! make_error {
138 ($kind:ident, $message:expr) => {
139 return Err($crate::error::ObjError::Load(
140 $crate::error::LoadError::new_internal(
141 $crate::error::LoadErrorKind::$kind,
142 $message.to_string(),
143 ),
144 ))
145 };
146}
147
148pub(crate) use make_error;
149
150pub(super) fn index_out_of_range<T, I>(index: usize) -> ObjResult<T> {
151 let name = std::any::type_name::<I>();
152 Err(ObjError::Load(LoadError {
153 kind: LoadErrorKind::IndexOutOfRange,
154 message: format!(
155 "Given index type '{name}' is not large enough to contain the index '{index}'"
156 ),
157 }))
158}