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::iter::FromIterator;
6 use core::{
7 convert::TryFrom,
8 ops::{Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
9 };
10
11 use super::RangeError;
12 use crate::codepointinvlist::utils::deconstruct_range;
13 use crate::codepointinvlist::CodePointInversionList;
14 use crate::codepointinvlist::CodePointInversionListBuilder;
15 use potential_utf::PotentialCodePoint;
16 use zerovec::ZeroVec;
17
try_from_range<'data>( range: impl RangeBounds<char>, ) -> Result<CodePointInversionList<'data>, RangeError>18 fn 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)] // valid
29 Ok(CodePointInversionList::try_from_inversion_list(inv_list).unwrap())
30 } else {
31 Err(RangeError(from, till))
32 }
33 }
34
35 impl TryFrom<Range<char>> for CodePointInversionList<'_> {
36 type Error = RangeError;
37
try_from(range: Range<char>) -> Result<Self, Self::Error>38 fn try_from(range: Range<char>) -> Result<Self, Self::Error> {
39 try_from_range(range)
40 }
41 }
42
43 impl TryFrom<RangeFrom<char>> for CodePointInversionList<'_> {
44 type Error = RangeError;
45
try_from(range: RangeFrom<char>) -> Result<Self, Self::Error>46 fn try_from(range: RangeFrom<char>) -> Result<Self, Self::Error> {
47 try_from_range(range)
48 }
49 }
50
51 impl TryFrom<RangeFull> for CodePointInversionList<'_> {
52 type Error = RangeError;
53
try_from(_: RangeFull) -> Result<Self, Self::Error>54 fn try_from(_: RangeFull) -> Result<Self, Self::Error> {
55 Ok(Self::all())
56 }
57 }
58
59 impl TryFrom<RangeInclusive<char>> for CodePointInversionList<'_> {
60 type Error = RangeError;
61
try_from(range: RangeInclusive<char>) -> Result<Self, Self::Error>62 fn try_from(range: RangeInclusive<char>) -> Result<Self, Self::Error> {
63 try_from_range(range)
64 }
65 }
66
67 impl TryFrom<RangeTo<char>> for CodePointInversionList<'_> {
68 type Error = RangeError;
69
try_from(range: RangeTo<char>) -> Result<Self, Self::Error>70 fn try_from(range: RangeTo<char>) -> Result<Self, Self::Error> {
71 try_from_range(range)
72 }
73 }
74
75 impl TryFrom<RangeToInclusive<char>> for CodePointInversionList<'_> {
76 type Error = RangeError;
77
try_from(range: RangeToInclusive<char>) -> Result<Self, Self::Error>78 fn try_from(range: RangeToInclusive<char>) -> Result<Self, Self::Error> {
79 try_from_range(range)
80 }
81 }
82
83 impl FromIterator<RangeInclusive<u32>> for CodePointInversionList<'_> {
from_iter<I: IntoIterator<Item = RangeInclusive<u32>>>(iter: I) -> Self84 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)]
94 mod tests {
95 use super::*;
96 use crate::codepointinvlist::CodePointInversionList;
97 use core::{char, convert::TryFrom};
98
99 #[test]
test_try_from_range()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]
test_try_from_range_error()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]
test_try_from_range_inclusive()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]
test_try_from_range_inclusive_err()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]
test_try_from_range_from()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]
test_try_from_range_to()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]
test_try_from_range_to_err()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]
test_try_from_range_to_inclusive()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]
test_try_from_range_full()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]
test_from_range_iterator()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 }
181