char_collection/
conversions.rs
1use std::iter;
8use std::ops::RangeInclusive;
9use unic_char_range::CharRange;
10use unic_ucd_block::Block;
11use unicode_blocks::UnicodeBlockId;
12
13use crate::{CharCollection, MultiCharRange};
14
15macro_rules! impl_for_range_inclusive_int_type {
16 ($($t:ty),*) => {$(
17 impl MultiCharRange for RangeInclusive<$t> {
18 fn iter_ranges(&self) -> Box<dyn Iterator<Item=CharRange>> {
19 Box::new(iter::once(to_char_range!(self)))
20 }
21
22 fn range_count(&self) -> usize {
23 1
24 }
25 })*}
26}
27
28macro_rules! to_char_range {
30 ($range:expr) => {
31 CharRange::closed(
32 char::try_from(*$range.start() as u32).unwrap(),
33 char::try_from(*$range.end() as u32).unwrap(),
34 )
35 };
36}
37
38impl MultiCharRange for char {
39 fn iter_ranges(&self) -> Box<dyn Iterator<Item = CharRange>> {
40 Box::new(std::iter::once(CharRange::closed(*self, *self)))
41 }
42
43 fn range_count(&self) -> usize {
44 1
45 }
46}
47
48impl MultiCharRange for CharRange {
49 fn iter_ranges(&self) -> Box<dyn Iterator<Item = CharRange>> {
50 Box::new(iter::once(self.clone()))
51 }
52
53 fn range_count(&self) -> usize {
54 1
55 }
56}
57
58impl MultiCharRange for RangeInclusive<char> {
59 fn iter_ranges(&self) -> Box<dyn Iterator<Item = CharRange>> {
60 Box::new(iter::once(CharRange::closed(*self.start(), *self.end())))
61 }
62
63 fn range_count(&self) -> usize {
64 1
65 }
66}
67
68impl_for_range_inclusive_int_type!(u8, i8, u32, i32);
69
70impl MultiCharRange for UnicodeBlockId {
71 fn iter_ranges(&self) -> Box<dyn Iterator<Item = CharRange>> {
72 self.block().iter_ranges()
73 }
74
75 fn range_count(&self) -> usize {
76 1
77 }
78}
79
80impl MultiCharRange for Block {
81 fn iter_ranges<'a>(&'a self) -> Box<dyn Iterator<Item = CharRange> + 'a> {
82 Box::new(self.range.iter_ranges())
83 }
84
85 fn range_count(&self) -> usize {
86 1
87 }
88}
89
90impl<T: MultiCharRange> From<&T> for CharCollection {
91 fn from(source: &T) -> Self {
92 let mut collection = CharCollection::new();
93 collection.insert(source);
94 collection
95 }
96}
97
98#[cfg(test)]
99mod multi_char_range_tests {
100 use crate::MultiCharRange;
101 use unic_char_range::{chars, CharRange};
102
103 #[test]
104 fn test_char() {
105 let source = 'a';
106 assert_eq!(source.iter_ranges().collect::<Vec<CharRange>>(), vec![chars!('a'..='a')]);
107 assert_eq!(source.range_count(), 1);
108 }
109
110 #[test]
111 fn test_char_range() {
112 let source = chars!('d'..='g');
113 assert_eq!(source.iter_ranges().collect::<Vec<CharRange>>(), vec![chars!('d'..='g')]);
114 assert_eq!(source.range_count(), 1);
115 }
116
117 #[test]
118 fn test_range_inclusive_char() {
119 let source = 'd'..='g';
120 assert_eq!(source.iter_ranges().collect::<Vec<CharRange>>(), vec![chars!('d'..='g')]);
121 assert_eq!(source.range_count(), 1);
122 }
123
124 macro_rules! test_range_inclusive_int {
125 ($t:ty) => {
126 paste::paste! {
127 #[test]
128 fn [<test_char_range_inclusive_ $t>]() {
129 let source: std::ops::RangeInclusive<$t> = 0x0..=0x9;
130 assert_eq!(
131 source.iter_ranges().collect::<Vec<CharRange>>(),
132 vec![chars!('\u{0}'..='\u{9}')]
133 );
134 assert_eq!(source.range_count(), 1);
135 }
136 }
137 };
138 }
139
140 test_range_inclusive_int!(u8);
141 test_range_inclusive_int!(i8);
142 test_range_inclusive_int!(u32);
143 test_range_inclusive_int!(i32);
144
145 #[test]
146 fn test_unicode_block_id() {
147 let source = unicode_blocks::UnicodeBlockId::BasicLatin;
148 assert_eq!(
149 source.iter_ranges().collect::<Vec<CharRange>>(),
150 vec![chars!('\u{0000}'..='\u{007f}')]
151 );
152 assert_eq!(source.range_count(), 1);
153 }
154
155 #[test]
156 fn test_unicode_block() {
157 let source = unicode_blocks::UnicodeBlockId::BasicLatin.block();
158 assert_eq!(
159 source.iter_ranges().collect::<Vec<CharRange>>(),
160 vec![chars!('\u{0000}'..='\u{007f}')]
161 );
162 assert_eq!(source.range_count(), 1);
163 }
164}
165
166#[cfg(test)]
167mod from_tests {
168 use crate::CharCollection;
169 use unicode_blocks::UnicodeBlockId;
170
171 #[test]
172 fn test_char() {
173 let actual: CharCollection = (&'a').into();
174 assert_eq!(actual, char_collect!('a'..='a'));
175 }
176
177 #[test]
178 fn test_unicode_block_id() {
179 let actual: CharCollection = (&UnicodeBlockId::BasicLatin).into();
180 assert_eq!(actual, char_collect!('\u{0000}'..='\u{007f}'));
181 }
182}