devela/text/
error.rs

1// devela::text::error
2//
3//!
4//
5// TOC
6// - individual text-related error types:
7//   - InvalidChar
8//   - InvalidUtf8
9// - full composite errors:
10//   - TextResult
11//   - TextError
12//
13// TODO:
14// - make method from_utf8_error work with either core or simdutf8
15// - new method from_core_utf8_error
16// - (REFRESH UNDERSTANDING)
17
18use crate::{
19    _core::str::Utf8Error, impl_error, Interval, Mismatch, MismatchedCapacity,
20    DOC_MISMATCHED_CAPACITY,
21};
22
23/* individual errors */
24
25impl_error! { individual: pub struct InvalidChar(char);
26    DOC_INVALID_CHAR = "An invalid given character was found.",
27    self+f => write!(f, "An invalid {:?} character was found.", self.0)
28}
29
30impl_error! { individual:
31    pub struct InvalidUtf8 {
32        /// The index in the given string up to which valid UTF-8 was verified.
33        pub valid_up_to: Option<usize>,
34        /// The length of the error in bytes, if known.
35        pub error_len: Option<usize>
36    }
37    DOC_INVALID_UTF8 = "Invalid Utf-8 found while interpreting a byte sequence.\n\n
38This is basically a replication of `core::str::`[`Utf8Error`].",
39    self+f => match (self.valid_up_to, self.error_len) {
40        // core::str & simdutf8::compat
41        (Some(valid), Some(len)) => write!(f, "Invalid UTF-8, valid up to: {valid}, len: {len}"),
42        (Some(valid), None) => write!(f, "Invalid UTF-8, valid up to: {valid}"),
43        // exceptional
44        (None, Some(len)) => write!(f, "Invalid UTF-8, unknown valid length, len: {len}"),
45        // simdutf8::basic
46        (None, None) => write!(f, "Invalid UTF-8, unknown valid length"),
47    }
48}
49#[rustfmt::skip]
50impl From<Utf8Error> for InvalidUtf8 { fn from(f: Utf8Error) -> Self { Self::from_utf8_error(f) } }
51impl InvalidUtf8 {
52    /// Converts `core::str`[`Utf8Error`] to [`InvalidUtf8`] in compile-time.
53    #[must_use]
54    pub const fn from_utf8_error(from: Utf8Error) -> InvalidUtf8 {
55        let (valid_up_to, error_len) = (from.valid_up_to(), from.error_len());
56        InvalidUtf8 { valid_up_to: Some(valid_up_to), error_len }
57    }
58}
59#[cfg(feature = "dep_simdutf8")]
60mod dep_simdutf8 {
61    use super::InvalidUtf8;
62    use ::simdutf8::{basic, compat};
63
64    impl From<basic::Utf8Error> for InvalidUtf8 {
65        fn from(f: basic::Utf8Error) -> Self {
66            Self::from_basic_utf8_error(f)
67        }
68    }
69    impl From<compat::Utf8Error> for InvalidUtf8 {
70        fn from(f: compat::Utf8Error) -> Self {
71            Self::from_compat_utf8_error(f)
72        }
73    }
74    impl InvalidUtf8 {
75        /// Converts `simdutf8::compat`[`Utf8Error`][compat::Utf8Error]
76        /// to [`InvalidUtf8`].
77        // WAIT: [const_methods](https://github.com/rusticstuff/simdutf8/pull/111)
78        #[must_use]
79        pub fn from_compat_utf8_error(from: compat::Utf8Error) -> InvalidUtf8 {
80            let (valid_up_to, error_len) = (from.valid_up_to(), from.error_len());
81            InvalidUtf8 { valid_up_to: Some(valid_up_to), error_len }
82        }
83        /// Converts `simdutf8::basic`[`Utf8Error`][basic::Utf8Error]
84        /// to [`InvalidUtf8`] in compile-time.
85        #[must_use]
86        pub const fn from_basic_utf8_error(_from: basic::Utf8Error) -> InvalidUtf8 {
87            InvalidUtf8 { valid_up_to: None, error_len: None }
88        }
89    }
90}
91
92/* composite errors */
93
94impl_error! { composite: fmt(f)
95    /// An error composite of [`InvalidChar`] + [`InvalidUtf8`] + [`MismatchedCapacity`].
96    ///
97    /// Used in methods of:
98    /// [`StringNonul`][crate::StringNonul], and `StringU*`.
99    pub enum InvalidText {
100        DOC_INVALID_CHAR: Char(c|0: char) => InvalidChar(*c),
101        DOC_INVALID_UTF8: Utf8 {
102            #[doc = ""] valid_up_to: Option<usize>,
103            #[doc = ""] error_len: Option<usize>
104        } => InvalidUtf8 { valid_up_to: *valid_up_to, error_len: *error_len },
105        DOC_MISMATCHED_CAPACITY:
106            Capacity(c|0: Mismatch<Interval<usize>, usize>) => MismatchedCapacity(*c),
107    }
108}
109#[rustfmt::skip]
110impl From<Utf8Error> for InvalidText { fn from(f: Utf8Error) -> Self { Self::from_utf8_error(f) } }
111impl InvalidText {
112    /// Converts `core::str`[`Utf8Error`] to [`InvalidText::Utf8`] in compile-time.
113    #[must_use]
114    pub const fn from_utf8_error(from: Utf8Error) -> InvalidText {
115        let (valid_up_to, error_len) = (from.valid_up_to(), from.error_len());
116        InvalidText::Utf8 { valid_up_to: Some(valid_up_to), error_len }
117    }
118}
119
120#[cfg(all(feature = "error", text··))]
121pub use full_composite::*;
122#[cfg(all(feature = "error", text··))]
123#[cfg_attr(feature = "nightly_doc", doc(cfg(all(feature = "error", text··))))]
124mod full_composite {
125    use super::*;
126    use crate::{ElementNotFound, MismatchedCapacity, DOC_ELEMENT_NOT_FOUND};
127
128    #[doc = crate::TAG_RESULT!()]
129    /// A text-related result.
130    pub type TextResult<T> = crate::Result<T, TextError>;
131
132    impl_error! { composite: fmt(f)
133        /// A text-related composite error.
134        #[non_exhaustive]
135        pub enum TextError {
136            DOC_ELEMENT_NOT_FOUND:
137                ElementNotFound => ElementNotFound,
138
139            DOC_INVALID_CHAR:
140                InvalidChar(c|0: char) => InvalidChar(*c),
141
142            DOC_INVALID_UTF8:
143            InvalidUtf8 {
144                /// The index in the given string up to which valid UTF-8 was verified.
145                valid_up_to: Option<usize>,
146                /// The length of the error in bytes, if known.
147                error_len: Option<usize>
148            }
149            => InvalidUtf8 { valid_up_to: *valid_up_to, error_len: *error_len },
150
151            DOC_MISMATCHED_CAPACITY:
152                MismatchedCapacity(c|0: Mismatch<Interval<usize>, usize>) => MismatchedCapacity(*c),
153        }
154    }
155    impl_error! { composite: from(f): InvalidText, for: TextError {
156        Char(c) => InvalidChar(c),
157        Utf8 { valid_up_to, error_len } => InvalidUtf8 { valid_up_to, error_len },
158        Capacity(i) => MismatchedCapacity(i),
159    }}
160}