1 | // This file is part of ICU4X. For terms of use, please see the file |
2 | // called LICENSE at the top level of the ICU4X source tree |
3 | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | |
5 | use core::{ |
6 | char, |
7 | ops::{Bound::*, RangeBounds}, |
8 | }; |
9 | use zerovec::ule::AsULE; |
10 | use zerovec::ZeroVec; |
11 | |
12 | /// Returns whether the vector is sorted ascending non inclusive, of even length, |
13 | /// and within the bounds of `0x0 -> 0x10FFFF + 1` inclusive. |
14 | #[allow (clippy::indexing_slicing)] // windows |
15 | #[allow (clippy::unwrap_used)] // by is_empty check |
16 | pub fn is_valid_zv(inv_list_zv: &ZeroVec<'_, u32>) -> bool { |
17 | inv_list_zv.is_empty() |
18 | || (inv_list_zv.len() % 2 == 0 |
19 | && inv_list_zv.as_ule_slice().windows(size:2).all(|chunk: &[RawBytesULE<4>]| { |
20 | <u32 as AsULE>::from_unaligned(chunk[0]) < <u32 as AsULE>::from_unaligned(chunk[1]) |
21 | }) |
22 | && inv_list_zv.last().unwrap() <= char::MAX as u32 + 1) |
23 | } |
24 | |
25 | /// Returns start (inclusive) and end (exclusive) bounds of [`RangeBounds`] |
26 | pub fn deconstruct_range<T, R: RangeBounds<T>>(range: &R) -> (u32, u32) |
27 | where |
28 | T: Into<u32> + Copy, |
29 | { |
30 | let from: u32 = match range.start_bound() { |
31 | Included(b: &T) => (*b).into(), |
32 | Excluded(_) => unreachable!(), |
33 | Unbounded => 0, |
34 | }; |
35 | let till: u32 = match range.end_bound() { |
36 | Included(b: &T) => (*b).into() + 1, |
37 | Excluded(b: &T) => (*b).into(), |
38 | Unbounded => (char::MAX as u32) + 1, |
39 | }; |
40 | (from, till) |
41 | } |
42 | |
43 | #[cfg (test)] |
44 | mod tests { |
45 | use super::{deconstruct_range, is_valid_zv}; |
46 | use core::char; |
47 | use zerovec::ZeroVec; |
48 | |
49 | #[test ] |
50 | fn test_is_valid_zv() { |
51 | let check = ZeroVec::from_slice_or_alloc(&[0x2, 0x3, 0x4, 0x5]); |
52 | assert!(is_valid_zv(&check)); |
53 | } |
54 | |
55 | #[test ] |
56 | fn test_is_valid_zv_empty() { |
57 | let check = ZeroVec::from_slice_or_alloc(&[]); |
58 | assert!(is_valid_zv(&check)); |
59 | } |
60 | |
61 | #[test ] |
62 | fn test_is_valid_zv_overlapping() { |
63 | let check = ZeroVec::from_slice_or_alloc(&[0x2, 0x5, 0x4, 0x6]); |
64 | assert!(!is_valid_zv(&check)); |
65 | } |
66 | |
67 | #[test ] |
68 | fn test_is_valid_zv_out_of_order() { |
69 | let check = ZeroVec::from_slice_or_alloc(&[0x5, 0x4, 0x5, 0x6, 0x7]); |
70 | assert!(!is_valid_zv(&check)); |
71 | } |
72 | |
73 | #[test ] |
74 | fn test_is_valid_zv_duplicate() { |
75 | let check = ZeroVec::from_slice_or_alloc(&[0x1, 0x2, 0x3, 0x3, 0x5]); |
76 | assert!(!is_valid_zv(&check)); |
77 | } |
78 | |
79 | #[test ] |
80 | fn test_is_valid_zv_odd() { |
81 | let check = ZeroVec::from_slice_or_alloc(&[0x1, 0x2, 0x3, 0x4, 0x5]); |
82 | assert!(!is_valid_zv(&check)); |
83 | } |
84 | |
85 | #[test ] |
86 | fn test_is_valid_zv_out_of_range() { |
87 | let check = ZeroVec::from_slice_or_alloc(&[0x1, 0x2, 0x3, 0x4, (char::MAX as u32) + 1]); |
88 | assert!(!is_valid_zv(&check)); |
89 | } |
90 | |
91 | // deconstruct_range |
92 | |
93 | #[test ] |
94 | fn test_deconstruct_range() { |
95 | let expected = (0x41, 0x45); |
96 | let check = deconstruct_range(&('A' ..'E' )); // Range |
97 | assert_eq!(check, expected); |
98 | let check = deconstruct_range(&('A' ..='D' )); // Range Inclusive |
99 | assert_eq!(check, expected); |
100 | let check = deconstruct_range(&('A' ..)); // Range From |
101 | assert_eq!(check, (0x41, (char::MAX as u32) + 1)); |
102 | let check = deconstruct_range(&(..'A' )); // Range To |
103 | assert_eq!(check, (0x0, 0x41)); |
104 | let check = deconstruct_range(&(..='A' )); // Range To Inclusive |
105 | assert_eq!(check, (0x0, 0x42)); |
106 | let check = deconstruct_range::<char, _>(&(..)); // Range Full |
107 | assert_eq!(check, (0x0, (char::MAX as u32) + 1)); |
108 | } |
109 | } |
110 | |