| 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 | //! Traits for pluggable LiteMap backends. |
| 6 | //! |
| 7 | //! By default, LiteMap is backed by a `Vec`. However, in some environments, it may be desirable |
| 8 | //! to use a different data store while still using LiteMap to manage proper ordering of items. |
| 9 | //! |
| 10 | //! The general guidelines for a performant data store are: |
| 11 | //! |
| 12 | //! 1. Must support efficient random access for binary search |
| 13 | //! 2. Should support efficient append operations for deserialization |
| 14 | //! |
| 15 | //! To plug a custom data store into LiteMap, implement: |
| 16 | //! |
| 17 | //! - [`Store`] for most of the methods |
| 18 | //! - [`StoreIterable`] for methods that return iterators |
| 19 | //! - [`StoreFromIterator`] to enable `FromIterator` for LiteMap |
| 20 | //! |
| 21 | //! To test your implementation, enable the `"testing"` Cargo feature and use [`check_store()`]. |
| 22 | //! |
| 23 | //! [`check_store()`]: crate::testing::check_store |
| 24 | |
| 25 | mod slice_impl; |
| 26 | #[cfg (feature = "alloc" )] |
| 27 | mod vec_impl; |
| 28 | |
| 29 | use core::cmp::Ordering; |
| 30 | use core::iter::DoubleEndedIterator; |
| 31 | use core::iter::FromIterator; |
| 32 | use core::iter::Iterator; |
| 33 | use core::ops::Range; |
| 34 | |
| 35 | /// Trait to enable const construction of empty store. |
| 36 | pub trait StoreConstEmpty<K: ?Sized, V: ?Sized> { |
| 37 | /// An empty store |
| 38 | const EMPTY: Self; |
| 39 | } |
| 40 | |
| 41 | /// Trait to enable pluggable backends for LiteMap. |
| 42 | /// |
| 43 | /// Some methods have default implementations provided for convenience; however, it is generally |
| 44 | /// better to implement all methods that your data store supports. |
| 45 | pub trait Store<K: ?Sized, V: ?Sized>: Sized { |
| 46 | /// Returns the number of elements in the store. |
| 47 | fn lm_len(&self) -> usize; |
| 48 | |
| 49 | /// Returns whether the store is empty (contains 0 elements). |
| 50 | fn lm_is_empty(&self) -> bool { |
| 51 | self.lm_len() == 0 |
| 52 | } |
| 53 | |
| 54 | /// Gets a key/value pair at the specified index. |
| 55 | fn lm_get(&self, index: usize) -> Option<(&K, &V)>; |
| 56 | |
| 57 | /// Gets the last element in the store, or `None` if the store is empty. |
| 58 | fn lm_last(&self) -> Option<(&K, &V)> { |
| 59 | let len = self.lm_len(); |
| 60 | if len == 0 { |
| 61 | None |
| 62 | } else { |
| 63 | self.lm_get(len - 1) |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | /// Searches the store for a particular element with a comparator function. |
| 68 | /// |
| 69 | /// See the binary search implementation on `slice` for more information. |
| 70 | fn lm_binary_search_by<F>(&self, cmp: F) -> Result<usize, usize> |
| 71 | where |
| 72 | F: FnMut(&K) -> Ordering; |
| 73 | } |
| 74 | |
| 75 | pub trait StoreFromIterable<K, V>: Store<K, V> { |
| 76 | /// Create a sorted store from `iter`. |
| 77 | fn lm_sort_from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self; |
| 78 | } |
| 79 | |
| 80 | pub trait StoreSlice<K: ?Sized, V: ?Sized>: Store<K, V> { |
| 81 | type Slice: ?Sized; |
| 82 | |
| 83 | fn lm_get_range(&self, range: Range<usize>) -> Option<&Self::Slice>; |
| 84 | } |
| 85 | |
| 86 | pub trait StoreMut<K, V>: Store<K, V> { |
| 87 | /// Creates a new store with the specified capacity hint. |
| 88 | /// |
| 89 | /// Implementations may ignore the argument if they do not support pre-allocating capacity. |
| 90 | fn lm_with_capacity(capacity: usize) -> Self; |
| 91 | |
| 92 | /// Reserves additional capacity in the store. |
| 93 | /// |
| 94 | /// Implementations may ignore the argument if they do not support pre-allocating capacity. |
| 95 | fn lm_reserve(&mut self, additional: usize); |
| 96 | |
| 97 | /// Gets a key/value pair at the specified index, with a mutable value. |
| 98 | fn lm_get_mut(&mut self, index: usize) -> Option<(&K, &mut V)>; |
| 99 | |
| 100 | /// Pushes one additional item onto the store. |
| 101 | fn lm_push(&mut self, key: K, value: V); |
| 102 | |
| 103 | /// Inserts an item at a specific index in the store. |
| 104 | /// |
| 105 | /// # Panics |
| 106 | /// |
| 107 | /// Panics if `index` is greater than the length. |
| 108 | fn lm_insert(&mut self, index: usize, key: K, value: V); |
| 109 | |
| 110 | /// Removes an item at a specific index in the store. |
| 111 | /// |
| 112 | /// # Panics |
| 113 | /// |
| 114 | /// Panics if `index` is greater than the length. |
| 115 | fn lm_remove(&mut self, index: usize) -> (K, V); |
| 116 | |
| 117 | /// Removes all items from the store. |
| 118 | fn lm_clear(&mut self); |
| 119 | |
| 120 | /// Retains items satisfying a predicate in this store. |
| 121 | fn lm_retain<F>(&mut self, mut predicate: F) |
| 122 | where |
| 123 | F: FnMut(&K, &V) -> bool, |
| 124 | { |
| 125 | let mut i = 0; |
| 126 | while i < self.lm_len() { |
| 127 | #[allow (clippy::unwrap_used)] // i is in range |
| 128 | let (k, v) = self.lm_get(i).unwrap(); |
| 129 | if predicate(k, v) { |
| 130 | i += 1; |
| 131 | } else { |
| 132 | self.lm_remove(i); |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | /// Iterator methods for the LiteMap store. |
| 139 | pub trait StoreIterable<'a, K: 'a + ?Sized, V: 'a + ?Sized>: Store<K, V> { |
| 140 | type KeyValueIter: Iterator<Item = (&'a K, &'a V)> + DoubleEndedIterator + 'a; |
| 141 | |
| 142 | /// Returns an iterator over key/value pairs. |
| 143 | fn lm_iter(&'a self) -> Self::KeyValueIter; |
| 144 | } |
| 145 | |
| 146 | pub trait StoreIterableMut<'a, K: 'a, V: 'a>: StoreMut<K, V> + StoreIterable<'a, K, V> { |
| 147 | type KeyValueIterMut: Iterator<Item = (&'a K, &'a mut V)> + DoubleEndedIterator + 'a; |
| 148 | |
| 149 | /// Returns an iterator over key/value pairs, with a mutable value. |
| 150 | fn lm_iter_mut(&'a mut self) -> Self::KeyValueIterMut; |
| 151 | } |
| 152 | |
| 153 | pub trait StoreIntoIterator<K, V>: StoreMut<K, V> { |
| 154 | type KeyValueIntoIter: Iterator<Item = (K, V)>; |
| 155 | |
| 156 | /// Returns an iterator that moves every item from this store. |
| 157 | fn lm_into_iter(self) -> Self::KeyValueIntoIter; |
| 158 | |
| 159 | /// Adds items from another store to the end of this store. |
| 160 | fn lm_extend_end(&mut self, other: Self) |
| 161 | where |
| 162 | Self: Sized, |
| 163 | { |
| 164 | for item in other.lm_into_iter() { |
| 165 | self.lm_push(item.0, item.1); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | /// Adds items from another store to the beginning of this store. |
| 170 | fn lm_extend_start(&mut self, other: Self) |
| 171 | where |
| 172 | Self: Sized, |
| 173 | { |
| 174 | for (i, item) in other.lm_into_iter().enumerate() { |
| 175 | self.lm_insert(i, item.0, item.1); |
| 176 | } |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | /// A store that can be built from a tuple iterator. |
| 181 | pub trait StoreFromIterator<K, V>: FromIterator<(K, V)> {} |
| 182 | |