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}