• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
lm_len(&self) -> usize47     fn lm_len(&self) -> usize;
48 
49     /// Returns whether the store is empty (contains 0 elements).
lm_is_empty(&self) -> bool50     fn lm_is_empty(&self) -> bool {
51         self.lm_len() == 0
52     }
53 
54     /// Gets a key/value pair at the specified index.
lm_get(&self, index: usize) -> Option<(&K, &V)>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.
lm_last(&self) -> Option<(&K, &V)>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.
lm_binary_search_by<F>(&self, cmp: F) -> Result<usize, usize> where F: FnMut(&K) -> Ordering70     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`.
lm_sort_from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self77     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 
lm_get_range(&self, range: Range<usize>) -> Option<&Self::Slice>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.
lm_with_capacity(capacity: usize) -> Self90     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.
lm_reserve(&mut self, additional: usize)95     fn lm_reserve(&mut self, additional: usize);
96 
97     /// Gets a key/value pair at the specified index, with a mutable value.
lm_get_mut(&mut self, index: usize) -> Option<(&K, &mut V)>98     fn lm_get_mut(&mut self, index: usize) -> Option<(&K, &mut V)>;
99 
100     /// Pushes one additional item onto the store.
lm_push(&mut self, key: K, value: V)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.
lm_insert(&mut self, index: usize, key: K, value: V)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.
lm_remove(&mut self, index: usize) -> (K, V)115     fn lm_remove(&mut self, index: usize) -> (K, V);
116 
117     /// Removes all items from the store.
lm_clear(&mut self)118     fn lm_clear(&mut self);
119 
120     /// Retains items satisfying a predicate in this store.
lm_retain<F>(&mut self, mut predicate: F) where F: FnMut(&K, &V) -> bool,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.
lm_iter(&'a self) -> Self::KeyValueIter143     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.
lm_iter_mut(&'a mut self) -> Self::KeyValueIterMut150     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.
lm_into_iter(self) -> Self::KeyValueIntoIter157     fn lm_into_iter(self) -> Self::KeyValueIntoIter;
158 
159     /// Adds items from another store to the end of this store.
lm_extend_end(&mut self, other: Self) where Self: Sized,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.
lm_extend_start(&mut self, other: Self) where Self: Sized,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