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