fontconfig/
charset.rs

1//!
2
3use std::fmt;
4use std::ops::{Deref, DerefMut};
5use std::ptr::{self, NonNull};
6
7use fontconfig_sys as sys;
8use sys::ffi_dispatch;
9
10#[cfg(feature = "dlopen")]
11use sys::statics::LIB;
12#[cfg(not(feature = "dlopen"))]
13use sys::*;
14
15use crate::FcTrue;
16
17/// Wrapper around `FcCharSet`.
18pub struct OwnedCharSet {
19    pub(crate) fcset: NonNull<sys::FcCharSet>,
20}
21
22/// Wrapper around `FcCharSet`.
23#[repr(transparent)]
24pub struct CharSet {
25    pub(crate) fcset: sys::FcCharSet,
26}
27
28impl CharSet {
29    /// Count entries in a charset
30    pub fn len(&self) -> usize {
31        let size = unsafe { ffi_dispatch!(LIB, FcCharSetCount, self.as_ptr()) };
32        size as usize
33    }
34
35    /// Check if charset has entries
36    pub fn is_empty(&self) -> bool {
37        self.len() == 0
38    }
39
40    /// Check if a character is in the `CharSet`.
41    pub fn has_char(&self, c: char) -> bool {
42        let res = unsafe { ffi_dispatch!(LIB, FcCharSetHasChar, self.as_ptr(), c as u32) };
43        res == FcTrue
44    }
45
46    /// Check if self is a subset of other `CharSet`.
47    pub fn is_subset(&self, other: &Self) -> bool {
48        let res = unsafe { ffi_dispatch!(LIB, FcCharSetIsSubset, self.as_ptr(), other.as_ptr()) };
49        res == FcTrue
50    }
51
52    /// Intersect self with other `CharSet`.
53    pub fn intersect(&self, other: &Self) -> OwnedCharSet {
54        let fcset =
55            unsafe { ffi_dispatch!(LIB, FcCharSetIntersect, self.as_ptr(), other.as_ptr()) };
56        OwnedCharSet {
57            fcset: NonNull::new(fcset).expect("intersect failed"),
58        }
59    }
60
61    /// Subtract other `CharSet` from self.
62    pub fn subtract(&self, other: &Self) -> OwnedCharSet {
63        let fcset = unsafe { ffi_dispatch!(LIB, FcCharSetSubtract, self.as_ptr(), other.as_ptr()) };
64        OwnedCharSet {
65            fcset: NonNull::new(fcset).expect("subtract failed"),
66        }
67    }
68
69    /// Union self with other `CharSet`.
70    pub fn union(&self, other: &Self) -> OwnedCharSet {
71        let fcset = unsafe { ffi_dispatch!(LIB, FcCharSetUnion, self.as_ptr(), other.as_ptr()) };
72        OwnedCharSet {
73            fcset: NonNull::new(fcset).expect("union failed"),
74        }
75    }
76
77    ///
78    pub fn iter(&self) -> Iter {
79        let mut map = [0; sys::constants::FC_CHARSET_MAP_SIZE as usize];
80        let mut next = 0;
81        let codepoint = unsafe {
82            ffi_dispatch!(
83                LIB,
84                FcCharSetFirstPage,
85                self.as_ptr(),
86                map.as_mut_ptr(),
87                &mut next
88            )
89        };
90        Iter {
91            cs: self,
92            codepoint,
93            next,
94            map,
95            i: 0,
96            bit: 0,
97        }
98    }
99
100    pub(crate) fn as_ptr(&self) -> *const sys::FcCharSet {
101        &self.fcset
102    }
103
104    pub(crate) fn as_mut_ptr(&mut self) -> *mut sys::FcCharSet {
105        &mut self.fcset
106    }
107}
108
109impl OwnedCharSet {
110    /// Create a new, empty `CharSet`.
111    pub fn new() -> Self {
112        let fcset = unsafe { ffi_dispatch!(LIB, FcCharSetCreate,) };
113        OwnedCharSet {
114            fcset: NonNull::new(fcset).unwrap(),
115        }
116    }
117    /// Add a character to the `CharSet`.
118    pub fn add_char(&mut self, c: char) {
119        let res = unsafe { ffi_dispatch!(LIB, FcCharSetAddChar, self.as_mut_ptr(), c as u32) };
120        assert_eq!(res, FcTrue);
121    }
122
123    /// Delete a character from the `CharSet
124    pub fn del_char(&mut self, c: char) {
125        let res = unsafe { ffi_dispatch!(LIB, FcCharSetDelChar, self.as_mut_ptr(), c as u32) };
126        assert_eq!(res, FcTrue);
127    }
128
129    /// Merge self with other `CharSet`.
130    pub fn merge(&mut self, other: &CharSet) {
131        let res = unsafe {
132            ffi_dispatch!(
133                LIB,
134                FcCharSetMerge,
135                self.as_mut_ptr(),
136                other.as_ptr(),
137                ptr::null_mut()
138            )
139        };
140        assert_eq!(res, FcTrue);
141    }
142}
143
144impl PartialEq for CharSet {
145    fn eq(&self, other: &Self) -> bool {
146        let res = unsafe { ffi_dispatch!(LIB, FcCharSetEqual, self.as_ptr(), other.as_ptr()) };
147        res == FcTrue
148    }
149}
150
151// NOTE: This just add reference, it is not safe.
152// impl<'a> Clone for CharSet<'a> {
153//     fn clone(&self) -> CharSet<'a> {
154//         let fcset = unsafe { ffi_dispatch!(LIB, FcCharSetCopy, self.fcset.as_ptr()) };
155//         CharSet {
156//             fcset: NonNull::new(fcset).expect("Can't clone CharSet"),
157//             _marker: PhantomData,
158//         }
159//     }
160// }
161
162impl Drop for OwnedCharSet {
163    fn drop(&mut self) {
164        unsafe { ffi_dispatch!(LIB, FcCharSetDestroy, self.as_mut_ptr()) };
165    }
166}
167
168impl Default for OwnedCharSet {
169    fn default() -> Self {
170        Self::new()
171    }
172}
173
174impl Deref for OwnedCharSet {
175    type Target = CharSet;
176    fn deref(&self) -> &CharSet {
177        unsafe { &*(self.fcset.as_ptr() as *const CharSet) }
178    }
179}
180
181impl DerefMut for OwnedCharSet {
182    fn deref_mut(&mut self) -> &mut CharSet {
183        unsafe { &mut *(self.fcset.as_ptr() as *mut CharSet) }
184    }
185}
186
187impl AsRef<CharSet> for OwnedCharSet {
188    fn as_ref(&self) -> &CharSet {
189        self
190    }
191}
192
193impl AsMut<CharSet> for OwnedCharSet {
194    fn as_mut(&mut self) -> &mut CharSet {
195        self
196    }
197}
198
199impl fmt::Debug for CharSet {
200    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201        f.debug_set().entries(self.iter()).finish()
202    }
203}
204
205impl fmt::Debug for OwnedCharSet {
206    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207        f.debug_set().entries(self.iter()).finish()
208    }
209}
210
211///
212pub struct Iter<'a> {
213    cs: &'a CharSet,
214    codepoint: sys::FcChar32,
215    next: sys::FcChar32,
216    map: [sys::FcChar32; sys::constants::FC_CHARSET_MAP_SIZE as usize],
217    i: usize,
218    bit: usize,
219}
220
221impl Iterator for Iter<'_> {
222    type Item = char;
223    fn next(&mut self) -> Option<char> {
224        const MAP_SIZE: usize = sys::constants::FC_CHARSET_MAP_SIZE as usize;
225        loop {
226            if self.codepoint == sys::constants::FC_CHARSET_DONE {
227                return None;
228            }
229            // end of page.
230            if self.i >= MAP_SIZE {
231                if self.next == sys::constants::FC_CHARSET_DONE {
232                    // end of last page.
233                    self.codepoint = sys::constants::FC_CHARSET_DONE;
234                } else {
235                    // next page
236                    self.codepoint = unsafe {
237                        ffi_dispatch!(
238                            LIB,
239                            FcCharSetNextPage,
240                            self.cs.as_ptr(),
241                            self.map.as_mut_ptr(),
242                            &mut self.next
243                        )
244                    };
245                    self.i = 0;
246                }
247                continue;
248            }
249            let mut bits = self.map[self.i];
250            if bits == 0 {
251                self.i += 1;
252                self.bit = 0;
253                continue;
254            }
255
256            let mut ok = true;
257            // println!(" -> bits {:#b} {}", bits, self.bit);
258            let mut n = bits >> self.bit;
259            while n & 1 == 0 {
260                if n == 0 {
261                    self.i += 1;
262                    self.bit = 0;
263                    ok = false;
264                    break;
265                }
266                self.bit += 1;
267                if self.bit > 31 {
268                    self.i += 1;
269                    self.bit = 0;
270                    ok = false;
271                    break;
272                }
273                if self.i >= MAP_SIZE {
274                    ok = false;
275                    break;
276                }
277                bits = self.map[self.i];
278                // println!("bits {:#b} x {}", bits, self.bit);
279                n = bits >> self.bit;
280            }
281            // 如果上面的while循环正常执行完,没有break,才可以执行这里.
282            // if the while loop is not broken, then we can execute this.
283            if ok {
284                let codepoint =
285                    self.codepoint + (32u32 * self.i as u32) + u32::try_from(self.bit).ok()?;
286                // println!("{}({})", codepoint, char::from_u32(codepoint).unwrap());
287                self.bit += 1;
288                if self.bit > 31 {
289                    self.i += 1;
290                    self.bit = 0;
291                }
292                return char::try_from(codepoint).ok();
293            }
294        }
295    }
296}
297
298#[cfg(test)]
299mod tests {
300    use super::*;
301
302    #[test]
303    fn charset_modify() {
304        let mut cs = OwnedCharSet::new();
305        assert!(!cs.has_char('a'));
306        cs.add_char('a');
307        assert!(cs.has_char('a'));
308        cs.del_char('a');
309        assert!(!cs.has_char('a'));
310    }
311
312    #[test]
313    fn charset_merge() {
314        let mut cs1 = OwnedCharSet::new();
315        let mut cs2 = OwnedCharSet::new();
316        cs1.add_char('a');
317        cs2.add_char('b');
318        cs1.merge(&cs2);
319        assert!(cs1.has_char('a'));
320        assert!(cs1.has_char('b'));
321    }
322
323    #[test]
324    fn charset_union() {
325        let mut cs1 = OwnedCharSet::new();
326        let mut cs2 = OwnedCharSet::new();
327        cs1.add_char('a');
328        cs2.add_char('b');
329        let cs3 = cs1.union(&cs2);
330        assert!(cs3.has_char('a'));
331        assert!(cs3.has_char('b'));
332        assert!(!cs1.has_char('b'));
333        assert!(!cs2.has_char('a'));
334    }
335
336    #[test]
337    fn charset_intersect() {
338        let mut cs1 = OwnedCharSet::new();
339        let mut cs2 = OwnedCharSet::new();
340        cs1.add_char('a');
341        cs1.add_char('c');
342        cs2.add_char('b');
343        cs2.add_char('c');
344        let cs3 = cs1.intersect(&cs2);
345        assert!(!cs3.has_char('a'));
346        assert!(!cs3.has_char('b'));
347        assert!(cs3.has_char('c'));
348        assert!(!cs1.has_char('b'));
349        assert!(!cs2.has_char('a'));
350    }
351
352    #[test]
353    fn charset_subtract() {
354        let mut cs1 = OwnedCharSet::new();
355        let mut cs2 = OwnedCharSet::new();
356        cs1.add_char('a');
357        cs1.add_char('c');
358        cs2.add_char('b');
359        cs2.add_char('c');
360        let cs3 = cs1.subtract(&cs2);
361        assert!(cs3.has_char('a'));
362        assert!(!cs3.has_char('b'));
363        assert!(!cs3.has_char('c'));
364        assert!(!cs1.has_char('b'));
365        assert!(!cs2.has_char('a'));
366    }
367
368    #[test]
369    fn charset_equal() {
370        let mut cs1 = OwnedCharSet::new();
371        let mut cs2 = OwnedCharSet::new();
372        cs1.add_char('a');
373        cs1.add_char('c');
374        cs2.add_char('b');
375        cs2.add_char('c');
376        assert_ne!(cs1.as_ref(), cs2.as_ref());
377        cs2.add_char('a');
378        cs2.del_char('b');
379        assert_eq!(cs1.as_ref(), cs2.as_ref());
380    }
381
382    #[test]
383    fn charset_iter() {
384        let mut cs = OwnedCharSet::new();
385        cs.add_char('a');
386        cs.add_char('b');
387        cs.add_char('c');
388        cs.add_char('汉');
389        cs.add_char('字');
390        cs.add_char('😁');
391        let mut iter = cs.iter();
392        assert_eq!(iter.next(), Some('a'));
393        assert_eq!(iter.next(), Some('b'));
394        assert_eq!(iter.next(), Some('c'));
395        assert_eq!(iter.next(), Some('字'));
396        assert_eq!(iter.next(), Some('汉'));
397        assert_eq!(iter.next(), Some('😁'));
398        assert_eq!(iter.next(), None);
399    }
400}