Skip to main content

hb_subset/
map.rs

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