icu_collections/codepointinvlist/
utils.rs1use core::{
6 char,
7 ops::{Bound::*, RangeBounds},
8};
9use potential_utf::PotentialCodePoint;
10use zerovec::ZeroVec;
11use zerovec::ule::AsULE;
12
13#[expect(clippy::indexing_slicing)] #[expect(clippy::unwrap_used)] pub fn is_valid_zv(inv_list_zv: &ZeroVec<'_, PotentialCodePoint>) -> bool {
18 inv_list_zv.is_empty()
19 || (inv_list_zv.len().is_multiple_of(2)
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
27pub fn deconstruct_range<T>(range: impl RangeBounds<T>) -> (u32, u32)
29where
30 T: Into<u32> + Copy,
31{
32 let from = match range.start_bound() {
33 Included(b) => (*b).into(),
34 Excluded(_) => ::core::panicking::panic("internal error: entered unreachable code")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)]
46mod tests {
47 use super::{PotentialCodePoint, deconstruct_range, is_valid_zv};
48 use zerovec::ZeroVec;
49
50 fn make_zv(slice: &[u32]) -> ZeroVec<'_, PotentialCodePoint> {
51 slice
52 .iter()
53 .copied()
54 .map(PotentialCodePoint::from_u24)
55 .collect()
56 }
57 #[test]
58 fn test_is_valid_zv() {
59 let check = make_zv(&[0x2, 0x3, 0x4, 0x5]);
60 assert!(is_valid_zv(&check));
61 }
62
63 #[test]
64 fn test_is_valid_zv_empty() {
65 let check = make_zv(&[]);
66 assert!(is_valid_zv(&check));
67 }
68
69 #[test]
70 fn test_is_valid_zv_overlapping() {
71 let check = make_zv(&[0x2, 0x5, 0x4, 0x6]);
72 assert!(!is_valid_zv(&check));
73 }
74
75 #[test]
76 fn test_is_valid_zv_out_of_order() {
77 let check = make_zv(&[0x5, 0x4, 0x5, 0x6, 0x7]);
78 assert!(!is_valid_zv(&check));
79 }
80
81 #[test]
82 fn test_is_valid_zv_duplicate() {
83 let check = make_zv(&[0x1, 0x2, 0x3, 0x3, 0x5]);
84 assert!(!is_valid_zv(&check));
85 }
86
87 #[test]
88 fn test_is_valid_zv_odd() {
89 let check = make_zv(&[0x1, 0x2, 0x3, 0x4, 0x5]);
90 assert!(!is_valid_zv(&check));
91 }
92
93 #[test]
94 fn test_is_valid_zv_out_of_range() {
95 let check = make_zv(&[0x1, 0x2, 0x3, 0x4, (char::MAX as u32) + 1]);
96 assert!(!is_valid_zv(&check));
97 }
98
99 #[test]
102 fn test_deconstruct_range() {
103 let expected = (0x41, 0x45);
104 let check = deconstruct_range('A'..'E'); assert_eq!(check, expected);
106 let check = deconstruct_range('A'..='D'); assert_eq!(check, expected);
108 let check = deconstruct_range('A'..); assert_eq!(check, (0x41, (char::MAX as u32) + 1));
110 let check = deconstruct_range(..'A'); assert_eq!(check, (0x0, 0x41));
112 let check = deconstruct_range(..='A'); assert_eq!(check, (0x0, 0x42));
114 let check = deconstruct_range::<char>(..); assert_eq!(check, (0x0, (char::MAX as u32) + 1));
116 }
117}