1 // Copyright © 2016–2020 University of Malta
2 
3 // This program is free software: you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public License
5 // as published by the Free Software Foundation, either version 3 of
6 // the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License and a copy of the GNU General Public License along with
15 // this program. If not, see <https://www.gnu.org/licenses/>.
16 
17 #![allow(dead_code)]
18 
19 use az::{CheckedCast, WrappingCast};
20 
21 pub trait UnwrappedCast<Dst> {
unwrapped_cast(self) -> Dst22     fn unwrapped_cast(self) -> Dst;
23 }
24 impl<Dst, Src: CheckedCast<Dst>> UnwrappedCast<Dst> for Src {
25     #[inline]
unwrapped_cast(self) -> Dst26     fn unwrapped_cast(self) -> Dst {
27         self.checked_cast().expect("overflow")
28     }
29 }
30 
31 pub trait UnwrappedAs {
unwrapped_as<Dst>(self) -> Dst where Self: UnwrappedCast<Dst>32     fn unwrapped_as<Dst>(self) -> Dst
33     where
34         Self: UnwrappedCast<Dst>;
35 }
36 
37 impl<T> UnwrappedAs for T {
38     #[inline]
unwrapped_as<Dst>(self) -> Dst where Self: UnwrappedCast<Dst>,39     fn unwrapped_as<Dst>(self) -> Dst
40     where
41         Self: UnwrappedCast<Dst>,
42     {
43         self.unwrapped_cast()
44     }
45 }
46 
47 pub trait NegAbs {
48     type Abs;
neg_abs(self) -> (bool, Self::Abs)49     fn neg_abs(self) -> (bool, Self::Abs);
50 }
51 
52 macro_rules! neg_abs {
53     ($I:ty; $U:ty) => {
54         impl NegAbs for $I {
55             type Abs = $U;
56             #[inline]
57             fn neg_abs(self) -> (bool, $U) {
58                 if self < 0 {
59                     (true, self.wrapping_neg().wrapping_cast())
60                 } else {
61                     (false, self.wrapping_cast())
62                 }
63             }
64         }
65 
66         impl NegAbs for $U {
67             type Abs = $U;
68             #[inline]
69             fn neg_abs(self) -> (bool, $U) {
70                 (false, self)
71             }
72         }
73     };
74 }
75 
76 neg_abs! { i8; u8 }
77 neg_abs! { i16; u16 }
78 neg_abs! { i32; u32 }
79 neg_abs! { i64; u64 }
80 neg_abs! { i128; u128 }
81 neg_abs! { isize; usize }
82 
83 #[inline]
trunc_f64_to_f32(f: f64) -> f3284 pub fn trunc_f64_to_f32(f: f64) -> f32 {
85     // f as f32 might round away from zero, so we need to clear
86     // the least significant bits of f.
87     //   * If f is a nan, we do NOT want to clear any mantissa bits,
88     //     as this may change f into +/- infinity.
89     //   * If f is +/- infinity, the bits are already zero, so the
90     //     masking has no effect.
91     //   * If f is subnormal, f as f32 will be zero anyway.
92     if !f.is_nan() {
93         let u = f.to_bits();
94         // f64 has 29 more significant bits than f32.
95         let trunc_u = u & (!0 << 29);
96         let trunc_f = f64::from_bits(trunc_u);
97         trunc_f as f32
98     } else {
99         f as f32
100     }
101 }
102 
lcase(byte: u8) -> u8103 fn lcase(byte: u8) -> u8 {
104     match byte {
105         b'A'..=b'Z' => byte - b'A' + b'a',
106         _ => byte,
107     }
108 }
109 
trim_start(bytes: &[u8]) -> &[u8]110 pub fn trim_start(bytes: &[u8]) -> &[u8] {
111     for (start, &b) in bytes.iter().enumerate() {
112         match b {
113             b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => {}
114             _ => return &bytes[start..],
115         }
116     }
117     &[]
118 }
119 
trim_end(bytes: &[u8]) -> &[u8]120 pub fn trim_end(bytes: &[u8]) -> &[u8] {
121     for (end, &b) in bytes.iter().enumerate().rev() {
122         match b {
123             b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => {}
124             _ => return &bytes[..=end],
125         }
126     }
127     &[]
128 }
129 
130 // If bytes starts with a match to one of patterns, return bytes with
131 // the match skipped. Only bytes is converted to lcase.
skip_lcase_match<'a>(bytes: &'a [u8], patterns: &[&[u8]]) -> Option<&'a [u8]>132 pub fn skip_lcase_match<'a>(bytes: &'a [u8], patterns: &[&[u8]]) -> Option<&'a [u8]> {
133     'next_pattern: for pattern in patterns {
134         if bytes.len() < pattern.len() {
135             continue 'next_pattern;
136         }
137         for (&b, &p) in bytes.iter().zip(pattern.iter()) {
138             if lcase(b) != p {
139                 continue 'next_pattern;
140             }
141         }
142         return Some(&bytes[pattern.len()..]);
143     }
144     None
145 }
146 
147 // If bytes starts with '(' and has a matching ')', returns the
148 // contents and the remainder.
matched_brackets(bytes: &[u8]) -> Option<(&[u8], &[u8])>149 pub fn matched_brackets(bytes: &[u8]) -> Option<(&[u8], &[u8])> {
150     let mut iter = bytes.iter().enumerate();
151     match iter.next() {
152         Some((_, &b'(')) => {}
153         _ => return None,
154     }
155     let mut level = 1;
156     for (i, &b) in iter {
157         match b {
158             b'(' => level += 1,
159             b')' => {
160                 level -= 1;
161                 if level == 0 {
162                     return Some((&bytes[1..i], &bytes[i + 1..]));
163                 }
164             }
165             _ => {}
166         }
167     }
168     None
169 }
170 
find_outside_brackets(bytes: &[u8], pattern: u8) -> Option<usize>171 pub fn find_outside_brackets(bytes: &[u8], pattern: u8) -> Option<usize> {
172     let mut level = 0;
173     for (i, &b) in bytes.iter().enumerate() {
174         match b {
175             b'(' => level += 1,
176             b')' if level > 0 => level -= 1,
177             _ if level == 0 && b == pattern => return Some(i),
178             _ => {}
179         }
180     }
181     None
182 }
183 
find_space_outside_brackets(bytes: &[u8]) -> Option<usize>184 pub fn find_space_outside_brackets(bytes: &[u8]) -> Option<usize> {
185     let mut level = 0;
186     for (i, &b) in bytes.iter().enumerate() {
187         match b {
188             b'(' => level += 1,
189             b')' if level > 0 => level -= 1,
190             b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d if level == 0 => {
191                 return Some(i);
192             }
193             _ => {}
194         }
195     }
196     None
197 }
198