fyrox_core/visitor/error.rs
1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Possible errors that may occur during serialization/deserialization.
22
23use crate::io::FileError;
24use crate::visitor::Visitor;
25use base64::DecodeError;
26use std::num::{ParseFloatError, ParseIntError};
27use std::{
28 error::Error,
29 fmt::{Display, Formatter},
30 string::FromUtf8Error,
31};
32
33/// Errors that may occur while reading or writing [`crate::visitor::Visitor`].
34#[derive(Debug)]
35pub enum VisitError {
36 /// An error that occured for multiple reasons, when there are multiple potential ways
37 /// to visit a node, and all of them lead to errors.
38 Multiple(Vec<VisitError>),
39 /// An [std::io::Error] occured while reading or writing a file with Visitor data.
40 Io(std::io::Error),
41 /// When a field is encoded as bytes, the field data is prefixed by an identifying byte
42 /// to allow the bytes to be decoded. This error happens when an identifying byte is
43 /// expected during decoding, but an unknown value is found in that byte.
44 UnknownFieldType(u8),
45 /// Attempting to visit a field on a read-mode Visitor when no field in the visitor data
46 /// has the given name.
47 FieldDoesNotExist(String),
48 /// Attempting to visit a field on a write-mode Visitor when a field already has the
49 /// given name.
50 FieldAlreadyExists(String),
51 /// Attempting to enter a region on a write-mode Visitor when a region already has the
52 /// given name.
53 RegionAlreadyExists(String),
54 /// Current node handle is invalid and does not lead to a real node.
55 InvalidCurrentNode,
56 /// Attempting to visit a field using a read-mode Visitor when that field was originally
57 /// written using a value of a different type.
58 FieldTypeDoesNotMatch {
59 /// expected [`crate::visitor::FieldKind`] variant name, for instance "FieldKind::F64"
60 expected: &'static str,
61 /// Debug representation of actual [`crate::visitor::FieldKind`]
62 actual: String,
63 },
64 /// Attempting to enter a region on a read-mode Visitor when no region in the visitor's data
65 /// has the given name.
66 RegionDoesNotExist(String),
67 /// The Visitor tried to leave is current node, but somehow it had no current node. This should never happen.
68 NoActiveNode,
69 /// The [`crate::Visitor::MAGIC_BINARY_CURRENT`], [`crate::Visitor::MAGIC_ASCII_CURRENT`].
70 /// bytes were missing from the beginning of encoded Visitor data.
71 NotSupportedFormat,
72 /// Some sequence of bytes was not in UTF8 format.
73 InvalidName,
74 /// Visitor data can be self-referential, such as when the data contains multiple `Rc` references
75 /// to a single shared value. This causes the visitor to store the data once and then later references
76 /// to the same value point back to its first occurrence. This error occurs if one of these references
77 /// points to a value of the wrong type.
78 TypeMismatch {
79 /// The type that was visiting when the error occurred.
80 expected: &'static str,
81 /// The type that was stored in the `Rc` or `Arc`.
82 actual: &'static str,
83 },
84 /// Attempting to visit a mutably borrowed RefCell.
85 RefCellAlreadyMutableBorrowed,
86 /// A plain-text error message that could indicate almost anything.
87 User(String),
88 /// `Rc` and `Arc` values store an "Id" value in the Visitor data which is based in their internal pointer.
89 /// This error indicates that while reading this data, one of those Id values was discovered by be 0.
90 UnexpectedRcNullIndex,
91 /// A poison error occurred while trying to visit a mutex.
92 PoisonedMutex,
93 /// A FileLoadError was encountered while trying to decode Visitor data from a file.
94 FileLoadError(FileError),
95 /// Integer parsing error.
96 ParseIntError(ParseIntError),
97 /// Floating point number parsing error.
98 ParseFloatError(ParseFloatError),
99 /// An error occurred when trying to decode base64-encoded data.
100 DecodeError(DecodeError),
101 /// An error occurred when trying to parse uuid from a string.
102 UuidError(uuid::Error),
103 /// Arbitrary error.
104 Any(Box<dyn Error + Send + Sync>),
105}
106
107impl Error for VisitError {}
108
109impl VisitError {
110 /// Create a [`VisitError::FieldDoesNotExist`] containing the given field name and the
111 /// breadcrumbs of the current visitor node.
112 pub fn field_does_not_exist(name: &str, visitor: &Visitor) -> Self {
113 Self::FieldDoesNotExist(visitor.breadcrumbs() + " > " + name)
114 }
115 /// Create an error from two errors.
116 pub fn multiple(self, other: Self) -> Self {
117 match (self, other) {
118 (Self::Multiple(mut a), Self::Multiple(mut b)) => {
119 a.append(&mut b);
120 Self::Multiple(a)
121 }
122 (Self::Multiple(mut a), b) => {
123 a.push(b);
124 Self::Multiple(a)
125 }
126 (a, Self::Multiple(mut b)) => {
127 b.push(a);
128 Self::Multiple(b)
129 }
130 (a, b) => Self::Multiple(vec![a, b]),
131 }
132 }
133}
134
135impl Display for VisitError {
136 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
137 match self {
138 Self::Multiple(errs) => {
139 write!(f, "multiple errors:[")?;
140 for err in errs {
141 write!(f, "{err};")?;
142 }
143 write!(f, "]")
144 }
145 Self::Io(io) => write!(f, "io error: {io}"),
146 Self::UnknownFieldType(type_index) => write!(f, "unknown field type {type_index}"),
147 Self::FieldDoesNotExist(name) => write!(f, "field does not exist: {name}"),
148 Self::FieldAlreadyExists(name) => write!(f, "field already exists {name}"),
149 Self::RegionAlreadyExists(name) => write!(f, "region already exists {name}"),
150 Self::InvalidCurrentNode => write!(f, "invalid current node"),
151 Self::FieldTypeDoesNotMatch { expected, actual } => write!(
152 f,
153 "field type does not match. expected: {expected}, actual: {actual}"
154 ),
155 Self::RegionDoesNotExist(name) => write!(f, "region does not exist: {name}"),
156 Self::NoActiveNode => write!(f, "no active node"),
157 Self::NotSupportedFormat => write!(f, "not supported format"),
158 Self::InvalidName => write!(f, "invalid name"),
159 Self::TypeMismatch { expected, actual } => {
160 write!(f, "type mismatch. expected: {expected}, actual: {actual}")
161 }
162 Self::RefCellAlreadyMutableBorrowed => write!(f, "ref cell already mutable borrowed"),
163 Self::User(msg) => write!(f, "user defined error: {msg}"),
164 Self::UnexpectedRcNullIndex => write!(f, "unexpected rc null index"),
165 Self::PoisonedMutex => write!(f, "attempt to lock poisoned mutex"),
166 Self::FileLoadError(e) => write!(f, "file load error: {e:?}"),
167 Self::ParseIntError(e) => write!(f, "unable to parse integer: {e:?}"),
168 Self::ParseFloatError(e) => write!(f, "unable to parse float: {e:?}"),
169 Self::DecodeError(e) => write!(f, "base64 decoding error: {e:?}"),
170 Self::UuidError(e) => write!(f, "uuid error: {e:?}"),
171 Self::Any(e) => {
172 write!(f, "{e}")
173 }
174 }
175 }
176}
177
178impl<T> From<std::sync::PoisonError<std::sync::MutexGuard<'_, T>>> for VisitError {
179 fn from(_: std::sync::PoisonError<std::sync::MutexGuard<'_, T>>) -> Self {
180 Self::PoisonedMutex
181 }
182}
183
184impl<T> From<std::sync::PoisonError<&mut T>> for VisitError {
185 fn from(_: std::sync::PoisonError<&mut T>) -> Self {
186 Self::PoisonedMutex
187 }
188}
189
190impl<T> From<std::sync::PoisonError<std::sync::RwLockWriteGuard<'_, T>>> for VisitError {
191 fn from(_: std::sync::PoisonError<std::sync::RwLockWriteGuard<'_, T>>) -> Self {
192 Self::PoisonedMutex
193 }
194}
195
196impl From<std::io::Error> for VisitError {
197 fn from(io_err: std::io::Error) -> Self {
198 Self::Io(io_err)
199 }
200}
201
202impl From<FromUtf8Error> for VisitError {
203 fn from(_: FromUtf8Error) -> Self {
204 Self::InvalidName
205 }
206}
207
208impl From<String> for VisitError {
209 fn from(s: String) -> Self {
210 Self::User(s)
211 }
212}
213
214impl From<FileError> for VisitError {
215 fn from(e: FileError) -> Self {
216 Self::FileLoadError(e)
217 }
218}
219
220impl From<ParseIntError> for VisitError {
221 fn from(value: ParseIntError) -> Self {
222 Self::ParseIntError(value)
223 }
224}
225
226impl From<ParseFloatError> for VisitError {
227 fn from(value: ParseFloatError) -> Self {
228 Self::ParseFloatError(value)
229 }
230}
231
232impl From<DecodeError> for VisitError {
233 fn from(value: DecodeError) -> Self {
234 Self::DecodeError(value)
235 }
236}
237
238impl From<uuid::Error> for VisitError {
239 fn from(value: uuid::Error) -> Self {
240 Self::UuidError(value)
241 }
242}
243
244impl From<Box<dyn Error + Send + Sync>> for VisitError {
245 fn from(value: Box<dyn Error + Send + Sync>) -> Self {
246 Self::Any(value)
247 }
248}