1 //! Enumerations for the sign-bit of a number.
2
3 use super::format::NumberFormat;
4 use super::num::Number;
5
6 // ENUMERATION
7
8 /// Enumeration for the sign of a a number.
9 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
10 pub enum Sign {
11 /// Negative value.
12 Negative,
13 /// Positive value.
14 Positive,
15 }
16
17 // HELPERS
18
19 // Get if an option contains a digit separator.
20 #[inline(always)]
21 #[cfg(feature = "format")]
is_digit_separator(option: Option<&u8>, digit_separator: u8) -> bool22 fn is_digit_separator(option: Option<&u8>, digit_separator: u8) -> bool {
23 option == Some(&digit_separator)
24 }
25
26 // Convert option of byte to option of sign.
27 #[inline(always)]
28 #[cfg(feature = "format")]
to_sign<T>(option: Option<&u8>) -> Option<Sign> where T: Number29 fn to_sign<T>(option: Option<&u8>)
30 -> Option<Sign>
31 where T: Number
32 {
33 match option {
34 Some(&b'+') => Some(Sign::Positive),
35 Some(&b'-') if T::IS_SIGNED => Some(Sign::Negative),
36 _ => None
37 }
38 }
39
40 // PARSE
41
42 /// Find and parse sign without any possible digit separators.
43 #[inline(always)]
parse_sign_no_separator<'a, T>(bytes: &'a [u8], _: u8) -> (Sign, &'a [u8]) where T: Number44 pub(crate) fn parse_sign_no_separator<'a, T>(bytes: &'a [u8], _: u8)
45 -> (Sign, &'a [u8])
46 where T: Number
47 {
48 match bytes.get(0) {
49 Some(&b'+') => (Sign::Positive, &index!(bytes[1..])),
50 Some(&b'-') if T::IS_SIGNED => (Sign::Negative, &index!(bytes[1..])),
51 _ => (Sign::Positive, bytes)
52 }
53 }
54
55 /// Find and parse sign with leading and consecutive digit separators.
56 ///
57 /// We need to consider the following possibilities:
58 /// 1). _*[+-]\d+
59 #[inline(always)]
60 #[cfg(feature = "format")]
parse_sign_lc_separator<'a, T>(bytes: &'a [u8], digit_separator: u8) -> (Sign, &'a [u8]) where T: Number61 pub(crate) fn parse_sign_lc_separator<'a, T>(bytes: &'a [u8], digit_separator: u8)
62 -> (Sign, &'a [u8])
63 where T: Number
64 {
65 let mut index = 0;
66 while is_digit_separator(bytes.get(index), digit_separator) {
67 index += 1;
68 }
69 if let Some(sign) = to_sign::<T>(bytes.get(index)) {
70 (sign, &index!(bytes[index+1..]))
71 } else {
72 (Sign::Positive, bytes)
73 }
74 }
75
76 /// Find and parse sign with leading digit separators.
77 ///
78 /// We need to consider the following possibilities:
79 /// 1). [+-]\d+
80 /// 2). _[+-]\d+
81 #[inline(always)]
82 #[cfg(feature = "format")]
parse_sign_l_separator<'a, T>(bytes: &'a [u8], digit_separator: u8) -> (Sign, &'a [u8]) where T: Number83 pub(crate) fn parse_sign_l_separator<'a, T>(bytes: &'a [u8], digit_separator: u8)
84 -> (Sign, &'a [u8])
85 where T: Number
86 {
87 let b0 = bytes.get(0);
88 if let Some(sign) = to_sign::<T>(b0) {
89 (sign, &index!(bytes[1..]))
90 } else if is_digit_separator(b0, digit_separator) {
91 if let Some(sign) = to_sign::<T>(bytes.get(1)) {
92 (sign, &index!(bytes[2..]))
93 } else {
94 (Sign::Positive, bytes)
95 }
96 } else {
97 (Sign::Positive, bytes)
98 }
99 }
100
101 /// Find and parse sign with digit separators.
102 #[inline(always)]
103 #[cfg(feature = "format")]
parse_sign_separator<'a, T>(bytes: &'a [u8], format: NumberFormat) -> (Sign, &'a [u8]) where T: Number104 pub(crate) fn parse_sign_separator<'a, T>(bytes: &'a [u8], format: NumberFormat)
105 -> (Sign, &'a [u8])
106 where T: Number
107 {
108 // If the integer cannot have leading digit separators, we know the sign
109 // byte must by the first byte. Otherwise, we must consider digit separators
110 // before the sign byte.
111 let leading = format.integer_leading_digit_separator();
112 let consecutive = format.integer_consecutive_digit_separator();
113 match (leading, consecutive) {
114 (true, true) => parse_sign_lc_separator::<T>(bytes, format.digit_separator()),
115 (true, false) => parse_sign_l_separator::<T>(bytes, format.digit_separator()),
116 (false, _) => parse_sign_no_separator::<T>(bytes, format.digit_separator())
117 }
118 }
119
120 /// Find and parse sign.
121 #[inline]
parse_sign<'a, T>(bytes: &'a [u8], format: NumberFormat) -> (Sign, &'a [u8]) where T: Number122 pub(crate) fn parse_sign<'a, T>(bytes: &'a [u8], format: NumberFormat)
123 -> (Sign, &'a [u8])
124 where T: Number
125 {
126 #[cfg(not(feature = "format"))]
127 return parse_sign_no_separator::<T>(bytes, format.digit_separator());
128
129 #[cfg(feature = "format")]
130 return parse_sign_separator::<T>(bytes, format);
131 }
132
133 // TESTS
134 // -----
135
136 #[cfg(test)]
137 mod tests {
138 use super::*;
139 use crate::util::test::*;
140
141 #[test]
parse_sign_no_separator_test()142 fn parse_sign_no_separator_test() {
143 // Signed
144 assert_eq!(parse_sign_no_separator::<i32>(b"", b'_'), (Sign::Positive, b!("")));
145 assert_eq!(parse_sign_no_separator::<i32>(b"+", b'_'), (Sign::Positive, b!("")));
146 assert_eq!(parse_sign_no_separator::<i32>(b"-", b'_'), (Sign::Negative, b!("")));
147 assert_eq!(parse_sign_no_separator::<i32>(b"+5", b'_'), (Sign::Positive, b!("5")));
148 assert_eq!(parse_sign_no_separator::<i32>(b"-5", b'_'), (Sign::Negative, b!("5")));
149 assert_eq!(parse_sign_no_separator::<i32>(b"_-5", b'_'), (Sign::Positive, b!("_-5")));
150 assert_eq!(parse_sign_no_separator::<i32>(b"___-5", b'_'), (Sign::Positive, b!("___-5")));
151
152 // Unsigned
153 assert_eq!(parse_sign_no_separator::<u32>(b"+5", b'_'), (Sign::Positive, b!("5")));
154 assert_eq!(parse_sign_no_separator::<u32>(b"-5", b'_'), (Sign::Positive, b!("-5")));
155 }
156
157 #[test]
158 #[cfg(feature = "format")]
parse_sign_lc_separator_test()159 fn parse_sign_lc_separator_test() {
160 assert_eq!(parse_sign_lc_separator::<i32>(b"", b'_'), (Sign::Positive, b!("")));
161 assert_eq!(parse_sign_lc_separator::<i32>(b"+", b'_'), (Sign::Positive, b!("")));
162 assert_eq!(parse_sign_lc_separator::<i32>(b"-", b'_'), (Sign::Negative, b!("")));
163 assert_eq!(parse_sign_lc_separator::<i32>(b"+5", b'_'), (Sign::Positive, b!("5")));
164 assert_eq!(parse_sign_lc_separator::<i32>(b"-5", b'_'), (Sign::Negative, b!("5")));
165 assert_eq!(parse_sign_lc_separator::<i32>(b"_-5", b'_'), (Sign::Negative, b!("5")));
166 assert_eq!(parse_sign_lc_separator::<i32>(b"___-5", b'_'), (Sign::Negative, b!("5")));
167
168 // Unsigned
169 assert_eq!(parse_sign_lc_separator::<u32>(b"___+5", b'_'), (Sign::Positive, b!("5")));
170 assert_eq!(parse_sign_lc_separator::<u32>(b"___-5", b'_'), (Sign::Positive, b!("___-5")));
171 }
172
173 #[test]
174 #[cfg(feature = "format")]
parse_sign_l_separator_test()175 fn parse_sign_l_separator_test() {
176 assert_eq!(parse_sign_l_separator::<i32>(b"", b'_'), (Sign::Positive, b!("")));
177 assert_eq!(parse_sign_l_separator::<i32>(b"+", b'_'), (Sign::Positive, b!("")));
178 assert_eq!(parse_sign_l_separator::<i32>(b"-", b'_'), (Sign::Negative, b!("")));
179 assert_eq!(parse_sign_l_separator::<i32>(b"+5", b'_'), (Sign::Positive, b!("5")));
180 assert_eq!(parse_sign_l_separator::<i32>(b"-5", b'_'), (Sign::Negative, b!("5")));
181 assert_eq!(parse_sign_l_separator::<i32>(b"_-5", b'_'), (Sign::Negative, b!("5")));
182 assert_eq!(parse_sign_l_separator::<i32>(b"___-5", b'_'), (Sign::Positive, b!("___-5")));
183
184 // Unsigned
185 assert_eq!(parse_sign_l_separator::<u32>(b"_+5", b'_'), (Sign::Positive, b!("5")));
186 assert_eq!(parse_sign_l_separator::<u32>(b"_-5", b'_'), (Sign::Positive, b!("_-5")));
187 }
188
189 #[test]
190 #[cfg(feature = "format")]
parse_sign_separator_test()191 fn parse_sign_separator_test() {
192 let format = NumberFormat::ignore(b'_').unwrap();
193 assert_eq!(parse_sign_separator::<i32>(b"", format), (Sign::Positive, b!("")));
194 assert_eq!(parse_sign_separator::<i32>(b"+", format), (Sign::Positive, b!("")));
195 assert_eq!(parse_sign_separator::<i32>(b"-", format), (Sign::Negative, b!("")));
196 assert_eq!(parse_sign_separator::<i32>(b"+5", format), (Sign::Positive, b!("5")));
197 assert_eq!(parse_sign_separator::<i32>(b"-5", format), (Sign::Negative, b!("5")));
198 assert_eq!(parse_sign_separator::<i32>(b"_-5", format), (Sign::Negative, b!("5")));
199 assert_eq!(parse_sign_separator::<i32>(b"___-5", format), (Sign::Negative, b!("5")));
200
201 // Unsigned
202 assert_eq!(parse_sign_separator::<u32>(b"__+5", format), (Sign::Positive, b!("5")));
203 assert_eq!(parse_sign_separator::<u32>(b"__-5", format), (Sign::Positive, b!("__-5")));
204 }
205
206 #[test]
parse_sign_test()207 fn parse_sign_test() {
208 let format = NumberFormat::standard().unwrap();
209 assert_eq!(parse_sign::<i32>(b"", format), (Sign::Positive, b!("")));
210 assert_eq!(parse_sign::<i32>(b"+", format), (Sign::Positive, b!("")));
211 assert_eq!(parse_sign::<i32>(b"-", format), (Sign::Negative, b!("")));
212 assert_eq!(parse_sign::<i32>(b"+5", format), (Sign::Positive, b!("5")));
213 assert_eq!(parse_sign::<i32>(b"-5", format), (Sign::Negative, b!("5")));
214 assert_eq!(parse_sign::<i32>(b"_-5", format), (Sign::Positive, b!("_-5")));
215 assert_eq!(parse_sign::<i32>(b"___-5", format), (Sign::Positive, b!("___-5")));
216
217 // Unsigned
218 assert_eq!(parse_sign::<u32>(b"+5", format), (Sign::Positive, b!("5")));
219 assert_eq!(parse_sign::<u32>(b"-5", format), (Sign::Positive, b!("-5")));
220 }
221 }
222