unic_char_property/
tables.rs

1// Copyright 2017 The UNIC Project Developers.
2//
3// See the COPYRIGHT file at the top-level directory of this distribution.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Character data tables used in UNIC.
12
13use unic_char_range::CharRange;
14
15/// A mapping from characters to some associated data.
16///
17/// For the set case, use `()` as the associated value.
18#[derive(Copy, Clone, Debug)]
19pub enum CharDataTable<V: 'static> {
20    #[doc(hidden)]
21    Direct(&'static [(char, V)]),
22    #[doc(hidden)]
23    Range(&'static [(CharRange, V)]),
24}
25
26impl<V> Default for CharDataTable<V> {
27    fn default() -> Self {
28        CharDataTable::Direct(&[])
29    }
30}
31
32impl<V> CharDataTable<V> {
33    /// Does this table contain a mapping for a character?
34    pub fn contains(&self, needle: char) -> bool {
35        match *self {
36            CharDataTable::Direct(table) => {
37                table.binary_search_by_key(&needle, |&(k, _)| k).is_ok()
38            }
39            CharDataTable::Range(table) => table
40                .binary_search_by(|&(range, _)| range.cmp_char(needle))
41                .is_ok(),
42        }
43    }
44}
45
46impl<V: Copy> CharDataTable<V> {
47    /// Find the associated data for a character in this table.
48    pub fn find(&self, needle: char) -> Option<V> {
49        match *self {
50            CharDataTable::Direct(table) => table
51                .binary_search_by_key(&needle, |&(k, _)| k)
52                .map(|idx| table[idx].1)
53                .ok(),
54            CharDataTable::Range(table) => table
55                .binary_search_by(|&(range, _)| range.cmp_char(needle))
56                .map(|idx| table[idx].1)
57                .ok(),
58        }
59    }
60
61    /// Find the range and the associated data for a character in the range table.
62    pub fn find_with_range(&self, needle: char) -> Option<(CharRange, V)> {
63        match *self {
64            CharDataTable::Direct(_) => None,
65            CharDataTable::Range(table) => table
66                .binary_search_by(|&(range, _)| range.cmp_char(needle))
67                .map(|idx| table[idx])
68                .ok(),
69        }
70    }
71}
72
73impl<V: Copy + Default> CharDataTable<V> {
74    /// Find the associated data for a character in this table, or the default value if not entered.
75    pub fn find_or_default(&self, needle: char) -> V {
76        self.find(needle).unwrap_or_else(Default::default)
77    }
78}
79
80/// Iterator for `CharDataTable`. Iterates over pairs `(CharRange, V)`.
81#[derive(Debug)]
82pub struct CharDataTableIter<'a, V: 'static>(&'a CharDataTable<V>, usize);
83
84impl<'a, V: Copy> Iterator for CharDataTableIter<'a, V> {
85    type Item = (CharRange, V);
86
87    fn next(&mut self) -> Option<Self::Item> {
88        match *self.0 {
89            CharDataTable::Direct(arr) => {
90                if self.1 >= arr.len() {
91                    None
92                } else {
93                    let idx = self.1;
94                    self.1 += 1;
95                    let (ch, v) = arr[idx];
96                    Some((chars!(ch..=ch), v))
97                }
98            }
99            CharDataTable::Range(arr) => {
100                if self.1 >= arr.len() {
101                    None
102                } else {
103                    let idx = self.1;
104                    self.1 += 1;
105                    Some(arr[idx])
106                }
107            }
108        }
109    }
110}
111
112impl<V> CharDataTable<V> {
113    /// Iterate over the entries in this table. Yields pairs `(CharRange, V)`.
114    pub fn iter(&self) -> CharDataTableIter<'_, V> {
115        CharDataTableIter(self, 0)
116    }
117}