icu_collections/codepointinvlist/
conversions.rs1use core::iter::FromIterator;
6use core::{
7 convert::TryFrom,
8 ops::{Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
9};
10
11use super::RangeError;
12use crate::codepointinvlist::utils::deconstruct_range;
13use crate::codepointinvlist::CodePointInversionList;
14use crate::codepointinvlist::CodePointInversionListBuilder;
15use potential_utf::PotentialCodePoint;
16use zerovec::ZeroVec;
17
18fn try_from_range<'data>(
19 range: impl RangeBounds<char>,
20) -> Result<CodePointInversionList<'data>, RangeError> {
21 let (from, till) = deconstruct_range(range);
22 if from < till {
23 let set = [
24 PotentialCodePoint::from_u24(from),
25 PotentialCodePoint::from_u24(till),
26 ];
27 let inv_list: ZeroVec<PotentialCodePoint> = ZeroVec::alloc_from_slice(&set);
28 #[allow(clippy::unwrap_used)] Ok(CodePointInversionList::try_from_inversion_list(inv_list).unwrap())
30 } else {
31 Err(RangeError(from, till))
32 }
33}
34
35impl TryFrom<Range<char>> for CodePointInversionList<'_> {
36 type Error = RangeError;
37
38 fn try_from(range: Range<char>) -> Result<Self, Self::Error> {
39 try_from_range(range)
40 }
41}
42
43impl TryFrom<RangeFrom<char>> for CodePointInversionList<'_> {
44 type Error = RangeError;
45
46 fn try_from(range: RangeFrom<char>) -> Result<Self, Self::Error> {
47 try_from_range(range)
48 }
49}
50
51impl TryFrom<RangeFull> for CodePointInversionList<'_> {
52 type Error = RangeError;
53
54 fn try_from(_: RangeFull) -> Result<Self, Self::Error> {
55 Ok(Self::all())
56 }
57}
58
59impl TryFrom<RangeInclusive<char>> for CodePointInversionList<'_> {
60 type Error = RangeError;
61
62 fn try_from(range: RangeInclusive<char>) -> Result<Self, Self::Error> {
63 try_from_range(range)
64 }
65}
66
67impl TryFrom<RangeTo<char>> for CodePointInversionList<'_> {
68 type Error = RangeError;
69
70 fn try_from(range: RangeTo<char>) -> Result<Self, Self::Error> {
71 try_from_range(range)
72 }
73}
74
75impl TryFrom<RangeToInclusive<char>> for CodePointInversionList<'_> {
76 type Error = RangeError;
77
78 fn try_from(range: RangeToInclusive<char>) -> Result<Self, Self::Error> {
79 try_from_range(range)
80 }
81}
82
83impl FromIterator<RangeInclusive<u32>> for CodePointInversionList<'_> {
84 fn from_iter<I: IntoIterator<Item = RangeInclusive<u32>>>(iter: I) -> Self {
85 let mut builder = CodePointInversionListBuilder::new();
86 for range in iter {
87 builder.add_range32(range);
88 }
89 builder.build()
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::codepointinvlist::CodePointInversionList;
97 use core::{char, convert::TryFrom};
98
99 #[test]
100 fn test_try_from_range() {
101 let check: Vec<char> = CodePointInversionList::try_from('A'..'B')
102 .unwrap()
103 .iter_chars()
104 .collect();
105 assert_eq!(vec!['A'], check);
106 }
107
108 #[test]
109 fn test_try_from_range_error() {
110 let check = CodePointInversionList::try_from('A'..'A');
111 assert!(matches!(check, Err(RangeError(65, 65))));
112 }
113
114 #[test]
115 fn test_try_from_range_inclusive() {
116 let check: Vec<char> = CodePointInversionList::try_from('A'..='A')
117 .unwrap()
118 .iter_chars()
119 .collect();
120 assert_eq!(vec!['A'], check);
121 }
122
123 #[test]
124 fn test_try_from_range_inclusive_err() {
125 let check = CodePointInversionList::try_from('B'..'A');
126 assert!(matches!(check, Err(RangeError(66, 65))));
127 }
128
129 #[test]
130 fn test_try_from_range_from() {
131 let uset = CodePointInversionList::try_from('A'..).unwrap();
132 let check: usize = uset.size();
133 let expected: usize = (char::MAX as usize) + 1 - 65;
134 assert_eq!(expected, check);
135 }
136
137 #[test]
138 fn test_try_from_range_to() {
139 let uset = CodePointInversionList::try_from(..'A').unwrap();
140 let check: usize = uset.size();
141 let expected: usize = 65;
142 assert_eq!(expected, check);
143 }
144
145 #[test]
146 fn test_try_from_range_to_err() {
147 let check = CodePointInversionList::try_from(..(0x0 as char));
148 assert!(matches!(check, Err(RangeError(0, 0))));
149 }
150
151 #[test]
152 fn test_try_from_range_to_inclusive() {
153 let uset = CodePointInversionList::try_from(..='A').unwrap();
154 let check: usize = uset.size();
155 let expected: usize = 66;
156 assert_eq!(expected, check);
157 }
158
159 #[test]
160 fn test_try_from_range_full() {
161 let uset = CodePointInversionList::try_from(..).unwrap();
162 let check: usize = uset.size();
163 let expected: usize = (char::MAX as usize) + 1;
164 assert_eq!(expected, check);
165 }
166
167 #[test]
168 fn test_from_range_iterator() {
169 let ranges = [
170 0..=0x3FFF,
171 0x4000..=0x7FFF,
172 0x8000..=0xBFFF,
173 0xC000..=0xFFFF,
174 ];
175 let expected =
176 CodePointInversionList::try_from_u32_inversion_list_slice(&[0x0, 0x1_0000]).unwrap();
177 let actual = CodePointInversionList::from_iter(ranges);
178 assert_eq!(expected, actual);
179 }
180}