• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zbraniecki / icu4x / 9457158389

10 Jun 2024 11:45PM UTC coverage: 75.174% (+0.05%) from 75.121%
9457158389

push

github

web-flow
Add constructing TinyAsciiStr from utf16 (#5025)

Introduces TinyAsciiStr constructors from utf16 and converges on the
consensus from #4931.

---------

Co-authored-by: Robert Bastian <4706271+robertbastian@users.noreply.github.com>

65 of 82 new or added lines in 14 files covered. (79.27%)

3441 existing lines in 141 files now uncovered.

52850 of 70304 relevant lines covered (75.17%)

563298.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.86
/components/collections/src/codepointinvlist/builder.rs
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 alloc::vec;
6
use alloc::vec::Vec;
7
use core::{char, cmp::Ordering, ops::RangeBounds};
8

9
use crate::codepointinvlist::{utils::deconstruct_range, CodePointInversionList};
10
use zerovec::{ule::AsULE, ZeroVec};
11

12
/// A builder for [`CodePointInversionList`].
13
///
14
/// Provides exposure to builder functions and conversion to [`CodePointInversionList`]
15
#[derive(Default)]
×
16
pub struct CodePointInversionListBuilder {
17
    // A sorted list of even length, with values <= char::MAX + 1
18
    intervals: Vec<u32>,
×
19
}
20

21
impl CodePointInversionListBuilder {
22
    /// Returns empty [`CodePointInversionListBuilder`]
23
    pub const fn new() -> Self {
4,572✔
24
        Self { intervals: vec![] }
4,572✔
25
    }
4,572✔
26

27
    /// Returns a [`CodePointInversionList`] and consumes the [`CodePointInversionListBuilder`]
28
    pub fn build(self) -> CodePointInversionList<'static> {
4,470✔
29
        let inv_list: ZeroVec<u32> = ZeroVec::alloc_from_slice(&self.intervals);
4,470✔
30
        #[allow(clippy::unwrap_used)] // by invariant
31
        CodePointInversionList::try_from_inversion_list(inv_list).unwrap()
4,470✔
32
    }
4,470✔
33

34
    /// Abstraction for adding/removing a range from start..end
35
    ///
36
    /// If add is true add, else remove
37
    fn add_remove_middle(&mut self, start: u32, end: u32, add: bool) {
5,702,872✔
38
        if start >= end || end > char::MAX as u32 + 1 {
5,702,872✔
39
            return;
40
        }
41
        let start_res = self.intervals.binary_search(&start);
5,703,955✔
42
        let end_res = self.intervals.binary_search(&end);
5,703,955✔
43
        let mut start_ind = start_res.unwrap_or_else(|x| x);
7,935,093✔
44
        let mut end_ind = end_res.unwrap_or_else(|x| x);
11,402,993✔
45
        let start_pos_check = (start_ind % 2 == 0) == add;
5,703,955✔
46
        let end_pos_check = (end_ind % 2 == 0) == add;
5,703,955✔
47
        let start_eq_end = start_ind == end_ind;
5,703,955✔
48

49
        #[allow(clippy::indexing_slicing)] // all indices are binary search results
50
        if start_eq_end && start_pos_check && end_res.is_err() {
5,703,955✔
51
            let ins = &[start, end];
2,230,567✔
52
            self.intervals
2,230,567✔
53
                .splice(start_ind..end_ind, ins.iter().copied());
4,461,134✔
54
        } else {
55
            if start_pos_check {
3,473,388✔
56
                self.intervals[start_ind] = start;
590✔
57
                start_ind += 1;
590✔
58
            }
59
            if end_pos_check {
3,473,388✔
60
                if end_res.is_ok() {
3,473,317✔
61
                    end_ind += 1;
4,023✔
62
                } else {
63
                    end_ind -= 1;
3,469,294✔
64
                    self.intervals[end_ind] = end;
3,469,294✔
65
                }
66
            }
67
            if start_ind < end_ind {
3,473,388✔
68
                self.intervals.drain(start_ind..end_ind);
3,521✔
69
            }
70
        }
71
    }
5,705,040✔
72

73
    /// Add the range to the [`CodePointInversionListBuilder`]
74
    ///
75
    /// Accomplishes this through binary search for the start and end indices and merges intervals
76
    /// in between with inplace memory. Performs `O(1)` operation if adding to end of list, and `O(N)` otherwise,
77
    /// where `N` is the number of endpoints.
78
    fn add(&mut self, start: u32, end: u32) {
5,706,266✔
79
        if start >= end {
5,706,266✔
80
            return;
81
        }
82
        if self.intervals.is_empty() {
5,706,003✔
83
            self.intervals.extend_from_slice(&[start, end]);
4,479✔
84
            return;
85
        }
86
        self.add_remove_middle(start, end, true);
5,701,524✔
87
    }
5,706,266✔
88

89
    /// Add the character to the [`CodePointInversionListBuilder`]
90
    ///
91
    /// # Examples
92
    ///
93
    /// ```
94
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
95
    /// let mut builder = CodePointInversionListBuilder::new();
96
    /// builder.add_char('a');
97
    /// let check = builder.build();
98
    /// assert_eq!(check.iter_chars().next(), Some('a'));
99
    /// ```
100
    pub fn add_char(&mut self, c: char) {
5,677✔
101
        let to_add = c as u32;
5,677✔
102
        self.add(to_add, to_add + 1);
5,677✔
103
    }
5,677✔
104

105
    /// Add the code point value to the [`CodePointInversionListBuilder`]
106
    ///
107
    /// Note: Even though [`u32`] and [`prim@char`] in Rust are non-negative 4-byte
108
    /// values, there is an important difference. A [`u32`] can take values up to
109
    /// a very large integer value, while a [`prim@char`] in Rust is defined to be in
110
    /// the range from 0 to the maximum valid Unicode Scalar Value.
111
    ///
112
    /// # Examples
113
    ///
114
    /// ```
115
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
116
    /// let mut builder = CodePointInversionListBuilder::new();
117
    /// builder.add32(0x41);
118
    /// let check = builder.build();
119
    /// assert!(check.contains32(0x41));
120
    /// ```
121
    pub fn add32(&mut self, c: u32) {
1✔
122
        if c <= char::MAX as u32 {
1✔
123
            // we already know 0 <= c  because c: u32
124
            self.add(c, c + 1);
1✔
125
        }
126
    }
1✔
127

128
    /// Add the range of characters to the [`CodePointInversionListBuilder`]
129
    ///
130
    /// # Examples
131
    ///
132
    /// ```
133
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
134
    /// let mut builder = CodePointInversionListBuilder::new();
135
    /// builder.add_range(&('A'..='Z'));
136
    /// let check = builder.build();
137
    /// assert_eq!(check.iter_chars().next(), Some('A'));
138
    /// ```
139
    pub fn add_range(&mut self, range: &impl RangeBounds<char>) {
269✔
140
        let (start, end) = deconstruct_range(range);
269✔
141
        self.add(start, end);
269✔
142
    }
269✔
143

144
    /// Add the range of characters, represented as u32, to the [`CodePointInversionListBuilder`]
145
    ///
146
    /// # Examples
147
    ///
148
    /// ```
149
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
150
    /// let mut builder = CodePointInversionListBuilder::new();
151
    /// builder.add_range32(&(0xd800..=0xdfff));
152
    /// let check = builder.build();
153
    /// assert!(check.contains32(0xd900));
154
    /// ```
155
    pub fn add_range32(&mut self, range: &impl RangeBounds<u32>) {
5,667,129✔
156
        let (start, end) = deconstruct_range(range);
5,667,129✔
157
        // Sets that include char::MAX need to allow an end value of MAX + 1
158
        if start <= end && end <= char::MAX as u32 + 1 {
5,667,129✔
159
            self.add(start, end);
5,667,279✔
160
        }
161
    }
5,667,429✔
162

163
    /// Add the [`CodePointInversionList`] reference to the [`CodePointInversionListBuilder`]
164
    ///
165
    /// # Examples
166
    ///
167
    /// ```
168
    /// use icu::collections::codepointinvlist::{
169
    ///     CodePointInversionList, CodePointInversionListBuilder,
170
    /// };
171
    /// let mut builder = CodePointInversionListBuilder::new();
172
    /// let set =
173
    ///     CodePointInversionList::try_from_inversion_list_slice(&[0x41, 0x4C])
174
    ///         .unwrap();
175
    /// builder.add_set(&set);
176
    /// let check = builder.build();
177
    /// assert_eq!(check.iter_chars().next(), Some('A'));
178
    /// ```
179
    #[allow(unused_assignments)]
180
    pub fn add_set(&mut self, set: &CodePointInversionList) {
301✔
181
        #[allow(clippy::indexing_slicing)] // chunks
182
        set.as_inversion_list()
602✔
183
            .as_ule_slice()
184
            .chunks(2)
185
            .for_each(|pair| {
33,924✔
186
                self.add(
67,246✔
187
                    AsULE::from_unaligned(pair[0]),
33,623✔
188
                    AsULE::from_unaligned(pair[1]),
33,623✔
189
                )
190
            });
33,623✔
191
    }
301✔
192

193
    /// Removes the range from the [`CodePointInversionListBuilder`]
194
    ///
195
    /// Performs binary search to find start and end affected intervals, then removes in an `O(N)` fashion
196
    /// where `N` is the number of endpoints, with in-place memory.
197
    fn remove(&mut self, start: u32, end: u32) {
1,442✔
198
        if start >= end || self.intervals.is_empty() {
1,442✔
199
            return;
200
        }
201
        if let Some(&last) = self.intervals.last() {
1,435✔
202
            #[allow(clippy::indexing_slicing)]
203
            // by invariant, if we have a last we have a (different) first
204
            if start <= self.intervals[0] && end >= last {
1,435✔
205
                self.intervals.clear();
11✔
206
            } else {
207
                self.add_remove_middle(start, end, false);
1,424✔
208
            }
209
        }
210
    }
1,442✔
211

212
    /// Remove the character from the [`CodePointInversionListBuilder`]
213
    ///
214
    /// # Examples
215
    ///
216
    /// ```
217
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
218
    /// let mut builder = CodePointInversionListBuilder::new();
219
    /// builder.add_range(&('A'..='Z'));
220
    /// builder.remove_char('A');
221
    /// let check = builder.build();
222
    /// assert_eq!(check.iter_chars().next(), Some('B'));
223
    pub fn remove_char(&mut self, c: char) {
2✔
224
        self.remove32(c as u32)
2✔
225
    }
2✔
226

227
    /// See [`Self::remove_char`]
228
    pub fn remove32(&mut self, c: u32) {
2✔
229
        self.remove(c, c + 1);
2✔
230
    }
2✔
231

232
    /// Remove the range of characters from the [`CodePointInversionListBuilder`]
233
    ///
234
    /// # Examples
235
    ///
236
    /// ```
237
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
238
    /// let mut builder = CodePointInversionListBuilder::new();
239
    /// builder.add_range(&('A'..='Z'));
240
    /// builder.remove_range(&('A'..='C'));
241
    /// let check = builder.build();
242
    /// assert_eq!(check.iter_chars().next(), Some('D'));
243
    pub fn remove_range(&mut self, range: &impl RangeBounds<char>) {
1✔
244
        let (start, end) = deconstruct_range(range);
1✔
245
        self.remove(start, end);
1✔
246
    }
1✔
247

248
    /// See [`Self::remove_range`]
UNCOV
249
    pub fn remove_range32(&mut self, range: &impl RangeBounds<u32>) {
×
UNCOV
250
        let (start, end) = deconstruct_range(range);
×
UNCOV
251
        self.remove(start, end);
×
UNCOV
252
    }
×
253

254
    /// Remove the [`CodePointInversionList`] from the [`CodePointInversionListBuilder`]
255
    ///
256
    /// # Examples
257
    ///
258
    /// ```
259
    /// use icu::collections::codepointinvlist::{CodePointInversionList, CodePointInversionListBuilder};
260
    /// let mut builder = CodePointInversionListBuilder::new();
261
    /// let set = CodePointInversionList::try_from_inversion_list_slice(&[0x41, 0x46]).unwrap();
262
    /// builder.add_range(&('A'..='Z'));
263
    /// builder.remove_set(&set); // removes 'A'..='E'
264
    /// let check = builder.build();
265
    /// assert_eq!(check.iter_chars().next(), Some('F'));
266
    #[allow(clippy::indexing_slicing)] // chunks
267
    pub fn remove_set(&mut self, set: &CodePointInversionList) {
29✔
268
        set.as_inversion_list()
58✔
269
            .as_ule_slice()
270
            .chunks(2)
271
            .for_each(|pair| {
1,382✔
272
                self.remove(
2,706✔
273
                    AsULE::from_unaligned(pair[0]),
1,353✔
274
                    AsULE::from_unaligned(pair[1]),
1,353✔
275
                )
276
            });
1,353✔
277
    }
29✔
278

279
    /// Retain the specified character in the [`CodePointInversionListBuilder`] if it exists
280
    ///
281
    /// # Examples
282
    ///
283
    /// ```
284
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
285
    /// let mut builder = CodePointInversionListBuilder::new();
286
    /// builder.add_range(&('A'..='Z'));
287
    /// builder.retain_char('A');
288
    /// let set = builder.build();
289
    /// let mut check = set.iter_chars();
290
    /// assert_eq!(check.next(), Some('A'));
291
    /// assert_eq!(check.next(), None);
292
    /// ```
293
    pub fn retain_char(&mut self, c: char) {
2✔
294
        self.retain32(c as u32)
2✔
295
    }
2✔
296

297
    /// See [`Self::retain_char`]
298
    pub fn retain32(&mut self, c: u32) {
2✔
299
        self.remove(0, c);
2✔
300
        self.remove(c + 1, (char::MAX as u32) + 1);
2✔
301
    }
2✔
302

303
    /// Retain the range of characters located within the [`CodePointInversionListBuilder`]
304
    ///
305
    /// # Examples
306
    ///
307
    /// ```
308
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
309
    /// let mut builder = CodePointInversionListBuilder::new();
310
    /// builder.add_range(&('A'..='Z'));
311
    /// builder.retain_range(&('A'..='B'));
312
    /// let set = builder.build();
313
    /// let mut check = set.iter_chars();
314
    /// assert_eq!(check.next(), Some('A'));
315
    /// assert_eq!(check.next(), Some('B'));
316
    /// assert_eq!(check.next(), None);
317
    /// ```
318
    pub fn retain_range(&mut self, range: &impl RangeBounds<char>) {
2✔
319
        let (start, end) = deconstruct_range(range);
2✔
320
        self.remove(0, start);
2✔
321
        self.remove(end, (char::MAX as u32) + 1);
2✔
322
    }
2✔
323

324
    /// See [`Self::retain_range`]
UNCOV
325
    pub fn retain_range32(&mut self, range: &impl RangeBounds<u32>) {
×
UNCOV
326
        let (start, end) = deconstruct_range(range);
×
UNCOV
327
        self.remove(0, start);
×
UNCOV
328
        self.remove(end, (char::MAX as u32) + 1);
×
UNCOV
329
    }
×
330

331
    /// Retain the elements in the specified set within the [`CodePointInversionListBuilder`]
332
    ///
333
    /// # Examples
334
    ///
335
    /// ```
336
    /// use icu::collections::codepointinvlist::{
337
    ///     CodePointInversionList, CodePointInversionListBuilder,
338
    /// };
339
    /// let mut builder = CodePointInversionListBuilder::new();
340
    /// let set = CodePointInversionList::try_from_inversion_list_slice(&[65, 70])
341
    ///     .unwrap();
342
    /// builder.add_range(&('A'..='Z'));
343
    /// builder.retain_set(&set); // retains 'A'..='E'
344
    /// let check = builder.build();
345
    /// assert!(check.contains('A'));
346
    /// assert!(!check.contains('G'));
347
    /// ```
348
    #[allow(clippy::indexing_slicing)] // chunks
349
    pub fn retain_set(&mut self, set: &CodePointInversionList) {
27✔
350
        let mut prev = 0;
27✔
351
        for pair in set.as_inversion_list().as_ule_slice().chunks(2) {
63✔
352
            let range_start = AsULE::from_unaligned(pair[0]);
36✔
353
            let range_limit = AsULE::from_unaligned(pair[1]);
36✔
354
            self.remove(prev, range_start);
36✔
355
            prev = range_limit;
36✔
356
        }
357
        self.remove(prev, (char::MAX as u32) + 1);
27✔
358
    }
27✔
359

360
    /// Computes the complement of the argument, adding any elements that do not yet exist in the builder,
361
    /// and removing any elements that already exist in the builder. See public functions for examples.
362
    ///
363
    /// Performs in `O(B + S)`, where `B` is the number of endpoints in the Builder, and `S` is the number
364
    /// of endpoints in the argument.
365
    fn complement_list(&mut self, set_iter: impl core::iter::Iterator<Item = u32>) {
10✔
366
        let mut res: Vec<u32> = vec![]; // not the biggest fan of having to allocate new memory
10✔
367
        let mut ai = self.intervals.iter();
10✔
368
        let mut bi = set_iter;
10✔
369
        let mut a = ai.next();
10✔
370
        let mut b = bi.next();
10✔
371
        while let (Some(c), Some(d)) = (a, b) {
43✔
372
            match c.cmp(&d) {
33✔
373
                Ordering::Less => {
15✔
374
                    res.push(*c);
15✔
375
                    a = ai.next();
15✔
376
                }
377
                Ordering::Greater => {
13✔
378
                    res.push(d);
13✔
379
                    b = bi.next();
13✔
380
                }
381
                Ordering::Equal => {
5✔
382
                    a = ai.next();
5✔
383
                    b = bi.next();
5✔
384
                }
385
            }
386
        }
387
        if let Some(c) = a {
10✔
388
            res.push(*c)
4✔
389
        }
390
        if let Some(d) = b {
10✔
391
            res.push(d)
6✔
392
        }
393
        res.extend(ai);
10✔
394
        res.extend(bi);
10✔
395
        self.intervals = res;
10✔
396
    }
10✔
397

398
    /// Computes the complement of the builder, inverting the builder (any elements in the builder are removed,
399
    /// while any elements not in the builder are added)
400
    ///
401
    /// # Examples
402
    ///
403
    /// ```
404
    /// use icu::collections::codepointinvlist::{
405
    ///     CodePointInversionList, CodePointInversionListBuilder,
406
    /// };
407
    /// let mut builder = CodePointInversionListBuilder::new();
408
    /// let set = CodePointInversionList::try_from_inversion_list_slice(&[
409
    ///     0x0,
410
    ///     0x41,
411
    ///     0x46,
412
    ///     (std::char::MAX as u32) + 1,
413
    /// ])
414
    /// .unwrap();
415
    /// builder.add_set(&set);
416
    /// builder.complement();
417
    /// let check = builder.build();
418
    /// assert_eq!(check.iter_chars().next(), Some('A'));
419
    /// ```
420
    pub fn complement(&mut self) {
186✔
421
        if !self.intervals.is_empty() {
186✔
422
            #[allow(clippy::indexing_slicing)] // by invariant
423
            if self.intervals[0] == 0 {
179✔
424
                self.intervals.drain(0..1);
18✔
425
            } else {
426
                self.intervals.insert(0, 0);
161✔
427
            }
428
            if self.intervals.last() == Some(&(char::MAX as u32 + 1)) {
179✔
429
                self.intervals.pop();
17✔
430
            } else {
431
                self.intervals.push(char::MAX as u32 + 1);
162✔
432
            }
433
        } else {
434
            self.intervals
7✔
435
                .extend_from_slice(&[0, (char::MAX as u32 + 1)]);
436
        }
437
    }
186✔
438

439
    /// Complements the character in the builder, adding it if not in the builder, and removing it otherwise.
440
    ///
441
    /// # Examples
442
    ///
443
    /// ```
444
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
445
    /// let mut builder = CodePointInversionListBuilder::new();
446
    /// builder.add_range(&('A'..='D'));
447
    /// builder.complement_char('A');
448
    /// builder.complement_char('E');
449
    /// let check = builder.build();
450
    /// assert!(check.contains('E'));
451
    /// assert!(!check.contains('A'));
452
    /// ```
453
    pub fn complement_char(&mut self, c: char) {
4✔
454
        self.complement32(c as u32);
4✔
455
    }
4✔
456

457
    /// See [`Self::complement_char`]
458
    pub fn complement32(&mut self, c: u32) {
4✔
459
        self.complement_list([c, c + 1].into_iter());
4✔
460
    }
4✔
461

462
    /// Complements the range in the builder, adding any elements in the range if not in the builder, and
463
    /// removing them otherwise.
464
    ///
465
    /// # Examples
466
    ///
467
    /// ```
468
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
469
    /// let mut builder = CodePointInversionListBuilder::new();
470
    /// builder.add_range(&('A'..='D'));
471
    /// builder.complement_range(&('C'..='F'));
472
    /// let check = builder.build();
473
    /// assert!(check.contains('F'));
474
    /// assert!(!check.contains('C'));
475
    /// ```
476
    pub fn complement_range(&mut self, range: &impl RangeBounds<char>) {
1✔
477
        let (start, end) = deconstruct_range(range);
1✔
478
        let to_complement = [start, end];
1✔
479
        self.complement_list(to_complement.iter().copied());
1✔
480
    }
1✔
481

482
    /// See [`Self::complement_range`]
UNCOV
483
    pub fn complement_range32(&mut self, range: &impl RangeBounds<u32>) {
×
UNCOV
484
        let (start, end) = deconstruct_range(range);
×
UNCOV
485
        let to_complement = [start, end];
×
UNCOV
486
        self.complement_list(to_complement.iter().copied());
×
UNCOV
487
    }
×
488

489
    /// Complements the set in the builder, adding any elements in the set if not in the builder, and
490
    /// removing them otherwise.
491
    ///
492
    /// # Examples
493
    ///
494
    /// ```
495
    /// use icu::collections::codepointinvlist::{
496
    ///     CodePointInversionList, CodePointInversionListBuilder,
497
    /// };
498
    /// let mut builder = CodePointInversionListBuilder::new();
499
    /// let set = CodePointInversionList::try_from_inversion_list_slice(&[
500
    ///     0x41, 0x46, 0x4B, 0x5A,
501
    /// ])
502
    /// .unwrap();
503
    /// builder.add_range(&('C'..='N')); // 67 - 78
504
    /// builder.complement_set(&set);
505
    /// let check = builder.build();
506
    /// assert!(check.contains('Q')); // 81
507
    /// assert!(!check.contains('N')); // 78
508
    /// ```
509
    pub fn complement_set(&mut self, set: &CodePointInversionList) {
2✔
510
        let inv_list_iter_owned = set.as_inversion_list().iter();
2✔
511
        self.complement_list(inv_list_iter_owned);
2✔
512
    }
2✔
513

514
    /// Returns whether the build is empty.
515
    ///
516
    /// # Examples
517
    ///
518
    /// ```
519
    /// use icu::collections::codepointinvlist::CodePointInversionListBuilder;
520
    /// let mut builder = CodePointInversionListBuilder::new();
521
    /// let check = builder.build();
522
    /// assert!(check.is_empty());
523
    /// ```
524
    pub fn is_empty(&self) -> bool {
1✔
525
        self.intervals.is_empty()
1✔
526
    }
1✔
527
}
528

529
#[cfg(test)]
530
mod tests {
531
    use super::{CodePointInversionList, CodePointInversionListBuilder};
532
    use core::char;
533
    use zerovec::ZeroVec;
534

535
    fn generate_tester(ex: &[u32]) -> CodePointInversionListBuilder {
43✔
536
        let inv_list = ZeroVec::<u32>::alloc_from_slice(ex);
43✔
537
        let check = CodePointInversionList::try_from_inversion_list(inv_list).unwrap();
43✔
538
        let mut builder = CodePointInversionListBuilder::new();
43✔
539
        builder.add_set(&check);
43✔
540
        builder
43✔
541
    }
43✔
542

543
    #[test]
544
    fn test_new() {
2✔
545
        let ex = CodePointInversionListBuilder::new();
1✔
546
        assert!(ex.intervals.is_empty());
1✔
547
    }
2✔
548

549
    #[test]
550
    fn test_build() {
2✔
551
        let mut builder = CodePointInversionListBuilder::new();
1✔
552
        builder.add(0x41, 0x42);
1✔
553
        let check: CodePointInversionList = builder.build();
1✔
554
        assert_eq!(check.iter_chars().next(), Some('A'));
1✔
555
    }
2✔
556

557
    #[test]
558
    fn test_empty_build() {
2✔
559
        let builder = CodePointInversionListBuilder::new();
1✔
560
        let check: CodePointInversionList = builder.build();
1✔
561
        assert!(check.is_empty());
1✔
562
    }
2✔
563

564
    #[test]
565
    fn test_add_to_empty() {
2✔
566
        let mut builder = CodePointInversionListBuilder::new();
1✔
567
        builder.add(0x0, 0xA);
1✔
568
        assert_eq!(builder.intervals, [0x0, 0xA]);
1✔
569
    }
2✔
570

571
    #[test]
572
    fn test_add_invalid() {
2✔
573
        let mut builder = CodePointInversionListBuilder::new();
1✔
574
        builder.add(0x0, 0x0);
1✔
575
        builder.add(0x5, 0x0);
1✔
576
        assert!(builder.intervals.is_empty());
1✔
577
    }
2✔
578

579
    #[test]
580
    fn test_add_to_start() {
2✔
581
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
582
        builder.add(0x0, 0x5);
1✔
583
        let expected = [0x0, 0x5, 0xA, 0x14, 0x28, 0x32];
1✔
584
        assert_eq!(builder.intervals, expected);
1✔
585
    }
2✔
586

587
    #[test]
588
    fn test_add_to_start_overlap() {
2✔
589
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
590
        builder.add(0x0, 0xE);
1✔
591
        let expected = [0x0, 0x14, 0x28, 0x32];
1✔
592
        assert_eq!(builder.intervals, expected);
1✔
593
    }
2✔
594

595
    #[test]
596
    fn test_add_to_end() {
2✔
597
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
598
        builder.add(0x3C, 0x46);
1✔
599
        let expected = [0xA, 0x14, 0x28, 0x32, 60, 70];
1✔
600
        assert_eq!(builder.intervals, expected);
1✔
601
    }
2✔
602

603
    #[test]
604
    fn test_add_to_end_overlap() {
2✔
605
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
606
        builder.add(0x2B, 0x46);
1✔
607
        let expected = [0xA, 0x14, 0x28, 0x46];
1✔
608
        assert_eq!(builder.intervals, expected);
1✔
609
    }
2✔
610

611
    #[test]
612
    fn test_add_to_middle_no_overlap() {
2✔
613
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
614
        builder.add(0x19, 0x1B);
1✔
615
        let expected = [0xA, 0x14, 0x19, 0x1B, 0x28, 0x32];
1✔
616
        assert_eq!(builder.intervals, expected);
1✔
617
    }
2✔
618

619
    #[test]
620
    fn test_add_to_middle_inside() {
2✔
621
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
622
        builder.add(0xA, 0x14);
1✔
623
        let expected = [0xA, 0x14, 0x28, 0x32];
1✔
624
        assert_eq!(builder.intervals, expected);
1✔
625
    }
2✔
626

627
    #[test]
628
    fn test_add_to_middle_left_overlap() {
2✔
629
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
630
        builder.add(0xF, 0x19);
1✔
631
        let expected = [0xA, 0x19, 0x28, 0x32];
1✔
632
        assert_eq!(builder.intervals, expected);
1✔
633
    }
2✔
634

635
    #[test]
636
    fn test_add_to_middle_right_overlap() {
2✔
637
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
638
        builder.add(0x1E, 0x28);
1✔
639
        let expected = [0xA, 0x14, 0x1E, 0x32];
1✔
640
        assert_eq!(builder.intervals, expected);
1✔
641
    }
2✔
642

643
    #[test]
644
    fn test_add_to_full_encompass() {
2✔
645
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
646
        builder.add(0x0, 0x3C);
1✔
647
        let expected = [0x0, 0x3C];
1✔
648
        assert_eq!(builder.intervals, expected);
1✔
649
    }
2✔
650

651
    #[test]
652
    fn test_add_to_partial_encompass() {
2✔
653
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
654
        builder.add(0x0, 0x23);
1✔
655
        let expected = [0x0, 0x23, 0x28, 0x32];
1✔
656
        assert_eq!(builder.intervals, expected);
1✔
657
    }
2✔
658

659
    #[test]
660
    fn test_add_aligned_front() {
2✔
661
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
662
        builder.add(5, 10);
1✔
663
        let expected = [5, 0x14, 0x28, 0x32];
1✔
664
        assert_eq!(builder.intervals, expected);
1✔
665
    }
2✔
666

667
    #[test]
668
    fn test_add_aligned_back() {
2✔
669
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
670
        builder.add(0x32, 0x37);
1✔
671
        let expected = [0xA, 0x14, 0x28, 0x37];
1✔
672
        assert_eq!(builder.intervals, expected);
1✔
673
    }
2✔
674

675
    #[test]
676
    fn test_add_aligned_start_middle() {
2✔
677
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
678
        builder.add(0x14, 0x19);
1✔
679
        let expected = [0xA, 0x19, 0x28, 0x32];
1✔
680
        assert_eq!(builder.intervals, expected);
1✔
681
    }
2✔
682

683
    #[test]
684
    fn test_add_aligned_end_middle() {
2✔
685
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
686
        builder.add(0x23, 0x28);
1✔
687
        let expected = [0xA, 0x14, 0x23, 0x32];
1✔
688
        assert_eq!(builder.intervals, expected);
1✔
689
    }
2✔
690

691
    #[test]
692
    fn test_add_aligned_in_between_end() {
2✔
693
        let mut builder = generate_tester(&[0xA, 0x14, 0x1E, 0x28, 0x32, 0x3C]);
1✔
694
        builder.add(0xF, 0x1E);
1✔
695
        let expected = [0xA, 0x28, 0x32, 0x3C];
1✔
696
        assert_eq!(builder.intervals, expected);
1✔
697
    }
2✔
698

699
    #[test]
700
    fn test_add_aligned_in_between_start() {
2✔
701
        let mut builder = generate_tester(&[0xA, 0x14, 0x1E, 0x28, 0x32, 0x3C]);
1✔
702
        builder.add(20, 35);
1✔
703
        let expected = [0xA, 0x28, 0x32, 0x3C];
1✔
704
        assert_eq!(builder.intervals, expected);
1✔
705
    }
2✔
706

707
    #[test]
708
    fn test_add_adjacent_ranges() {
2✔
709
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
710
        builder.add(0x13, 0x14);
1✔
711
        builder.add(0x14, 0x15);
1✔
712
        builder.add(0x15, 0x16);
1✔
713
        let expected = [0xA, 0x16, 0x28, 0x32];
1✔
714
        assert_eq!(builder.intervals, expected);
1✔
715
    }
2✔
716

717
    #[test]
718
    fn test_add_codepointinversionlist() {
2✔
719
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
720
        let check = CodePointInversionList::try_from_inversion_list_slice(&[
1✔
721
            0x5, 0xA, 0x16, 0x21, 0x2C, 0x33,
722
        ])
723
        .unwrap();
724
        builder.add_set(&check);
1✔
725
        let expected = [0x5, 0x14, 0x16, 0x21, 0x28, 0x33];
1✔
726
        assert_eq!(builder.intervals, expected);
1✔
727
    }
2✔
728
    #[test]
729
    fn test_add_char() {
2✔
730
        let mut builder = CodePointInversionListBuilder::new();
1✔
731
        builder.add_char('a');
1✔
732
        let expected = [0x61, 0x62];
1✔
733
        assert_eq!(builder.intervals, expected);
1✔
734
    }
2✔
735

736
    #[test]
737
    fn test_add_range() {
2✔
738
        let mut builder = CodePointInversionListBuilder::new();
1✔
739
        builder.add_range(&('A'..='Z'));
1✔
740
        let expected = [0x41, 0x5B];
1✔
741
        assert_eq!(builder.intervals, expected);
1✔
742
    }
2✔
743

744
    #[test]
745
    fn test_add_range32() {
2✔
746
        let mut builder = CodePointInversionListBuilder::new();
1✔
747
        builder.add_range32(&(0xd800..=0xdfff));
1✔
748
        let expected = [0xd800, 0xe000];
1✔
749
        assert_eq!(builder.intervals, expected);
1✔
750
    }
2✔
751

752
    #[test]
753
    fn test_add_invalid_range() {
2✔
754
        let mut builder = CodePointInversionListBuilder::new();
1✔
755
        builder.add_range(&('Z'..='A'));
1✔
756
        assert!(builder.intervals.is_empty());
1✔
757
    }
2✔
758

759
    #[test]
760
    fn test_remove_empty() {
2✔
761
        let mut builder = CodePointInversionListBuilder::new();
1✔
762
        builder.remove(0x0, 0xA);
1✔
763
        assert!(builder.intervals.is_empty());
1✔
764
    }
2✔
765

766
    #[test]
767
    fn test_remove_entire_builder() {
2✔
768
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
769
        builder.remove(0xA, 0x32);
1✔
770
        assert!(builder.intervals.is_empty());
1✔
771
    }
2✔
772

773
    #[test]
774
    fn test_remove_entire_range() {
2✔
775
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
776
        builder.remove(0xA, 0x14);
1✔
777
        let expected = [0x28, 0x32];
1✔
778
        assert_eq!(builder.intervals, expected);
1✔
779
    }
2✔
780

781
    #[test]
782
    fn test_remove_partial_range_left() {
2✔
783
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
784
        builder.remove(0xA, 0x2B);
1✔
785
        let expected = [0x2B, 0x32];
1✔
786
        assert_eq!(builder.intervals, expected);
1✔
787
    }
2✔
788

789
    #[test]
790
    fn test_remove_ne_range() {
2✔
791
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
792
        builder.remove(0x14, 0x28);
1✔
793
        let expected = [0xA, 0x14, 0x28, 0x32];
1✔
794
        assert_eq!(builder.intervals, expected);
1✔
795
    }
2✔
796

797
    #[test]
798
    fn test_remove_partial_range_right() {
2✔
799
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
800
        builder.remove(0xF, 0x37);
1✔
801
        let expected = [0xA, 0xF];
1✔
802
        assert_eq!(builder.intervals, expected);
1✔
803
    }
2✔
804

805
    #[test]
806
    fn test_remove_middle_range() {
2✔
807
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
808
        builder.remove(0xC, 0x12);
1✔
809
        let expected = [0xA, 0xC, 0x12, 0x14, 0x28, 0x32];
1✔
810
        assert_eq!(builder.intervals, expected);
1✔
811
    }
2✔
812

813
    #[test]
814
    fn test_remove_ne_middle_range() {
2✔
815
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
816
        builder.remove(0x19, 0x1B);
1✔
817
        let expected = [0xA, 0x14, 0x28, 0x32];
1✔
818
        assert_eq!(builder.intervals, expected);
1✔
819
    }
2✔
820

821
    #[test]
822
    fn test_remove_encompassed_range() {
2✔
823
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32, 70, 80]);
1✔
824
        builder.remove(0x19, 0x37);
1✔
825
        let expected = [0xA, 0x14, 0x46, 0x50];
1✔
826
        assert_eq!(builder.intervals, expected);
1✔
827
    }
2✔
828
    #[test]
829
    fn test_remove_adjacent_ranges() {
2✔
830
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
831
        builder.remove(0x27, 0x28);
1✔
832
        builder.remove(0x28, 0x29);
1✔
833
        builder.remove(0x29, 0x2A);
1✔
834
        let expected = [0xA, 0x14, 0x2A, 0x32];
1✔
835
        assert_eq!(builder.intervals, expected);
1✔
836
    }
2✔
837

838
    #[test]
839
    fn test_remove_char() {
2✔
840
        let mut builder = generate_tester(&[0x41, 0x46]);
1✔
841
        builder.remove_char('A'); // 65
1✔
842
        let expected = [0x42, 0x46];
1✔
843
        assert_eq!(builder.intervals, expected);
1✔
844
    }
2✔
845

846
    #[test]
847
    fn test_remove_range() {
2✔
848
        let mut builder = generate_tester(&[0x41, 0x5A]);
1✔
849
        builder.remove_range(&('A'..'L')); // 65 - 76
1✔
850
        let expected = [0x4C, 0x5A];
1✔
851
        assert_eq!(builder.intervals, expected);
1✔
852
    }
2✔
853

854
    #[test]
855
    fn test_remove_set() {
2✔
856
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32, 70, 80]);
1✔
857
        let remove =
858
            CodePointInversionList::try_from_inversion_list_slice(&[0xA, 0x14, 0x2D, 0x4B])
1✔
859
                .unwrap();
860
        builder.remove_set(&remove);
1✔
861
        let expected = [0x28, 0x2D, 0x4B, 0x50];
1✔
862
        assert_eq!(builder.intervals, expected);
1✔
863
    }
2✔
864

865
    #[test]
866
    fn test_retain_char() {
2✔
867
        let mut builder = generate_tester(&[0x41, 0x5A]);
1✔
868
        builder.retain_char('A'); // 65
1✔
869
        let expected = [0x41, 0x42];
1✔
870
        assert_eq!(builder.intervals, expected);
1✔
871
    }
2✔
872

873
    #[test]
874
    fn test_retain_range() {
2✔
875
        let mut builder = generate_tester(&[0x41, 0x5A]);
1✔
876
        builder.retain_range(&('C'..'F')); // 67 - 70
1✔
877
        let expected = [0x43, 0x46];
1✔
878
        assert_eq!(builder.intervals, expected);
1✔
879
    }
2✔
880

881
    #[test]
882
    fn test_retain_range_empty() {
2✔
883
        let mut builder = generate_tester(&[0x41, 0x46]);
1✔
884
        builder.retain_range(&('F'..'Z'));
1✔
885
        assert!(builder.intervals.is_empty());
1✔
886
    }
2✔
887

888
    #[test]
889
    fn test_retain_set() {
2✔
890
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32, 70, 80]);
1✔
891
        let retain = CodePointInversionList::try_from_inversion_list_slice(&[
1✔
892
            0xE, 0x14, 0x19, 0x37, 0x4D, 0x51,
893
        ])
894
        .unwrap();
895
        builder.retain_set(&retain);
1✔
896
        let expected = [0xE, 0x14, 0x28, 0x32, 0x4D, 0x50];
1✔
897
        assert_eq!(builder.intervals, expected);
1✔
898
    }
2✔
899

900
    #[test]
901
    fn test_complement() {
2✔
902
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
903
        builder.complement();
1✔
904
        let expected = [0x0, 0xA, 0x14, 0x28, 0x32, (char::MAX as u32) + 1];
1✔
905
        assert_eq!(builder.intervals, expected);
1✔
906
    }
2✔
907

908
    #[test]
909
    fn test_complement_empty() {
2✔
910
        let mut builder = generate_tester(&[]);
1✔
911
        builder.complement();
1✔
912
        let expected = [0x0, (char::MAX as u32) + 1];
1✔
913
        assert_eq!(builder.intervals, expected);
1✔
914

915
        builder.complement();
1✔
916
        let expected: [u32; 0] = [];
917
        assert_eq!(builder.intervals, expected);
1✔
918
    }
2✔
919

920
    #[test]
921
    fn test_complement_zero_max() {
2✔
922
        let mut builder = generate_tester(&[0x0, 0xA, 0x5A, (char::MAX as u32) + 1]);
1✔
923
        builder.complement();
1✔
924
        let expected = [0xA, 0x5A];
1✔
925
        assert_eq!(builder.intervals, expected);
1✔
926
    }
2✔
927

928
    #[test]
929
    fn test_complement_interior() {
2✔
930
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
931
        builder.complement_list([0xE, 0x14].iter().copied());
1✔
932
        let expected = [0xA, 0xE, 0x28, 0x32];
1✔
933
        assert_eq!(builder.intervals, expected);
1✔
934
    }
2✔
935

936
    #[test]
937
    fn test_complement_exterior() {
2✔
938
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
939
        builder.complement_list([0x19, 0x23].iter().copied());
1✔
940
        let expected = [0xA, 0x14, 0x19, 0x23, 0x28, 0x32];
1✔
941
        assert_eq!(builder.intervals, expected);
1✔
942
    }
2✔
943

944
    #[test]
945
    fn test_complement_larger_list() {
2✔
946
        let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]);
1✔
947
        builder.complement_list([0x1E, 0x37, 0x3C, 0x46].iter().copied());
1✔
948
        let expected = [0xA, 0x14, 0x1E, 0x28, 0x32, 0x37, 0x3C, 0x46];
1✔
949
        assert_eq!(builder.intervals, expected);
1✔
950
    }
2✔
951

952
    #[test]
953
    fn test_complement_char() {
2✔
954
        let mut builder = generate_tester(&[0x41, 0x4C]); // A - K
1✔
955
        builder.complement_char('A');
1✔
956
        builder.complement_char('L');
1✔
957
        let expected = [0x42, 0x4D];
1✔
958
        assert_eq!(builder.intervals, expected);
1✔
959
    }
2✔
960

961
    #[test]
962
    fn test_complement_range() {
2✔
963
        let mut builder = generate_tester(&[0x46, 0x4C]); // F - K
1✔
964
        builder.complement_range(&('A'..='Z'));
1✔
965
        let expected = [0x41, 0x46, 0x4C, 0x5B];
1✔
966
        assert_eq!(builder.intervals, expected);
1✔
967
    }
2✔
968

969
    #[test]
970
    fn test_complement_set() {
2✔
971
        let mut builder = generate_tester(&[0x43, 0x4E]);
1✔
972
        let set = CodePointInversionList::try_from_inversion_list_slice(&[0x41, 0x46, 0x4B, 0x5A])
1✔
973
            .unwrap();
974
        builder.complement_set(&set);
1✔
975
        let expected = [0x41, 0x43, 0x46, 0x4B, 0x4E, 0x5A];
1✔
976
        assert_eq!(builder.intervals, expected);
1✔
977
    }
2✔
978

979
    #[test]
980
    fn test_is_empty() {
2✔
981
        let builder = CodePointInversionListBuilder::new();
1✔
982
        assert!(builder.is_empty());
1✔
983
    }
2✔
984
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc