hb_subset/
map.rs

1//! Map represents an integer-to-integer mapping.
2//!
3//! While map in this module can be used as a general-purpose map in Rust code, it is recommended that you instead use
4//! [`std::collections::BTreeMap`] or [`std::collections::HashMap`] as those are implemented directly in Rust and do not
5//! rely on FFI to work.
6
7use std::{
8    fmt,
9    hash::Hash,
10    iter::{FilterMap, FusedIterator},
11    marker::PhantomData,
12};
13
14use crate::{set::Set, sys, AllocationError};
15
16/// Map objects are integer-to-integer hash-maps.
17///
18/// The map can be specialized to work over other integer-like types, like [`char`]s.
19pub struct Map<'a, K = u32, V = u32>(InnerMap, PhantomData<(&'a (), (K, V))>);
20
21impl<K, V> Map<'static, K, V> {
22    /// Creates a new, initially empty map.
23    #[doc(alias = "hb_map_create")]
24    pub fn new() -> Result<Self, AllocationError> {
25        let map = unsafe { sys::hb_map_create() };
26        if map.is_null() {
27            return Err(AllocationError);
28        }
29        Ok(Self(InnerMap(map), PhantomData))
30    }
31}
32
33impl<'a, K, V> Map<'a, K, V> {
34    /// Tests whether map is empty i.e. contains no elements.
35    #[doc(alias = "hb_map_is_empty")]
36    pub fn is_empty(&self) -> bool {
37        (unsafe { sys::hb_map_is_empty(self.as_raw()) }) != 0
38    }
39
40    /// Returns the number of key-value pairs in the set.
41    #[doc(alias = "hb_map_get_population")]
42    pub fn len(&self) -> usize {
43        (unsafe { sys::hb_map_get_population(self.as_raw()) }) as usize
44    }
45
46    /// Clears out the contents of a map.
47    #[doc(alias = "hb_map_clear")]
48    pub fn clear(&mut self) {
49        unsafe { sys::hb_map_clear(self.as_raw()) }
50    }
51
52    /// Constructs a copy of the map with `'static` lifetime.
53    #[doc(alias = "hb_map_copy")]
54    pub fn clone_static(&self) -> Map<'static, K, V> {
55        Map(InnerMap(unsafe { sys::hb_map_copy(self.as_raw()) }), PhantomData)
56    }
57
58    /// Adds the contents of `other` to map.
59    pub fn update(&mut self, other: &Self) {
60        unsafe { sys::hb_map_update(self.as_raw(), other.as_raw()) }
61    }
62
63    /// Gets the set of keys that have been defined.
64    #[doc(alias = "hb_map_keys")]
65    pub fn keys(&self) -> Result<Set<'static, K>, AllocationError> {
66        let set = Set::new()?;
67        unsafe { sys::hb_map_keys(self.as_raw(), set.as_raw()) };
68        Ok(set)
69    }
70
71    /// Gets the set of values that are associated with a key.
72    #[doc(alias = "hb_map_values")]
73    pub fn values(&self) -> Result<Set<'static, V>, AllocationError> {
74        let set = Set::new()?;
75        unsafe { sys::hb_map_values(self.as_raw(), set.as_raw()) };
76        Ok(set)
77    }
78}
79
80impl<'a, K, V> Map<'a, K, V>
81where
82    K: Into<u32>,
83    V: Into<u32>,
84{
85    /// Tests whether the map contains a key.
86    #[doc(alias = "hb_map_has")]
87    pub fn contains(&self, key: K) -> bool {
88        (unsafe { sys::hb_map_has(self.as_raw(), key.into()) }) != 0
89    }
90
91    /// Removes key and its associated value from map.
92    #[doc(alias = "hb_map_del")]
93    pub fn remove(&mut self, key: K) {
94        unsafe { sys::hb_map_del(self.as_raw(), key.into()) }
95    }
96
97    /// Inserts a key-value pair to map.
98    #[doc(alias = "hb_map_set")]
99    pub fn insert(&mut self, key: K, value: V) {
100        let key = key.into();
101        let value = value.into();
102        unsafe { sys::hb_map_set(self.as_raw(), key, value) }
103    }
104}
105
106impl<'a, K, V> Map<'a, K, V>
107where
108    K: Into<u32>,
109    V: TryFrom<u32>,
110{
111    /// Gets a value based on a key.
112    #[doc(alias = "hb_map_get")]
113    pub fn get(&self, key: K) -> Option<V> {
114        let key = key.into();
115        if (unsafe { sys::hb_map_has(self.as_raw(), key) }) != 0 {
116            V::try_from(unsafe { sys::hb_map_get(self.as_raw(), key) }).ok()
117        } else {
118            None
119        }
120    }
121}
122
123impl<'a, K, V> Map<'a, K, V>
124where
125    K: TryFrom<u32>,
126    V: TryFrom<u32>,
127{
128    /// Gets an iterator over key-value pairs stored in the map.
129    #[doc(alias = "hb_map_next")]
130    pub fn iter(&self) -> Iter<'_, 'a, K, V> {
131        Iter(
132            IterImpl::new(self).filter_map(|(k, v)| Some((k.try_into().ok()?, v.try_into().ok()?))),
133        )
134    }
135}
136
137impl<'a, K, V> Map<'a, K, V> {
138    /// Converts the map into raw [`sys::hb_map_t`] pointer.
139    ///
140    /// This method transfers the ownership of the map to the caller. It is up to the caller to call
141    /// [`sys::hb_map_destroy`] to free the object, or call [`Self::from_raw`] to convert it back into [`Map`].
142    pub fn into_raw(self) -> *mut sys::hb_map_t {
143        let ptr = self.0 .0;
144        std::mem::forget(self);
145        ptr
146    }
147
148    /// Exposes the raw inner pointer without transferring the ownership.
149    ///
150    /// Unlike [`Self::into_raw`], this method does not transfer the ownership of the pointer to the caller.
151    pub fn as_raw(&self) -> *mut sys::hb_map_t {
152        self.0 .0
153    }
154
155    /// Constructs a map from raw [`sys::hb_map_t`] object.
156    ///
157    /// # Safety
158    /// The given `map` pointer must either be constructed by some Harfbuzz function, or be returned from
159    /// [`Self::into_raw`].
160    pub unsafe fn from_raw(map: *mut sys::hb_map_t) -> Self {
161        Self(InnerMap(map), PhantomData)
162    }
163}
164
165impl<'a, K, V> Hash for Map<'a, K, V> {
166    #[doc(alias = "hb_map_hash")]
167    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
168        unsafe { sys::hb_map_hash(self.as_raw()) }.hash(state);
169    }
170}
171
172impl<'a, K, V> PartialEq for Map<'a, K, V> {
173    #[doc(alias = "hb_map_is_equal")]
174    fn eq(&self, other: &Self) -> bool {
175        (unsafe { sys::hb_map_is_equal(self.as_raw(), other.as_raw()) }) != 0
176    }
177}
178
179impl<'a, K, V> Eq for Map<'a, K, V>
180where
181    K: Eq,
182    V: Eq,
183{
184}
185
186impl<'a, K, V> Clone for Map<'a, K, V> {
187    fn clone(&self) -> Self {
188        self.clone_static()
189    }
190}
191
192impl<'a, K, V> fmt::Debug for Map<'a, K, V>
193where
194    K: TryFrom<u32> + fmt::Debug,
195    V: TryFrom<u32> + fmt::Debug,
196{
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        f.debug_map().entries(self).finish()
199    }
200}
201
202impl<'a, K, V> FromIterator<(K, V)> for Map<'a, K, V>
203where
204    K: Into<u32>,
205    V: Into<u32>,
206{
207    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
208        let mut map = Map::new().unwrap();
209        for (key, value) in iter {
210            map.insert(key, value);
211        }
212        map
213    }
214}
215
216impl<'m, 'a, K, V> IntoIterator for &'m Map<'a, K, V>
217where
218    K: TryFrom<u32>,
219    V: TryFrom<u32>,
220{
221    type Item = (K, V);
222    type IntoIter = Iter<'m, 'a, K, V>;
223
224    fn into_iter(self) -> Self::IntoIter {
225        self.iter()
226    }
227}
228
229/// Iterator over [`Map`] key-value pairs.
230///
231/// Use [`Map::iter`] to construct [`Iter`].
232pub struct Iter<'m, 'a, K, V>(IterFilter<'m, 'a, K, V>);
233type IterFilter<'m, 'a, K, V> = FilterMap<IterImpl<'m, 'a, K, V>, fn((u32, u32)) -> Option<(K, V)>>;
234
235impl<'m, 'a, K, V> Iterator for Iter<'m, 'a, K, V>
236where
237    K: TryFrom<u32>,
238    V: TryFrom<u32>,
239{
240    type Item = (K, V);
241
242    fn next(&mut self) -> Option<Self::Item> {
243        self.0.next()
244    }
245}
246
247impl<'m, 'a, K, V> FusedIterator for Iter<'m, 'a, K, V>
248where
249    K: TryFrom<u32>,
250    V: TryFrom<u32>,
251{
252}
253
254/// Iterator over raw elements over map, disregarding whether they can be represented as (K, V).
255struct IterImpl<'m, 'a, K, V>(&'m Map<'a, K, V>, i32);
256
257impl<'m, 'a, K, V> IterImpl<'m, 'a, K, V> {
258    fn new(map: &'m Map<'a, K, V>) -> Self {
259        Self(map, -1)
260    }
261}
262
263impl<'m, 'a, K, V> Iterator for IterImpl<'m, 'a, K, V> {
264    type Item = (u32, u32);
265
266    fn next(&mut self) -> Option<Self::Item> {
267        let mut key = 0;
268        let mut value = 0;
269        let prev_state = self.1;
270        let has_next = unsafe {
271            sys::hb_map_next(
272                self.0.as_raw(),
273                &mut self.1 as *mut i32,
274                &mut key as *mut u32,
275                &mut value as *mut u32,
276            )
277        } != 0;
278        if has_next {
279            Some((key, value))
280        } else {
281            self.1 = prev_state; // To fuse the iterator
282            None
283        }
284    }
285}
286
287/// Implementation detail of Map to hide source reference from drop check.
288///
289/// See [`set::InnerSet`] for more detailed explanation.
290struct InnerMap(*mut sys::hb_map_t);
291
292impl Drop for InnerMap {
293    #[doc(alias = "hb_map_destroy")]
294    fn drop(&mut self) {
295        unsafe { sys::hb_map_destroy(self.0) }
296    }
297}
298
299#[cfg(test)]
300mod tests {
301    use std::collections::BTreeSet;
302
303    use super::*;
304
305    #[test]
306    fn is_empty_works() {
307        let mut map = Map::<u32, u32>::new().unwrap();
308        assert!(map.is_empty());
309        map.insert(0, 0);
310        assert!(!map.is_empty());
311        map.insert(0, 10);
312        assert!(!map.is_empty());
313        map.remove(0);
314        assert!(map.is_empty());
315    }
316
317    #[test]
318    fn len_works() {
319        let mut map = Map::<u32, u32>::new().unwrap();
320        assert_eq!(map.len(), 0);
321        map.insert(0, 0);
322        assert_eq!(map.len(), 1);
323        map.insert(0, 10);
324        assert_eq!(map.len(), 1);
325        map.insert(1, 10);
326        assert_eq!(map.len(), 2);
327        map.remove(0);
328        assert_eq!(map.len(), 1);
329        map.remove(0);
330        assert_eq!(map.len(), 1);
331        map.remove(1);
332        assert_eq!(map.len(), 0);
333    }
334
335    #[test]
336    fn clear_works() {
337        let mut map = Map::<u32, u32>::from_iter([(0, 1), (0, 2), (1, 3)]);
338        assert_eq!(map.len(), 2);
339        map.clear();
340        assert!(map.is_empty());
341        assert_eq!(map.len(), 0);
342    }
343
344    #[test]
345    fn clone_does_not_change_original() {
346        let mut a = Map::<u32, u32>::from_iter([(0, 1), (1, 2), (10, 11)]);
347        let mut b = a.clone();
348        assert_eq!(a, b);
349        assert_eq!(b.len(), 3);
350        a.insert(20, 21);
351        assert_eq!(a.len(), 4);
352        assert_eq!(b.len(), 3);
353        b.remove(0);
354        assert_eq!(a.len(), 4);
355        assert_eq!(b.len(), 2);
356    }
357
358    #[test]
359    fn update_replaces_keys() {
360        let mut a = Map::<u32, u32>::from_iter([(0, 0), (1, 0), (10, 0)]);
361        let b = Map::<u32, u32>::from_iter([(1, 1), (5, 1), (11, 1)]);
362        a.update(&b);
363        assert_eq!(a.len(), 5);
364        assert_eq!(a.get(0).unwrap(), 0);
365        assert_eq!(a.get(1).unwrap(), 1);
366        assert_eq!(a.get(5).unwrap(), 1);
367        assert_eq!(a.get(10).unwrap(), 0);
368        assert_eq!(a.get(11).unwrap(), 1);
369    }
370
371    #[test]
372    fn keys_works() {
373        assert_eq!(Map::<u32, u32>::from_iter([]).keys().unwrap(), Set::from_iter([]));
374        assert_eq!(
375            Map::<u32, u32>::from_iter([(0, 100), (1, 101), (10, 110)])
376                .keys()
377                .unwrap(),
378            Set::from_iter([0, 1, 10])
379        );
380    }
381
382    #[test]
383    fn values_works() {
384        assert_eq!(Map::<u32, u32>::from_iter([]).values().unwrap(), Set::from_iter([]));
385        assert_eq!(
386            Map::<u32, u32>::from_iter([(0, 100), (1, 101), (10, 110)])
387                .values()
388                .unwrap(),
389            Set::from_iter([100, 101, 110])
390        );
391    }
392
393    #[test]
394    fn contains_works() {
395        let mut map = Map::<u32, u32>::new().unwrap();
396        assert!(!map.contains(0));
397        map.insert(0, 0);
398        assert!(map.contains(0));
399        map.insert(0, 10);
400        assert!(map.contains(0));
401        assert!(!map.contains(1));
402        map.insert(1, 10);
403        assert!(map.contains(0));
404        assert!(map.contains(1));
405        map.remove(0);
406        assert!(!map.contains(0));
407        assert!(map.contains(1));
408        map.remove(0);
409        assert!(!map.contains(0));
410        assert!(map.contains(1));
411        map.remove(1);
412        assert!(!map.contains(0));
413        assert!(!map.contains(1));
414    }
415
416    #[track_caller]
417    fn assert_set_is_correct<T: Ord + fmt::Debug>(
418        left: impl IntoIterator<Item = T>,
419        right: impl IntoIterator<Item = T>,
420    ) {
421        let left: BTreeSet<T> = BTreeSet::from_iter(left);
422        let right: BTreeSet<T> = BTreeSet::from_iter(right);
423        assert_eq!(left, right);
424    }
425
426    #[test]
427    #[should_panic]
428    fn assert_set_is_correct_detects_differences() {
429        assert_set_is_correct([1, 2], [1, 2, 3]);
430    }
431
432    #[test]
433    fn iter_works() {
434        let mut map = Map::<u32, u32>::from_iter([(0, 100), (4, 104)]);
435        assert_set_is_correct(map.iter(), [(0, 100), (4, 104)]);
436        map.insert(u32::MAX, u32::MAX);
437        assert_set_is_correct(map.iter(), [(0, 100), (4, 104), (u32::MAX, u32::MAX)]);
438    }
439
440    #[test]
441    fn iter_is_fused() {
442        let map = Map::<u32, u32>::from_iter([(0, 100), (4, 104)]);
443        let mut iter = map.iter();
444        assert!(iter.next().is_some());
445        assert!(iter.next().is_some());
446        assert!(iter.next().is_none());
447        assert!(iter.next().is_none());
448        assert!(iter.next().is_none());
449        assert!(iter.next().is_none());
450        assert!(iter.next().is_none());
451    }
452
453    #[test]
454    fn iter_of_invalid_codepoints_works() {
455        let mut map = Map::<u32, u32>::new().unwrap();
456        // Close to invalid code points
457        map.insert(0xD7FF, 10);
458        map.insert(0xE000, 10);
459        map.insert(20, 0xD7FF);
460        map.insert(21, 0xE000);
461
462        // Invalid code points in key
463        map.insert(0xD800, 3);
464        map.insert(0xD912, 4);
465        map.insert(0xDFFF, 5);
466
467        // Invalid code points in value
468        map.insert(23, 0xD800);
469        map.insert(24, 0xD912);
470        map.insert(25, 0xDFFF);
471
472        let char_to_u32_map = unsafe { Map::<char, u32>::from_raw(map.clone().into_raw()) };
473        assert_set_is_correct(&char_to_u32_map, [
474            ('\u{D7FF}', 10),
475            ('\u{E000}', 10),
476            ('\u{14}', 0xD7FF),
477            ('\u{15}', 0xE000),
478            ('\u{17}', 0xD800),
479            ('\u{18}', 0xD912),
480            ('\u{19}', 0xDFFF),
481        ]);
482
483        let u32_to_char_map = unsafe { Map::<u32, char>::from_raw(map.clone().into_raw()) };
484        assert_set_is_correct(&u32_to_char_map, [
485            (0xD7FF, '\u{0a}'),
486            (0xE000, '\u{0a}'),
487            (20, '\u{D7FF}'),
488            (21, '\u{E000}'),
489            (0xD800, '\u{3}'),
490            (0xD912, '\u{4}'),
491            (0xDFFF, '\u{5}'),
492        ]);
493
494        let char_to_char_map = unsafe { Map::<char, char>::from_raw(map.clone().into_raw()) };
495        assert_set_is_correct(&char_to_char_map, [
496            ('\u{D7FF}', '\u{0a}'),
497            ('\u{E000}', '\u{0a}'),
498            ('\u{14}', '\u{D7FF}'),
499            ('\u{15}', '\u{E000}'),
500        ]);
501    }
502
503    #[test]
504    fn value_can_be_u32_max() {
505        let mut map = Map::<u32, u32>::new().unwrap();
506        map.insert(0, u32::MAX - 1);
507        map.insert(1, u32::MAX);
508        assert_eq!(map.len(), 2);
509        assert_eq!(map.get(0).unwrap(), u32::MAX - 1);
510        assert_eq!(map.get(1).unwrap(), u32::MAX);
511    }
512
513    #[test]
514    fn key_can_be_u32_max() {
515        let mut map = Map::<u32, u32>::new().unwrap();
516        map.insert(u32::MAX - 1, 10);
517        map.insert(u32::MAX, 20);
518        assert_eq!(map.len(), 2);
519        assert_eq!(map.get(u32::MAX - 1).unwrap(), 10);
520        assert_eq!(map.get(u32::MAX).unwrap(), 20);
521    }
522}