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 potential_utf::PotentialCodePoint;
10 use zerovec::ule::AsULE;
11 use zerovec::ZeroVec;
12
13 /// Returns whether the vector is sorted ascending non inclusive, of even length,
14 /// and within the bounds of `0x0 -> 0x10FFFF + 1` inclusive.
15 #[allow(clippy::indexing_slicing)] // windows
16 #[allow(clippy::unwrap_used)] // by is_empty check
is_valid_zv(inv_list_zv: &ZeroVec<'_, PotentialCodePoint>) -> bool17 pub fn is_valid_zv(inv_list_zv: &ZeroVec<'_, PotentialCodePoint>) -> bool {
18 inv_list_zv.is_empty()
19 || (inv_list_zv.len() % 2 == 0
20 && inv_list_zv.as_ule_slice().windows(2).all(|chunk| {
21 <PotentialCodePoint as AsULE>::from_unaligned(chunk[0])
22 < <PotentialCodePoint as AsULE>::from_unaligned(chunk[1])
23 })
24 && u32::from(inv_list_zv.last().unwrap()) <= char::MAX as u32 + 1)
25 }
26
27 /// Returns start (inclusive) and end (exclusive) bounds of [`RangeBounds`]
deconstruct_range<T>(range: impl RangeBounds<T>) -> (u32, u32) where T: Into<u32> + Copy,28 pub fn deconstruct_range<T>(range: impl RangeBounds<T>) -> (u32, u32)
29 where
30 T: Into<u32> + Copy,
31 {
32 let from = match range.start_bound() {
33 Included(b) => (*b).into(),
34 Excluded(_) => unreachable!(),
35 Unbounded => 0,
36 };
37 let till = match range.end_bound() {
38 Included(b) => (*b).into() + 1,
39 Excluded(b) => (*b).into(),
40 Unbounded => (char::MAX as u32) + 1,
41 };
42 (from, till)
43 }
44
45 #[cfg(test)]
46 mod tests {
47 use super::{deconstruct_range, is_valid_zv, PotentialCodePoint};
48 use core::char;
49 use zerovec::ZeroVec;
50
make_zv(slice: &[u32]) -> ZeroVec<PotentialCodePoint>51 fn make_zv(slice: &[u32]) -> ZeroVec<PotentialCodePoint> {
52 slice
53 .iter()
54 .copied()
55 .map(PotentialCodePoint::from_u24)
56 .collect()
57 }
58 #[test]
test_is_valid_zv()59 fn test_is_valid_zv() {
60 let check = make_zv(&[0x2, 0x3, 0x4, 0x5]);
61 assert!(is_valid_zv(&check));
62 }
63
64 #[test]
test_is_valid_zv_empty()65 fn test_is_valid_zv_empty() {
66 let check = make_zv(&[]);
67 assert!(is_valid_zv(&check));
68 }
69
70 #[test]
test_is_valid_zv_overlapping()71 fn test_is_valid_zv_overlapping() {
72 let check = make_zv(&[0x2, 0x5, 0x4, 0x6]);
73 assert!(!is_valid_zv(&check));
74 }
75
76 #[test]
test_is_valid_zv_out_of_order()77 fn test_is_valid_zv_out_of_order() {
78 let check = make_zv(&[0x5, 0x4, 0x5, 0x6, 0x7]);
79 assert!(!is_valid_zv(&check));
80 }
81
82 #[test]
test_is_valid_zv_duplicate()83 fn test_is_valid_zv_duplicate() {
84 let check = make_zv(&[0x1, 0x2, 0x3, 0x3, 0x5]);
85 assert!(!is_valid_zv(&check));
86 }
87
88 #[test]
test_is_valid_zv_odd()89 fn test_is_valid_zv_odd() {
90 let check = make_zv(&[0x1, 0x2, 0x3, 0x4, 0x5]);
91 assert!(!is_valid_zv(&check));
92 }
93
94 #[test]
test_is_valid_zv_out_of_range()95 fn test_is_valid_zv_out_of_range() {
96 let check = make_zv(&[0x1, 0x2, 0x3, 0x4, (char::MAX as u32) + 1]);
97 assert!(!is_valid_zv(&check));
98 }
99
100 // deconstruct_range
101
102 #[test]
test_deconstruct_range()103 fn test_deconstruct_range() {
104 let expected = (0x41, 0x45);
105 let check = deconstruct_range('A'..'E'); // Range
106 assert_eq!(check, expected);
107 let check = deconstruct_range('A'..='D'); // Range Inclusive
108 assert_eq!(check, expected);
109 let check = deconstruct_range('A'..); // Range From
110 assert_eq!(check, (0x41, (char::MAX as u32) + 1));
111 let check = deconstruct_range(..'A'); // Range To
112 assert_eq!(check, (0x0, 0x41));
113 let check = deconstruct_range(..='A'); // Range To Inclusive
114 assert_eq!(check, (0x0, 0x42));
115 let check = deconstruct_range::<char>(..); // Range Full
116 assert_eq!(check, (0x0, (char::MAX as u32) + 1));
117 }
118 }
119