soft_ascii_string/
soft_char.rs

1use std::cmp::PartialEq;
2use std::fmt::{self, Display};
3use std::str;
4use std::char::{
5    self,
6    ToUppercase, ToLowercase,
7    EscapeDebug, EscapeDefault, EscapeUnicode
8};
9#[allow(unused_imports, deprecated)]
10use std::ascii::AsciiExt;
11
12use error::FromSourceError;
13
14
15///a `char` wrapper with a "is us-ascii" soft constraint
16#[derive(
17    Debug, Default, Copy, Clone, PartialEq, Eq,
18    PartialOrd, Ord, Hash
19)]
20pub struct SoftAsciiChar(char);
21
22
23impl SoftAsciiChar {
24
25    #[inline(always)]
26    pub fn from_unchecked(ch: char) -> Self {
27        SoftAsciiChar(ch)
28    }
29
30    #[inline(always)]
31    #[deprecated(since="1.0.0", note="use from_unchecked")]
32    pub fn from_char_unchecked(ch: char) -> Self {
33        SoftAsciiChar::from_unchecked(ch)
34    }
35
36    pub fn from_char(ch: char) -> Result<Self, FromSourceError<char>> {
37        if ch.is_ascii() {
38            Ok(SoftAsciiChar(ch))
39        } else {
40            Err(FromSourceError::new(ch))
41        }
42    }
43
44    #[inline]
45    pub fn is_ascii(self) -> bool {
46        self.0.is_ascii()
47    }
48
49    pub fn revalidate_soft_constraint(self) -> Result<Self, char> {
50        if self.is_ascii() {
51            Ok(self)
52        } else {
53            Err(self.0)
54        }
55    }
56}
57
58impl Display for SoftAsciiChar {
59    fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
60        let ch: char = (*self).into();
61        ch.fmt(fter)
62    }
63}
64
65impl Into<char> for SoftAsciiChar {
66    fn into(self) -> char {
67        self.0
68    }
69}
70
71//Deref does not work as all `&self`-logic methods use `self` because Self: Copy
72macro_rules! impl_wrapping {
73    (pub > $(fn $name:ident(self$(, $param:ident: $tp:ty)*) -> $ret:ty),*) => (
74        impl SoftAsciiChar {$(
75            #[inline]
76            pub fn $name(self $(, $param: $tp)*) -> $ret {
77                char::$name(self.0 $(, $param)*)
78            }
79        )*}
80    );
81}
82
83impl_wrapping! {
84    pub >
85    fn is_digit(self, radix: u32) -> bool,
86    fn to_digit(self, radix: u32) -> Option<u32>,
87    fn escape_unicode(self) -> EscapeUnicode,
88    fn escape_debug(self) -> EscapeDebug,
89    fn escape_default(self) -> EscapeDefault,
90    fn len_utf8(self) -> usize,
91    fn len_utf16(self) -> usize,
92    fn encode_utf8(self, dst: &mut [u8]) -> &mut str,
93    fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16],
94    fn is_alphabetic(self) -> bool,
95    fn is_lowercase(self) -> bool,
96    fn is_uppercase(self) -> bool,
97    fn is_whitespace(self) -> bool,
98    fn is_alphanumeric(self) -> bool,
99    fn is_control(self) -> bool,
100    fn is_numeric(self) -> bool,
101    fn to_lowercase(self) -> ToLowercase,
102    fn to_uppercase(self) -> ToUppercase
103}
104
105impl PartialEq<char> for SoftAsciiChar {
106    fn eq(&self, other: &char) -> bool {
107        self.0 == *other
108    }
109}
110
111impl PartialEq<SoftAsciiChar> for char {
112    fn eq(&self, other: &SoftAsciiChar) -> bool {
113        *self == other.0
114    }
115}
116
117//TODO FromStr with custom error
118
119#[cfg(test)]
120mod test {
121
122    mod SoftAsciiChar {
123        #![allow(non_snake_case)]
124        use super::super::SoftAsciiChar;
125        use error::FromSourceError;
126
127        #[test]
128        fn from_char() {
129            let res: SoftAsciiChar = assert_ok!(SoftAsciiChar::from_char('a'));
130            assert_eq!(res, 'a');
131            let res = assert_err!(SoftAsciiChar::from_char('↓'));
132            assert_eq!(res, FromSourceError::new('↓'));
133        }
134
135        #[test]
136        fn from_unchecked() {
137            let a: SoftAsciiChar = SoftAsciiChar::from_unchecked('a');
138            assert_eq!(a, 'a');
139            let a: SoftAsciiChar = SoftAsciiChar::from_unchecked('↓');
140            assert_eq!(a, '↓');
141        }
142
143        #[test]
144        fn revalidate_soft_constraint() {
145            let a: SoftAsciiChar = SoftAsciiChar::from_unchecked('a');
146            let val = assert_ok!(a.revalidate_soft_constraint());
147            assert_eq!(val, 'a');
148            let a: SoftAsciiChar = SoftAsciiChar::from_unchecked('↓');
149            let val = assert_err!(a.revalidate_soft_constraint());
150            assert_eq!(val, '↓');
151        }
152    }
153}