1use core::{error::Error as StdError, fmt};
2
3#[cfg(feature = "alloc")]
4use alloc::boxed::Box;
5#[cfg(feature = "alloc")]
6use core::ops::Deref;
7
8#[cfg(feature = "valuable")]
9use alloc::string::ToString;
10#[cfg(feature = "valuable")]
11use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct TooShortError {
16 min: usize,
17 actual: usize,
18}
19
20impl TooShortError {
21 pub const fn new(min: usize, actual: usize) -> Self {
23 Self { min, actual }
24 }
25
26 pub const fn min(&self) -> usize {
28 self.min
29 }
30
31 pub const fn actual(&self) -> usize {
33 self.actual
34 }
35}
36
37impl fmt::Display for TooShortError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(
40 f,
41 "is too short (min {} chars, got {})",
42 self.min, self.actual
43 )
44 }
45}
46
47impl StdError for TooShortError {}
48
49#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct TooLongError {
52 max: usize,
53 actual: usize,
54}
55
56impl TooLongError {
57 pub const fn new(max: usize, actual: usize) -> Self {
59 Self { max, actual }
60 }
61
62 pub const fn max(&self) -> usize {
64 self.max
65 }
66
67 pub const fn actual(&self) -> usize {
69 self.actual
70 }
71}
72
73impl fmt::Display for TooLongError {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 write!(
76 f,
77 "is too long (max {} chars, got {})",
78 self.max, self.actual
79 )
80 }
81}
82
83impl StdError for TooLongError {}
84
85#[derive(Debug, Copy, Clone, PartialEq, Eq)]
86enum IntegerValueRepr {
87 Signed(i128),
88 Unsigned(u128),
89}
90
91#[derive(Debug, Copy, Clone, PartialEq, Eq)]
97pub struct IntegerValue(IntegerValueRepr);
98
99impl IntegerValue {
100 pub const fn from_i128(value: i128) -> Self {
102 Self(IntegerValueRepr::Signed(value))
103 }
104
105 pub const fn from_u128(value: u128) -> Self {
107 Self(IntegerValueRepr::Unsigned(value))
108 }
109
110 pub fn as_i64(self) -> Option<i64> {
112 match self.0 {
113 IntegerValueRepr::Signed(value) => i64::try_from(value).ok(),
114 IntegerValueRepr::Unsigned(value) => i64::try_from(value).ok(),
115 }
116 }
117
118 pub fn as_u64(self) -> Option<u64> {
120 match self.0 {
121 IntegerValueRepr::Signed(value) => u64::try_from(value).ok(),
122 IntegerValueRepr::Unsigned(value) => u64::try_from(value).ok(),
123 }
124 }
125
126 pub fn as_i128(self) -> Option<i128> {
128 match self.0 {
129 IntegerValueRepr::Signed(value) => Some(value),
130 IntegerValueRepr::Unsigned(value) => i128::try_from(value).ok(),
131 }
132 }
133
134 pub fn as_u128(self) -> Option<u128> {
136 match self.0 {
137 IntegerValueRepr::Signed(value) => u128::try_from(value).ok(),
138 IntegerValueRepr::Unsigned(value) => Some(value),
139 }
140 }
141}
142
143impl fmt::Display for IntegerValue {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 match self.0 {
146 IntegerValueRepr::Signed(value) => write!(f, "{value}"),
147 IntegerValueRepr::Unsigned(value) => write!(f, "{value}"),
148 }
149 }
150}
151
152macro_rules! impl_signed_integer_value_from {
153 ($($ty:ty),* $(,)?) => {
154 $(
155 impl From<$ty> for IntegerValue {
156 fn from(value: $ty) -> Self {
157 Self::from_i128(i128::from(value))
158 }
159 }
160 )*
161 };
162}
163
164macro_rules! impl_unsigned_integer_value_from {
165 ($($ty:ty),* $(,)?) => {
166 $(
167 impl From<$ty> for IntegerValue {
168 fn from(value: $ty) -> Self {
169 Self::from_u128(u128::from(value))
170 }
171 }
172 )*
173 };
174}
175
176impl_signed_integer_value_from!(i8, i16, i32, i64, i128);
177impl_unsigned_integer_value_from!(u8, u16, u32, u64, u128);
178
179#[cfg(feature = "valuable")]
180impl Valuable for IntegerValue {
181 fn as_value(&self) -> Value<'_> {
182 match self.0 {
183 IntegerValueRepr::Signed(value) => Value::I128(value),
184 IntegerValueRepr::Unsigned(value) => Value::U128(value),
185 }
186 }
187
188 fn visit(&self, visit: &mut dyn Visit) {
189 visit.visit_value(self.as_value());
190 }
191}
192
193#[derive(Debug, Copy, Clone, PartialEq, Eq)]
194enum FloatValueRepr {
195 F32(u32),
196 F64(u64),
197}
198
199#[derive(Debug, Copy, Clone, PartialEq, Eq)]
204pub struct FloatValue(FloatValueRepr);
205
206impl FloatValue {
207 pub const fn from_f32(value: f32) -> Self {
209 Self(FloatValueRepr::F32(value.to_bits()))
210 }
211
212 pub const fn from_f64(value: f64) -> Self {
214 Self(FloatValueRepr::F64(value.to_bits()))
215 }
216
217 pub const fn as_f32(self) -> Option<f32> {
219 match self.0 {
220 FloatValueRepr::F32(bits) => Some(f32::from_bits(bits)),
221 FloatValueRepr::F64(_) => None,
222 }
223 }
224
225 pub const fn as_f64(self) -> Option<f64> {
227 match self.0 {
228 FloatValueRepr::F32(_) => None,
229 FloatValueRepr::F64(bits) => Some(f64::from_bits(bits)),
230 }
231 }
232}
233
234impl From<f32> for FloatValue {
235 fn from(value: f32) -> Self {
236 Self::from_f32(value)
237 }
238}
239
240impl From<f64> for FloatValue {
241 fn from(value: f64) -> Self {
242 Self::from_f64(value)
243 }
244}
245
246impl fmt::Display for FloatValue {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 match self.0 {
249 FloatValueRepr::F32(bits) => {
250 let value = f32::from_bits(bits);
251 write!(f, "{value}")
252 }
253 FloatValueRepr::F64(bits) => {
254 let value = f64::from_bits(bits);
255 write!(f, "{value}")
256 }
257 }
258 }
259}
260
261#[cfg(feature = "valuable")]
262impl Valuable for FloatValue {
263 fn as_value(&self) -> Value<'_> {
264 match self.0 {
265 FloatValueRepr::F32(bits) => Value::F32(f32::from_bits(bits)),
266 FloatValueRepr::F64(bits) => Value::F64(f64::from_bits(bits)),
267 }
268 }
269
270 fn visit(&self, visit: &mut dyn Visit) {
271 visit.visit_value(self.as_value());
272 }
273}
274
275#[derive(Debug, Copy, Clone, PartialEq, Eq)]
277pub enum FloatRangeViolation {
278 NotComparable,
280 BelowLowerBound,
282 AboveUpperBound,
284}
285
286impl FloatRangeViolation {
287 pub const fn as_str(self) -> &'static str {
289 match self {
290 Self::NotComparable => "not_comparable",
291 Self::BelowLowerBound => "below_lower_bound",
292 Self::AboveUpperBound => "above_upper_bound",
293 }
294 }
295}
296
297#[cfg(feature = "valuable")]
298impl Valuable for FloatRangeViolation {
299 fn as_value(&self) -> Value<'_> {
300 Value::String(self.as_str())
301 }
302
303 fn visit(&self, visit: &mut dyn Visit) {
304 visit.visit_value(self.as_value());
305 }
306}
307
308#[derive(Debug, Clone, PartialEq, Eq)]
310pub struct OutOfRangeIntegerError {
311 actual: IntegerValue,
312 lower_bound: Option<IntegerValue>,
313 upper_bound: Option<IntegerValue>,
314}
315
316impl OutOfRangeIntegerError {
317 pub const fn new(actual: IntegerValue) -> Self {
319 Self {
320 actual,
321 lower_bound: None,
322 upper_bound: None,
323 }
324 }
325
326 #[must_use]
328 pub const fn with_lower_bound(self, lower_bound: IntegerValue) -> Self {
329 Self {
330 actual: self.actual,
331 lower_bound: Some(lower_bound),
332 upper_bound: self.upper_bound,
333 }
334 }
335
336 #[must_use]
338 pub const fn with_upper_bound(self, upper_bound: IntegerValue) -> Self {
339 Self {
340 actual: self.actual,
341 lower_bound: self.lower_bound,
342 upper_bound: Some(upper_bound),
343 }
344 }
345
346 pub const fn actual(&self) -> IntegerValue {
348 self.actual
349 }
350
351 pub const fn lower_bound(&self) -> Option<IntegerValue> {
353 self.lower_bound
354 }
355
356 pub const fn upper_bound(&self) -> Option<IntegerValue> {
358 self.upper_bound
359 }
360}
361
362impl fmt::Display for OutOfRangeIntegerError {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 let actual = self.actual;
365 match (self.lower_bound, self.upper_bound) {
366 (Some(lower_bound), Some(upper_bound)) => {
367 write!(
368 f,
369 "out of range (value {actual}, lower bound {lower_bound}, upper bound {upper_bound})"
370 )
371 }
372 (Some(lower_bound), None) => {
373 write!(
374 f,
375 "out of range (value {actual}, lower bound {lower_bound})"
376 )
377 }
378 (None, Some(upper_bound)) => {
379 write!(
380 f,
381 "out of range (value {actual}, upper bound {upper_bound})"
382 )
383 }
384 (None, None) => write!(f, "out of range (value {actual})"),
385 }
386 }
387}
388
389impl StdError for OutOfRangeIntegerError {}
390
391#[derive(Debug, Clone, PartialEq, Eq)]
393pub struct OutOfRangeFloatError {
394 actual: FloatValue,
395 lower_bound: Option<FloatValue>,
396 upper_bound: Option<FloatValue>,
397 violation: FloatRangeViolation,
398}
399
400impl OutOfRangeFloatError {
401 pub const fn not_comparable(actual: FloatValue) -> Self {
403 Self {
404 actual,
405 lower_bound: None,
406 upper_bound: None,
407 violation: FloatRangeViolation::NotComparable,
408 }
409 }
410
411 pub const fn below_lower_bound(actual: FloatValue, lower_bound: FloatValue) -> Self {
413 Self {
414 actual,
415 lower_bound: Some(lower_bound),
416 upper_bound: None,
417 violation: FloatRangeViolation::BelowLowerBound,
418 }
419 }
420
421 pub const fn above_upper_bound(actual: FloatValue, upper_bound: FloatValue) -> Self {
423 Self {
424 actual,
425 lower_bound: None,
426 upper_bound: Some(upper_bound),
427 violation: FloatRangeViolation::AboveUpperBound,
428 }
429 }
430
431 pub const fn actual(&self) -> FloatValue {
433 self.actual
434 }
435
436 pub const fn lower_bound(&self) -> Option<FloatValue> {
438 self.lower_bound
439 }
440
441 pub const fn upper_bound(&self) -> Option<FloatValue> {
443 self.upper_bound
444 }
445
446 pub const fn violation(&self) -> FloatRangeViolation {
448 self.violation
449 }
450}
451
452impl fmt::Display for OutOfRangeFloatError {
453 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454 let actual = self.actual;
455 match self.violation {
456 FloatRangeViolation::NotComparable => write!(f, "not comparable (value {actual})"),
457 FloatRangeViolation::BelowLowerBound => match self.lower_bound {
458 Some(lower_bound) => {
459 write!(
460 f,
461 "out of range (value {actual}, lower bound {lower_bound})"
462 )
463 }
464 None => write!(f, "out of range (value {actual})"),
465 },
466 FloatRangeViolation::AboveUpperBound => match self.upper_bound {
467 Some(upper_bound) => {
468 write!(
469 f,
470 "out of range (value {actual}, upper bound {upper_bound})"
471 )
472 }
473 None => write!(f, "out of range (value {actual})"),
474 },
475 }
476 }
477}
478
479impl StdError for OutOfRangeFloatError {}
480
481#[cfg(feature = "valuable")]
482static OUT_OF_RANGE_INTEGER_ERROR_FIELDS: &[NamedField<'static>] = &[
483 NamedField::new("actual"),
484 NamedField::new("lower_bound"),
485 NamedField::new("upper_bound"),
486];
487
488#[cfg(feature = "valuable")]
489impl Valuable for OutOfRangeIntegerError {
490 fn as_value(&self) -> Value<'_> {
491 Value::Structable(self)
492 }
493
494 fn visit(&self, visit: &mut dyn Visit) {
495 let values = [
496 self.actual.as_value(),
497 self.lower_bound.as_value(),
498 self.upper_bound.as_value(),
499 ];
500 visit.visit_named_fields(&NamedValues::new(
501 OUT_OF_RANGE_INTEGER_ERROR_FIELDS,
502 &values,
503 ));
504 }
505}
506
507#[cfg(feature = "valuable")]
508impl Structable for OutOfRangeIntegerError {
509 fn definition(&self) -> StructDef<'_> {
510 StructDef::new_static(
511 "OutOfRangeIntegerError",
512 Fields::Named(OUT_OF_RANGE_INTEGER_ERROR_FIELDS),
513 )
514 }
515}
516
517#[cfg(feature = "valuable")]
518static OUT_OF_RANGE_FLOAT_ERROR_FIELDS: &[NamedField<'static>] = &[
519 NamedField::new("actual"),
520 NamedField::new("lower_bound"),
521 NamedField::new("upper_bound"),
522 NamedField::new("violation"),
523];
524
525#[cfg(feature = "valuable")]
526impl Valuable for OutOfRangeFloatError {
527 fn as_value(&self) -> Value<'_> {
528 Value::Structable(self)
529 }
530
531 fn visit(&self, visit: &mut dyn Visit) {
532 let values = [
533 self.actual.as_value(),
534 self.lower_bound.as_value(),
535 self.upper_bound.as_value(),
536 self.violation.as_value(),
537 ];
538 visit.visit_named_fields(&NamedValues::new(OUT_OF_RANGE_FLOAT_ERROR_FIELDS, &values));
539 }
540}
541
542#[cfg(feature = "valuable")]
543impl Structable for OutOfRangeFloatError {
544 fn definition(&self) -> StructDef<'_> {
545 StructDef::new_static(
546 "OutOfRangeFloatError",
547 Fields::Named(OUT_OF_RANGE_FLOAT_ERROR_FIELDS),
548 )
549 }
550}
551
552#[derive(Debug, Clone, PartialEq, Eq)]
554pub struct InvalidCharError {
555 index: usize,
556 ch: char,
557}
558
559impl InvalidCharError {
560 pub const fn new(index: usize, ch: char) -> Self {
562 Self { index, ch }
563 }
564
565 pub const fn index(&self) -> usize {
567 self.index
568 }
569
570 pub const fn ch(&self) -> char {
572 self.ch
573 }
574}
575
576impl fmt::Display for InvalidCharError {
577 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578 write!(
579 f,
580 "contains invalid character '{}' at index {}",
581 self.ch, self.index
582 )
583 }
584}
585
586impl StdError for InvalidCharError {}
587
588pub trait VouchedError: StdError + Send + Sync + 'static {
593 fn as_too_short(&self) -> Option<&TooShortError> {
595 None
596 }
597 fn as_too_long(&self) -> Option<&TooLongError> {
599 None
600 }
601 fn as_out_of_range_integer(&self) -> Option<&OutOfRangeIntegerError> {
603 None
604 }
605 fn as_out_of_range_float(&self) -> Option<&OutOfRangeFloatError> {
607 None
608 }
609 fn as_invalid_char(&self) -> Option<&InvalidCharError> {
611 None
612 }
613}
614
615#[cfg(feature = "alloc")]
660#[derive(Debug)]
661pub struct Error(Box<dyn VouchedError>);
662
663#[cfg(feature = "alloc")]
664impl Error {
665 pub fn new(inner: Box<dyn VouchedError>) -> Self {
667 Self(inner)
668 }
669
670 pub fn into_inner(self) -> Box<dyn VouchedError> {
672 self.0
673 }
674}
675
676#[cfg(feature = "alloc")]
677impl fmt::Display for Error {
678 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
679 self.0.fmt(f)
680 }
681}
682
683#[cfg(feature = "alloc")]
684impl StdError for Error {
685 fn source(&self) -> Option<&(dyn StdError + 'static)> {
686 Some(&*self.0)
687 }
688}
689
690#[cfg(feature = "alloc")]
691impl<E> From<E> for Error
692where
693 E: VouchedError,
694{
695 fn from(e: E) -> Self {
696 Self(Box::new(e))
697 }
698}
699
700#[cfg(feature = "alloc")]
701impl Deref for Error {
702 type Target = dyn VouchedError;
703
704 fn deref(&self) -> &Self::Target {
705 &*self.0
706 }
707}
708
709#[cfg(feature = "alloc")]
710impl AsRef<dyn VouchedError> for Error {
711 fn as_ref(&self) -> &(dyn VouchedError + 'static) {
712 &*self.0
713 }
714}
715
716#[cfg(feature = "valuable")]
717static ERROR_FIELDS: &[NamedField<'static>] = &[NamedField::new("message")];
718
719#[cfg(feature = "valuable")]
720impl Valuable for Error {
721 fn as_value(&self) -> Value<'_> {
722 Value::Structable(self)
723 }
724
725 fn visit(&self, visit: &mut dyn Visit) {
726 let message = self.to_string();
727 let values = [message.as_value()];
728 visit.visit_named_fields(&NamedValues::new(ERROR_FIELDS, &values));
729 }
730}
731
732#[cfg(feature = "valuable")]
733impl Structable for Error {
734 fn definition(&self) -> StructDef<'_> {
735 StructDef::new_static("Error", Fields::Named(ERROR_FIELDS))
736 }
737}