nstd_sys/core/unichar.rs
1//! A Unicode scalar value.
2//!
3//! This is a structure that wraps an `NSTDChar32` (Rust's `char` primitive is not FFI safe). This
4//! is done so that an `NSTDUnichar` can be created once and used a number of times without
5//! worrying about Unicode validity.
6use crate::{
7 core::optional::{gen_optional, NSTDOptional},
8 NSTDBool, NSTDChar32, NSTDUInt32,
9};
10use nstdapi::nstdapi;
11
12/// Represents a unicode scalar value.
13#[nstdapi]
14#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
15pub struct NSTDUnichar {
16 /// The 32-bit value.
17 value: NSTDChar32,
18}
19impl From<char> for NSTDUnichar {
20 /// Converts a Rust `char` into an `NSTDUnichar`.
21 #[inline]
22 fn from(value: char) -> Self {
23 Self { value: value as _ }
24 }
25}
26impl From<NSTDUnichar> for char {
27 /// Converts an `NSTDUnichar` into a Rust `char`.
28 #[inline]
29 fn from(value: NSTDUnichar) -> Self {
30 // SAFETY: `value` is always a valid Unicode scalar value.
31 unsafe { Self::from_u32_unchecked(value.value) }
32 }
33}
34gen_optional!(NSTDOptionalUnichar, NSTDUnichar);
35
36/// Creates a new `NSTDUnichar` from a 32-bit character value.
37///
38/// # Parameters:
39///
40/// - `NSTDChar32 value` - The 32-bit character to be converted into an `NSTDUnichar`.
41///
42/// # Returns
43///
44/// `NSTDOptionalUnichar unichar` - The new Unicode scalar value on success.
45#[inline]
46#[nstdapi]
47pub const fn nstd_core_unichar_new(value: NSTDChar32) -> NSTDOptionalUnichar {
48 match char::from_u32(value) {
49 Some(_) => NSTDOptional::Some(NSTDUnichar { value }),
50 _ => NSTDOptional::None,
51 }
52}
53
54/// Returns the Unicode replacement character (�).
55///
56/// # Returns
57///
58/// `NSTDUnichar replacement_char` - The Unicode replacement character (�).
59///
60/// # Example
61///
62/// ```
63/// use nstd_sys::core::unichar::nstd_core_unichar_replacement;
64///
65/// assert!(unsafe { nstd_core_unichar_replacement() } == char::REPLACEMENT_CHARACTER.into());
66/// ```
67#[inline]
68#[nstdapi]
69pub const fn nstd_core_unichar_replacement() -> NSTDUnichar {
70 NSTDUnichar {
71 value: char::REPLACEMENT_CHARACTER as _,
72 }
73}
74
75/// Generates deterministic functions such as `is_alphabetic` or `is_numeric`.
76macro_rules! gen_deterministic {
77 (
78 $(#[$meta:meta])*
79 $name: ident,
80 $method: ident
81 ) => {
82 $(#[$meta])*
83 #[inline]
84 #[nstdapi]
85 pub fn $name(chr: NSTDUnichar) -> NSTDBool {
86 char::from(chr).$method()
87 }
88 };
89}
90gen_deterministic!(
91 /// Determines whether or not `chr` is an ASCII character.
92 ///
93 /// # Parameters:
94 ///
95 /// - `NSTDUnichar chr` - The character to check.
96 ///
97 /// # Returns
98 ///
99 /// `NSTDBool is_ascii` - `NSTD_TRUE` if `chr` is an ASCII character.
100 ///
101 /// # Example
102 ///
103 /// ```
104 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_ascii, NSTD_FALSE};
105 ///
106 /// unsafe {
107 /// assert!(nstd_core_unichar_is_ascii('='.into()) != NSTD_FALSE);
108 /// assert!(nstd_core_unichar_is_ascii('💯'.into()) == NSTD_FALSE);
109 /// }
110 /// ```
111 nstd_core_unichar_is_ascii,
112 is_ascii
113);
114gen_deterministic!(
115 /// Determines whether or not `chr` is alphabetic according to the Unicode standard.
116 ///
117 /// # Parameters:
118 ///
119 /// - `NSTDUnichar chr` - The character to check.
120 ///
121 /// # Returns
122 ///
123 /// `NSTDBool is_alphabetic` - `NSTD_TRUE` if `chr` is alphabetic.
124 ///
125 /// # Example
126 ///
127 /// ```
128 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_alphabetic, NSTD_FALSE};
129 ///
130 /// unsafe {
131 /// assert!(nstd_core_unichar_is_alphabetic('G'.into()) != NSTD_FALSE);
132 /// assert!(nstd_core_unichar_is_alphabetic('0'.into()) == NSTD_FALSE);
133 /// }
134 /// ```
135 nstd_core_unichar_is_alphabetic,
136 is_alphabetic
137);
138gen_deterministic!(
139 /// Determines whether or not `chr` is numeric according to the Unicode standard.
140 ///
141 /// # Parameters:
142 ///
143 /// - `NSTDUnichar chr` - The character to check.
144 ///
145 /// # Returns
146 ///
147 /// `NSTDBool is_numeric` - `NSTD_TRUE` if `chr` is numeric.
148 ///
149 /// # Example
150 ///
151 /// ```
152 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_numeric, NSTD_FALSE};
153 ///
154 /// unsafe {
155 /// assert!(nstd_core_unichar_is_numeric('9'.into()) != NSTD_FALSE);
156 /// assert!(nstd_core_unichar_is_numeric('a'.into()) == NSTD_FALSE);
157 /// }
158 /// ```
159 nstd_core_unichar_is_numeric,
160 is_numeric
161);
162gen_deterministic!(
163 /// Determines whether or not `chr` is alphabetic or numeric according to the Unicode standard.
164 ///
165 /// # Parameters:
166 ///
167 /// - `NSTDUnichar chr` - The character to check.
168 ///
169 /// # Returns
170 ///
171 /// `NSTDBool is_alphanumeric` - `NSTD_TRUE` if `chr` is alphabetic or numeric.
172 ///
173 /// # Example
174 ///
175 /// ```
176 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_alphanumeric, NSTD_FALSE};
177 ///
178 /// unsafe {
179 /// assert!(nstd_core_unichar_is_alphanumeric('Z'.into()) != NSTD_FALSE);
180 /// assert!(nstd_core_unichar_is_alphanumeric('5'.into()) != NSTD_FALSE);
181 /// assert!(nstd_core_unichar_is_alphanumeric(';'.into()) == NSTD_FALSE);
182 /// }
183 /// ```
184 nstd_core_unichar_is_alphanumeric,
185 is_alphanumeric
186);
187gen_deterministic!(
188 /// Determines whether or not `chr` is lowercase according to the Unicode standard.
189 ///
190 /// # Parameters:
191 ///
192 /// - `NSTDUnichar chr` - The character to check.
193 ///
194 /// # Returns
195 ///
196 /// `NSTDBool is_lowercase` - `NSTD_TRUE` if `chr` is lowercase.
197 ///
198 /// # Example
199 ///
200 /// ```
201 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_lowercase, NSTD_FALSE};
202 ///
203 /// unsafe {
204 /// assert!(nstd_core_unichar_is_lowercase('v'.into()) != NSTD_FALSE);
205 /// assert!(nstd_core_unichar_is_lowercase('M'.into()) == NSTD_FALSE);
206 /// }
207 /// ```
208 nstd_core_unichar_is_lowercase,
209 is_lowercase
210);
211gen_deterministic!(
212 /// Determines whether or not `chr` is uppercase according to the Unicode standard.
213 ///
214 /// # Parameters:
215 ///
216 /// - `NSTDUnichar chr` - The character to check.
217 ///
218 /// # Returns
219 ///
220 /// `NSTDBool is_uppercase` - `NSTD_TRUE` if `chr` is uppercase.
221 ///
222 /// # Example
223 ///
224 /// ```
225 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_uppercase, NSTD_FALSE};
226 ///
227 /// unsafe {
228 /// assert!(nstd_core_unichar_is_uppercase('P'.into()) != NSTD_FALSE);
229 /// assert!(nstd_core_unichar_is_uppercase('s'.into()) == NSTD_FALSE);
230 /// }
231 /// ```
232 nstd_core_unichar_is_uppercase,
233 is_uppercase
234);
235gen_deterministic!(
236 /// Determines whether or not `chr` is white space according to the Unicode standard.
237 ///
238 /// # Parameters:
239 ///
240 /// - `NSTDUnichar chr` - The character to check.
241 ///
242 /// # Returns
243 ///
244 /// `NSTDBool is_whitespace` - `NSTD_TRUE` if `chr` is white space.
245 ///
246 /// # Example
247 ///
248 /// ```
249 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_whitespace, NSTD_FALSE};
250 ///
251 /// unsafe {
252 /// assert!(nstd_core_unichar_is_whitespace('\n'.into()) != NSTD_FALSE);
253 /// assert!(nstd_core_unichar_is_whitespace('.'.into()) == NSTD_FALSE);
254 /// }
255 /// ```
256 nstd_core_unichar_is_whitespace,
257 is_whitespace
258);
259gen_deterministic!(
260 /// Determines whether or not `chr` is a control character according to the Unicode standard.
261 ///
262 /// # Parameters:
263 ///
264 /// - `NSTDUnichar chr` - The character to check.
265 ///
266 /// # Returns
267 ///
268 /// `NSTDBool is_control` - `NSTD_TRUE` if `chr` is a control character.
269 ///
270 /// # Example
271 ///
272 /// ```
273 /// use nstd_sys::{core::unichar::nstd_core_unichar_is_control, NSTD_FALSE};
274 ///
275 /// unsafe {
276 /// assert!(nstd_core_unichar_is_control('\0'.into()) != NSTD_FALSE);
277 /// assert!(nstd_core_unichar_is_control('\\'.into()) == NSTD_FALSE);
278 /// }
279 /// ```
280 nstd_core_unichar_is_control,
281 is_control
282);
283
284/// Determines whether or not `chr` is a digit, depending on `radix`.
285///
286/// # Parameters:
287///
288/// - `NSTDUnichar chr` - The character to check.
289///
290/// - `NSTDUInt32 radix` - The base.
291///
292/// # Returns
293///
294/// `NSTDBool is_digit` - `NSTD_TRUE` if `chr` is a digit.
295///
296/// # Example
297///
298/// ```
299/// use nstd_sys::{core::unichar::nstd_core_unichar_is_digit, NSTD_FALSE};
300///
301/// unsafe {
302/// assert!(nstd_core_unichar_is_digit('5'.into(), 16) != NSTD_FALSE);
303/// assert!(nstd_core_unichar_is_digit('E'.into(), 16) != NSTD_FALSE);
304/// assert!(nstd_core_unichar_is_digit('F'.into(), 10) == NSTD_FALSE);
305/// assert!(nstd_core_unichar_is_digit('0'.into(), 37) == NSTD_FALSE);
306/// }
307/// ```
308#[inline]
309#[nstdapi]
310pub fn nstd_core_unichar_is_digit(chr: NSTDUnichar, radix: NSTDUInt32) -> NSTDBool {
311 radix <= 36 && char::from(chr).is_digit(radix)
312}