devela/text/char/impls/
c7.rs

1// devela::text::char::impls::char7
2
3use super::*;
4#[cfg(feature = "ascii")]
5use crate::AsciiChar;
6use crate::{Char, DataOverflow, NonExtremeU8};
7
8impl char7 {
9    /* private helper fns */
10
11    // SAFETY: this is not marked as unsafe because it's only used privately
12    // by this module for a few selected operations.
13    #[must_use]
14    const fn from_char_unchecked(c: char) -> char7 {
15        char7::new_unchecked(c as u32 as u8)
16    }
17
18    // SAFETY: this is not marked as unsafe because it's only used privately
19    // by this module for a few selected operations.
20    #[must_use]
21    const fn new_unchecked(value: u8) -> char7 {
22        #[cfg(any(feature = "safe_text", not(feature = "unsafe_niche")))]
23        if let Some(c) = NonExtremeU8::new(value) {
24            char7(c)
25        } else {
26            unreachable![]
27        }
28        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_niche"))]
29        unsafe {
30            char7(NonExtremeU8::new_unchecked(value))
31        }
32    }
33
34    /* constants */
35
36    /// The lowest unicode scalar a `char7` can represent, `'\u{00}'`.
37    pub const MIN: char7 = char7::new_unchecked(0x00);
38
39    /// The highest unicode scalar a `char7` can represent, `'\u{7F}'`.
40    pub const MAX: char7 = char7::new_unchecked(0x7F);
41
42    /* conversions */
43
44    /// Converts an `AsciiChar` to `char7`.
45    #[must_use]
46    #[cfg(feature = "ascii")]
47    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "ascii")))]
48    pub const fn from_ascii_char(c: AsciiChar) -> char7 {
49        char7::new_unchecked(c as u8)
50    }
51
52    /// Tries to convert a `char8` to `char7`.
53    ///
54    /// # Errors
55    /// Returns [`DataOverflow`] if the character can't fit in 7 bits.
56    #[cfg(feature = "_char8")]
57    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "_char8")))]
58    pub const fn try_from_char8(c: char8) -> Result<char7, DataOverflow> {
59        if Char::is_7bit(c.to_u32()) {
60            Ok(char7::new_unchecked(c.to_u32() as u8))
61        } else {
62            Err(DataOverflow(Some(c.to_u32() as usize)))
63        }
64    }
65    /// Tries to convert a `char16` to `char7`.
66    ///
67    /// # Errors
68    /// Returns [`DataOverflow`] if the character can't fit in 7 bits.
69    #[cfg(feature = "_char16")]
70    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "_char16")))]
71    pub const fn try_from_char16(c: char16) -> Result<char7, DataOverflow> {
72        if Char::is_7bit(c.to_u32()) {
73            Ok(char7::new_unchecked(c.to_u32() as u8))
74        } else {
75            Err(DataOverflow(Some(c.to_u32() as usize)))
76        }
77    }
78    /// Tries to convert a `char` to `char7`.
79    ///
80    /// # Errors
81    /// Returns [`DataOverflow`] if the character can't fit in 7 bits.
82    pub const fn try_from_char(c: char) -> Result<char7, DataOverflow> {
83        if Char::is_7bit(c as u32) {
84            Ok(char7::new_unchecked(c as u32 as u8))
85        } else {
86            Err(DataOverflow(Some(c as u32 as usize)))
87        }
88    }
89
90    //
91
92    /// Converts a `char7` to `AsciiChar`.
93    #[must_use]
94    #[cfg(feature = "ascii")]
95    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "ascii")))]
96    pub const fn to_ascii_char(c: char7) -> AsciiChar {
97        #[cfg(any(feature = "safe_text", not(feature = "unsafe_niche")))]
98        return if let Some(c) = AsciiChar::from_u8(c.0.get()) { c } else { unreachable!() };
99
100        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_niche"))]
101        unsafe {
102            AsciiChar::from_u8_unchecked(c.0.get())
103        }
104    }
105
106    /// Converts this `char7` to `char8`.
107    #[must_use]
108    #[cfg(feature = "_char8")]
109    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "_char8")))]
110    pub const fn to_char8(self) -> char8 {
111        char8::from_char7(self)
112    }
113    /// Converts this `char7` to `char16`.
114    #[must_use]
115    #[cfg(feature = "_char16")]
116    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "_char16")))]
117    pub const fn to_char16(self) -> char16 {
118        char16::from_char7(self)
119    }
120    /// Converts this `char7` to `char`.
121    #[must_use]
122    pub const fn to_char(self) -> char {
123        self.0.get() as char
124    }
125    /// Converts this `char7` to `u32`.
126    #[must_use]
127    pub const fn to_u32(self) -> u32 {
128        self.0.get() as u32
129    }
130
131    /// Converts this `char7` to an UTF-8 encoded sequence of bytes.
132    //
133    // https://en.wikipedia.org/wiki/UTF-8#Encoding
134    #[must_use]
135    #[allow(clippy::unusual_byte_groupings)]
136    pub const fn to_utf8_bytes(self) -> [u8; 1] {
137        // From 0x0000 to 0x007F:
138        // the UTF-8 encoding is the same as the scalar value.
139        [self.0.get()]
140    }
141
142    //
143
144    /* queries */
145
146    /// Returns `true` if this unicode scalar is a [noncharacter][0].
147    ///
148    /// [0]: https://www.unicode.org/glossary/#noncharacter
149    #[must_use]
150    pub const fn is_noncharacter(self) -> bool {
151        false
152    }
153
154    /// Returns `true` if this unicode scalar is an [abstract character][0].
155    ///
156    /// [0]: https://www.unicode.org/glossary/#abstract_character
157    #[must_use]
158    pub const fn is_character(self) -> bool {
159        true
160    }
161
162    /// Checks if the value is within the ASCII range.
163    #[must_use]
164    pub const fn is_ascii(self) -> bool {
165        true
166    }
167
168    /// Makes a copy of the value in its ASCII upper case equivalent.
169    ///
170    /// ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, but non-ASCII letters
171    /// are unchanged.
172    #[must_use]
173    pub const fn to_ascii_uppercase(self) -> char7 {
174        Self::from_char_unchecked(char::to_ascii_uppercase(&self.to_char()))
175    }
176
177    /// Makes a copy of the value in its ASCII lower case equivalent.
178    ///
179    /// ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, but non-ASCII letters
180    /// are unchanged.
181    #[must_use]
182    pub const fn to_ascii_lowercase(self) -> char7 {
183        Self::from_char_unchecked(char::to_ascii_lowercase(&self.to_char()))
184    }
185}