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
use strings::ToDebugString;

#[cfg(feature = "test_build")]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CharType {
    AsciiLower,
    AsciiUpper,
    AsciiNumeric,
    AsciiNonAlphanumericGraphic,
    NonAsciiGraphic,
    NonGraphic,
}

#[cfg(not(feature = "test_build"))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum CharType {
    AsciiLower,
    AsciiUpper,
    AsciiNumeric,
    AsciiNonAlphanumericGraphic,
    NonAsciiGraphic,
    NonGraphic,
}

fn debug_starts_with_slash(c: char) -> bool {
    // Skip the first `char`, which is always a single quote
    c.to_debug_string().chars().nth(1) == Some('\\')
}

/// Determines whether a [`char`] is graphic.
///
/// There is an
/// [official Unicode definition](https://www.unicode.org/versions/Unicode14.0.0/ch03.pdf#G30602)
/// of _graphic character_, but that definition is not followed here. In Malachite, a [`char`] is
/// considered graphic if it is ASCII and not a
/// [C0 control](https://unicode.org/charts/PDF/U0000.pdf), or non-ASCII and its debug string does
/// not begin with a backslash. This function can be used as a guide to whether a [`char`] can be
/// displayed on a screen without resorting to some sort of escape sequence. Of course, many
/// typefaces will not be able to render many graphic [`char`]s.
///
/// The ASCII space `' '` is the only graphic whitespace [`char`].
///
/// # Worst-case complexity
/// Constant time and additional memory.
///
/// # Examples
/// ```
/// use malachite_base::chars::char_is_graphic;
///
/// assert_eq!(char_is_graphic('a'), true);
/// assert_eq!(char_is_graphic(' '), true);
/// assert_eq!(char_is_graphic('\n'), false);
/// assert_eq!(char_is_graphic('ñ'), true);
/// assert_eq!(char_is_graphic('\u{5f771}'), false);
/// ```
pub fn char_is_graphic(c: char) -> bool {
    if c.is_ascii() {
        !c.is_ascii_control()
    } else {
        !debug_starts_with_slash(c)
    }
}

impl CharType {
    pub_crate_test! {contains(self, c: char) -> bool {
        match self {
            CharType::AsciiLower => c.is_ascii_lowercase(),
            CharType::AsciiUpper => c.is_ascii_uppercase(),
            CharType::AsciiNumeric => c.is_ascii_digit(),
            CharType::AsciiNonAlphanumericGraphic => {
                c.is_ascii() && !c.is_ascii_alphanumeric() && !c.is_ascii_control()
            }
            CharType::NonAsciiGraphic => !c.is_ascii() && !debug_starts_with_slash(c),
            CharType::NonGraphic => {
                c.is_ascii_control() || !c.is_ascii() && debug_starts_with_slash(c)
            }
        }
    }}
}

/// Constants associated with [`char`]s.
///
/// Apart from the constants visibile on this page, the trait-based constants
/// [`MIN`](crate::comparison::traits::Min::MIN), [`MAX`](crate::comparison::traits::Max::MAX), and
/// [`NAME`](crate::named::Named::NAME) are also defined.
pub mod constants;
/// Functions for incrementing and decrementing [`char`]s.
pub mod crement;
/// Iterators that generate [`char`]s without repetition.
pub mod exhaustive;
/// Iterators that generate [`char`]s randomly.
pub mod random;