1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use core::fmt;

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum OrdError {
    /// The first character in a [conventionally UTF-8] `String` is an invalid
    /// UTF-8 byte sequence.
    ///
    /// [conventionally UTF-8]: crate::Encoding::Utf8
    InvalidUtf8ByteSequence,
    /// The given `String` is empty and has no first character.
    EmptyString,
}

impl OrdError {
    /// `OrdError` corresponds to an [`ArgumentError`] Ruby exception.
    ///
    /// [`ArgumentError`]: https://ruby-doc.org/core-3.1.2/ArgumentError.html
    pub const EXCEPTION_TYPE: &'static str = "ArgumentError";

    /// Construct a new `OrdError` for an invalid UTF-8 byte sequence.
    ///
    /// Only [conventionally UTF-8] `String`s can generate this error.
    ///
    /// # Examples
    ///
    /// ```
    /// use spinoso_string::{OrdError, String};
    ///
    /// let s = String::utf8(b"\xFFabc".to_vec());
    /// assert_eq!(s.ord(), Err(OrdError::invalid_utf8_byte_sequence()));
    ///
    /// let s = String::binary(b"\xFFabc".to_vec());
    /// assert_eq!(s.ord(), Ok(0xFF));
    /// ```
    ///
    /// [conventionally UTF-8]: crate::Encoding::Utf8
    #[inline]
    #[must_use]
    pub const fn invalid_utf8_byte_sequence() -> Self {
        Self::InvalidUtf8ByteSequence
    }

    /// Construct a new `OrdError` for an empty `String`.
    ///
    /// Empty `String`s have no first character. Empty `String`s with any
    /// encoding return this error.
    ///
    /// # Examples
    ///
    /// ```
    /// use spinoso_string::{OrdError, String};
    ///
    /// let s = String::utf8(b"\xFFabc".to_vec());
    /// assert_eq!(s.ord(), Err(OrdError::invalid_utf8_byte_sequence()));
    /// ```
    #[inline]
    #[must_use]
    pub const fn empty_string() -> Self {
        Self::EmptyString
    }

    /// Error message for this `OrdError`.
    ///
    /// This message is suitable for generating an [`ArgumentError`] exception
    /// from this `OrdError`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spinoso_string::OrdError;
    ///
    /// assert_eq!(
    ///     OrdError::invalid_utf8_byte_sequence().message(),
    ///     "invalid byte sequence in UTF-8"
    /// );
    /// assert_eq!(OrdError::empty_string().message(), "empty string");
    /// ```
    ///
    /// [`ArgumentError`]: https://ruby-doc.org/core-3.1.2/ArgumentError.html
    #[inline]
    #[must_use]
    pub const fn message(self) -> &'static str {
        match self {
            Self::InvalidUtf8ByteSequence => "invalid byte sequence in UTF-8",
            Self::EmptyString => "empty string",
        }
    }
}

impl fmt::Display for OrdError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.message())
    }
}

#[cfg(feature = "std")]
impl std::error::Error for OrdError {}