• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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