malachite_base/chars/
mod.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::strings::ToDebugString;
10
11#[cfg(feature = "test_build")]
12#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
13pub enum CharType {
14    AsciiLower,
15    AsciiUpper,
16    AsciiNumeric,
17    AsciiNonAlphanumericGraphic,
18    NonAsciiGraphic,
19    NonGraphic,
20}
21
22#[cfg(not(feature = "test_build"))]
23#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
24enum CharType {
25    AsciiLower,
26    AsciiUpper,
27    AsciiNumeric,
28    AsciiNonAlphanumericGraphic,
29    NonAsciiGraphic,
30    NonGraphic,
31}
32
33fn debug_starts_with_slash(c: char) -> bool {
34    // Skip the first `char`, which is always a single quote
35    c.to_debug_string().chars().nth(1) == Some('\\')
36}
37
38/// Determines whether a [`char`] is graphic.
39///
40/// There is an [official Unicode
41/// definition](https://www.unicode.org/versions/Unicode14.0.0/ch03.pdf#G30602) of _graphic
42/// character_, but that definition is not followed here. In Malachite, a [`char`] is considered
43/// graphic if it is ASCII and not a [C0 control](https://www.unicode.org/charts/PDF/U0000.pdf), or
44/// non-ASCII and its debug string does not begin with a backslash. This function can be used as a
45/// guide to whether a [`char`] can be displayed on a screen without resorting to some sort of
46/// escape sequence. Of course, many typefaces will not be able to render many graphic [`char`]s.
47///
48/// The ASCII space `' '` is the only graphic whitespace [`char`].
49///
50/// # Worst-case complexity
51/// Constant time and additional memory.
52///
53/// # Examples
54/// ```
55/// use malachite_base::chars::char_is_graphic;
56///
57/// assert_eq!(char_is_graphic('a'), true);
58/// assert_eq!(char_is_graphic(' '), true);
59/// assert_eq!(char_is_graphic('\n'), false);
60/// assert_eq!(char_is_graphic('ñ'), true);
61/// assert_eq!(char_is_graphic('\u{5f771}'), false);
62/// ```
63pub fn char_is_graphic(c: char) -> bool {
64    if c.is_ascii() {
65        !c.is_ascii_control()
66    } else {
67        !debug_starts_with_slash(c)
68    }
69}
70
71impl CharType {
72    pub_crate_test! {contains(self, c: char) -> bool {
73        match self {
74            CharType::AsciiLower => c.is_ascii_lowercase(),
75            CharType::AsciiUpper => c.is_ascii_uppercase(),
76            CharType::AsciiNumeric => c.is_ascii_digit(),
77            CharType::AsciiNonAlphanumericGraphic => {
78                c.is_ascii() && !c.is_ascii_alphanumeric() && !c.is_ascii_control()
79            }
80            CharType::NonAsciiGraphic => !c.is_ascii() && !debug_starts_with_slash(c),
81            CharType::NonGraphic => {
82                c.is_ascii_control() || !c.is_ascii() && debug_starts_with_slash(c)
83            }
84        }
85    }}
86}
87
88/// Constants associated with [`char`]s.
89///
90/// Apart from the constants visibile on this page, the trait-based constants
91/// [`MIN`](crate::comparison::traits::Min::MIN), [`MAX`](crate::comparison::traits::Max::MAX), and
92/// [`NAME`](crate::named::Named::NAME) are also defined.
93pub mod constants;
94/// Functions for incrementing and decrementing [`char`]s.
95pub mod crement;
96/// Iterators that generate [`char`]s without repetition.
97pub mod exhaustive;
98#[cfg(feature = "random")]
99/// Iterators that generate [`char`]s randomly.
100pub mod random;