Skip to main content

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