huski_lib/
lib.rs

1//! American Standard Code for Information Interchange table aide library.
2
3use huski_auxies::len;
4use core::ops::RangeInclusive;
5
6pub use huski_lib_core::ranges::*;
7pub use huski_lib_core::table::TABLE;
8
9/// Similar to `fn codes()` but it accepts `&[Ranges]` as input
10/// and returns merged open result.
11///
12/// ```
13/// use huski_lib_core::ranges::Ranges;
14/// use huski_lib::acquire;
15///
16/// let rs = acquire(&[Ranges::Capital,Ranges::Small]);
17/// assert_eq!('A', rs[0].code() as char);
18/// assert_eq!('z', rs[51].code() as char);
19/// ```
20pub fn acquire(rs: &[Ranges]) -> Vec<Code> {
21    let mut len = 0;
22    for r in rs {
23        len += len!(ranges(r.clone()));
24    }
25
26    let mut merged = Vec::new();
27    merged.reserve_exact(len);
28    for r in rs {
29        merged.extend(to_codes(r.clone()).into_iter())
30    }
31    merged
32}
33
34/// Similar to `fn codes()` but it accepts `&[Ranges]` as input
35/// and returns open result in apart.
36///
37/// ```
38/// use huski_lib_core::ranges::Ranges;
39/// use huski_lib::acquire_apart;
40///
41/// let rs = acquire_apart(&[Ranges::Capital,Ranges::Small]);
42/// assert_eq!('A', rs[0][0].code() as char);
43/// assert_eq!('z', rs[1][25].code() as char);
44/// ```
45pub fn acquire_apart(rs: &[Ranges]) -> Vec<Vec<Code>> {
46    let mut many = Vec::new();
47    many.reserve_exact(rs.len());
48
49    for r in rs {
50        let codes = to_codes(r.clone());
51        many.push(codes);
52    }
53
54    many
55}
56
57fn to_codes(r: Ranges) -> Vec<Code> {
58    codes(ranges(r))
59}
60
61/// Provides information about ASCII code
62#[derive(Debug, PartialEq, Clone)]
63pub struct Code {
64    code: u8,
65    human: &'static str,
66    desc: &'static str,
67}
68
69/// Value acquisition.
70impl Code {
71    /// Decimal code value.
72    pub const fn code(&self) -> u8 {
73        self.code
74    }
75
76    /// Human representation.
77    pub const fn human(&self) -> &'static str {
78        self.human
79    }
80
81    /// Code description.
82    pub const fn desc(&self) -> &'static str {
83        self.desc
84    }
85}
86
87/// Provides `Code`s for ranges specified.
88///
89/// Input values must fit into range 0-127, otherwise
90/// function will panic.
91///
92/// Duplicities and input order are preserved.
93/// ```
94/// use huski_lib_core::ranges::LETTERS;
95/// use huski_lib::codes;
96///
97/// let cs = codes(&LETTERS);
98/// assert_eq!(52, cs.len());
99/// assert_eq!('A', cs[0].code() as char);
100/// assert_eq!('z', cs[51].code() as char);
101/// ```
102pub fn codes(rs: &[RangeInclusive<usize>]) -> Vec<Code> {
103    let mut codes = Vec::new();
104    codes.reserve_exact(len!(rs));
105
106    let sc = codes.spare_capacity_mut();
107
108    let mut wrix = 0;
109    for r in rs {
110        for i in r.clone() {
111            let info = TABLE[i];
112            let code = Code {
113                code: i as u8,
114                human: info.0,
115                desc: info.1,
116            };
117
118            sc[wrix].write(code);
119            wrix += 1;
120        }
121    }
122
123    unsafe {
124        codes.set_len(wrix);
125    }
126
127    codes
128}
129
130#[cfg(test)]
131mod tests_of_units {
132    use huski_lib_core::ranges::{Ranges, PRINTABLE};
133
134    use crate::{Code, to_codes as to_codes_fn, codes};
135
136    mod acquire {
137
138        use huski_lib_core::ranges::{LETTERS, SYMBOLS, Ranges};
139        use crate::{Code, acquire, codes};
140
141        #[test]
142        fn basic_test() {
143            let proof = codes(&LETTERS);
144            let test = acquire(&[Ranges::Letters]);
145
146            assert_eq!(proof, test);
147        }
148
149        #[test]
150        fn merging_test() {
151            let l = codes(&LETTERS);
152            let s = codes(&SYMBOLS);
153            let test = acquire(&[Ranges::Letters, Ranges::Symbols]);
154
155            let proof = l.into_iter().chain(s.into_iter()).collect::<Vec<Code>>();
156            assert_eq!(proof, test);
157        }
158    }
159
160    mod acquire_apart {
161
162        use huski_lib_core::ranges::{LETTERS, SYMBOLS, Ranges};
163        use crate::{acquire_apart, codes};
164
165        #[test]
166        fn basic_test() {
167            let proof = vec![codes(&LETTERS)];
168            let test = acquire_apart(&[Ranges::Letters]);
169
170            assert_eq!(proof, test);
171        }
172
173        #[test]
174        fn merging_test() {
175            let l = codes(&LETTERS);
176            let s = codes(&SYMBOLS);
177            let test = acquire_apart(&[Ranges::Letters, Ranges::Symbols]);
178
179            let proof = vec![l, s];
180            assert_eq!(proof, test);
181        }
182    }
183
184    #[test]
185    fn to_codes() {
186        let r = Ranges::Printable;
187        assert_eq!(codes(&PRINTABLE), to_codes_fn(r.clone()));
188    }
189
190    #[test]
191    fn code() {
192        let code = 99;
193        let human = "human";
194        let desc = "desc";
195
196        let test = Code { code, human, desc };
197
198        assert_eq!(code, test.code);
199        assert_eq!(human, test.human);
200        assert_eq!(desc, test.desc);
201    }
202
203    mod codes {
204        use crate::codes as codes_fn;
205        use huski_lib_core::table::TABLE;
206
207        #[test]
208        fn basic_test() {
209            let codes = [(0..=2), (125..=127)];
210            let test = codes_fn(&codes);
211
212            assert_eq!(6, test.len());
213            assert!(6 <= test.capacity());
214
215            let mut reix = 0;
216            for r in codes {
217                for i in r {
218                    let info = TABLE[i];
219                    let t = &test[reix];
220
221                    reix += 1;
222
223                    assert_eq!(i as u8, t.code);
224                    assert_eq!(info.0, t.human);
225                    assert_eq!(info.1, t.desc);
226                }
227            }
228        }
229
230        #[test]
231        #[should_panic(expected = "index out of bounds: the len is 128 but the index is 128")]
232        fn index_128() {
233            let r128 = [128..=128];
234            _ = codes_fn(r128.as_slice())
235        }
236
237        #[test]
238        fn preservation() {
239            let codes = [127..=127, 127..=127, 0..=0];
240
241            let len = codes.len();
242            let test = codes_fn(codes.as_slice());
243
244            assert_eq!(len, test.len());
245
246            for i in 0..len {
247                let code = *codes[i].start();
248                let info = TABLE[code];
249
250                let t = &test[i];
251
252                assert_eq!(code as u8, t.code);
253                assert_eq!(info.0, t.human);
254                assert_eq!(info.1, t.desc);
255            }
256        }
257    }
258}