oceanpkg_shared/ext/
bytes.rs

1/// Extended functionality for
2/// [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html).
3pub trait BytesExt {
4    /// Returns whether `self` matches case-insensitively to `other`, which only
5    /// contains [ASCII] characters with the `0b100000` (lowercase) bit set.
6    ///
7    /// This method can often be used in place of
8    /// [`eq_ignore_ascii_case`](https://doc.rust-lang.org/std/primitive.slice.html#method.eq_ignore_ascii_case)
9    /// and is more performant since this uses a simple bitwise OR instead of a
10    /// lookup table. The main restriction is that only the following [ASCII]
11    /// characters may be in `other`:
12    ///
13    /// | Type          | Values |
14    /// | :------------ | :----- |
15    /// | Alphanumeric  | `a`-`z`, `0`-`9` |
16    /// | Punctuation   | `!`, `?`, `.`, `,`, `:`, `;`, `'`, `` ` ``, `\`, `/`, `#`, `$`, `&`, <code>&#124;</code>, `~` |
17    /// | Brackets      | `<`, `>`, `(`, `)`, `{`, `}` |
18    /// | Math          | `+`, `-`, `*`, `%`, `=` |
19    /// | Non-Graphical | `SPACE`, `DELETE` |
20    ///
21    /// # Examples
22    ///
23    /// This method can be used to match against filesystem paths:
24    ///
25    /// ```rust
26    /// use oceanpkg_shared::ext::BytesExt;
27    ///
28    /// let lower = b"../hello.txt";
29    /// let upper = b"../HELLO.TXT";
30    ///
31    /// assert!(upper.matches_special_lowercase(lower));
32    /// assert!(lower.matches_special_lowercase(lower));
33    /// assert!(!lower.matches_special_lowercase(upper));
34    /// assert!(!upper.matches_special_lowercase(upper));
35    /// ```
36    ///
37    /// [ASCII]: https://en.wikipedia.org/wiki/ASCII
38    fn matches_special_lowercase<B: AsRef<[u8]>>(self, other: B) -> bool;
39}
40
41// Monomorphized form
42fn matches_special_lowercase_imp(a: &[u8], b: &[u8]) -> bool {
43    a.len() == b.len() && a.iter().zip(b).all(|(&a, &b)| { a | 0b100000 == b })
44}
45
46impl BytesExt for &[u8] {
47    fn matches_special_lowercase<B: AsRef<[u8]>>(self, other: B) -> bool {
48        matches_special_lowercase_imp(self.as_ref(), other.as_ref())
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn matches_special_lowercase() {
58        let cases = [
59            (["ocean.toml", "ocean.toml"], true),
60            (["OCEAN.toMl", "ocean.toml"], true),
61            (["ocean.toml", "OCEAN.toml"], false),
62            (["ocean.tom",  "ocean.toml"], false),
63        ];
64        for &([a, b], cond) in cases.iter() {
65            assert_eq!(a.as_bytes().matches_special_lowercase(b), cond);
66        }
67    }
68}