Skip to content

Commit a2431d8

Browse files
tapeinosynetapeinosyne
tapeinosyne
authored andcommitted
Supplant the Borrow bound on keys with a new AsKey trait
QP-trie keys are now bound by a new public trait, `AsKey`, rather than `Borrow<[u8]>`. `AsKey` types must be borrowable both as a key slice, much like in `Borrow`, and as `&[u8]`, which is used internally for nybble operations. The trait is implemented for common `std` types, roughly matching prior coverage, and is amenable to further expansion.
1 parent 4b2980b commit a2431d8

File tree

3 files changed

+217
-15
lines changed

3 files changed

+217
-15
lines changed

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,21 @@ enable compilation of `Deserialize` and `Serialize` implementations for `Trie`.
1919
## When should I use a QP-trie?
2020

2121
QP-tries as implemented in this crate are key-value maps for any keys which
22-
implement `Borrow<[u8]>`. They are useful whenever you might need the same
23-
operations as a `HashMap` or `BTreeMap`, but need either a bit more speed
24-
(QP-tries are as fast or a bit faster as Rust's `HashMap` with the default
25-
hasher) and/or the ability to efficiently query for sets of elements with a
26-
given prefix.
22+
implement `qp_trie::AsKey`, a specialized trait akin to `Borrow<[u8]>`. They
23+
are useful whenever you might need the same operations as a `HashMap` or
24+
`BTreeMap`, but need either a bit more speed (QP-tries are as fast or a bit
25+
faster as Rust's `HashMap` with the default hasher) and/or the ability to
26+
efficiently query for sets of elements with a given prefix.
2727

2828
QP-tries support efficient lookup/insertion/removal of individual elements,
2929
lookup/removal of sets of values with keys with a given prefix.
3030

3131
## Examples
3232

33-
Keys can be any type which implements `Borrow<[u8]>`. Unfortunately at the
34-
moment, this rules out `String` - while this trie can still be used to store
35-
strings, it is necessary to manually convert them to byte slices and `Vec<u8>`s
36-
for use as keys. Here's a naive, simple example of putting 9 2-element byte arrays
37-
into the trie, and then removing all byte arrays which begin with "1":
33+
Keys can be any type which implements `AsKey`. Currently, this means strings as
34+
well as byte slices, vectors, and arrays. Here's a naive, simple example of
35+
putting 9 2-element byte arrays into the trie, and then removing all byte
36+
arrays which begin with "1":
3837

3938
```rust
4039
use qp_trie::Trie;
@@ -137,7 +136,7 @@ test bench_trie_insert ... bench: 50,966,392 ns/iter (+/- 18,077,240)
137136

138137
## Future work
139138

140-
- Add wrapper types for `String` and `str` to make working with strings easier.
139+
- Support more key types.
141140

142141
## License
143142

src/key.rs

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
use std::borrow::Borrow;
2+
3+
4+
/// A trait for keys in a QP-trie.
5+
///
6+
/// Implementing types must be borrowable in the form of both a key slice,
7+
/// such as `&str`, and the plain byte slice `&[u8]`. The former is used in
8+
/// the public `trie::Trie` API, while the latter is used internally to match
9+
/// and store keys.
10+
///
11+
/// Note that, as a consequence, keys which are not bytewise-equivalent will
12+
/// not associate to the same entry, even if they are equal under `Eq`.
13+
pub trait AsKey {
14+
/// The borrowed form of this key type.
15+
type Borrowed: ?Sized;
16+
17+
/// Borrow this key as a slice.
18+
fn as_key_slice(&self) -> &Self::Borrowed;
19+
20+
/// View the key slice as a plain byte sequence.
21+
fn as_key_bytes(key: &Self::Borrowed) -> &[u8];
22+
23+
/// Borrow the key as nybbles, in the form of a plain byte sequence.
24+
#[inline]
25+
fn as_nybbles(&self) -> &[u8] {
26+
Self::as_key_bytes(self.as_key_slice())
27+
}
28+
29+
/// View the nybbles of a value that can borrowed as a key slice.
30+
#[inline]
31+
fn nybbles_from<'a, Q: 'a + ?Sized>(val: &'a Q) -> &'a [u8]
32+
where
33+
Self::Borrowed: 'a,
34+
Q: Borrow<Self::Borrowed>,
35+
{
36+
Self::as_key_bytes(val.borrow())
37+
}
38+
}
39+
40+
41+
impl<'a> AsKey for &'a [u8] {
42+
type Borrowed = [u8];
43+
44+
#[inline]
45+
fn as_key_slice(&self) -> &Self::Borrowed {
46+
self
47+
}
48+
49+
#[inline]
50+
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
51+
key
52+
}
53+
}
54+
55+
56+
impl AsKey for Vec<u8> {
57+
type Borrowed = [u8];
58+
59+
#[inline]
60+
fn as_key_slice(&self) -> &Self::Borrowed {
61+
self.as_slice()
62+
}
63+
64+
#[inline]
65+
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
66+
key
67+
}
68+
}
69+
70+
71+
impl<'a> AsKey for &'a str {
72+
type Borrowed = str;
73+
74+
#[inline]
75+
fn as_key_slice(&self) -> &Self::Borrowed {
76+
self
77+
}
78+
79+
#[inline]
80+
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
81+
key.as_bytes()
82+
}
83+
}
84+
85+
86+
impl AsKey for String {
87+
type Borrowed = str;
88+
89+
#[inline]
90+
fn as_key_slice(&self) -> &Self::Borrowed {
91+
self.as_str()
92+
}
93+
94+
#[inline]
95+
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
96+
key.as_bytes()
97+
}
98+
}
99+
100+
101+
pub trait Break: AsKey {
102+
fn empty<'a>() -> &'a <Self as AsKey>::Borrowed;
103+
fn find_break(&self, loc: usize) -> &<Self as AsKey>::Borrowed;
104+
}
105+
106+
107+
impl<'b> Break for &'b [u8] {
108+
#[inline]
109+
fn empty<'a>() -> &'a [u8] {
110+
<&'a [u8]>::default()
111+
}
112+
113+
#[inline]
114+
fn find_break(&self, loc: usize) -> &[u8] {
115+
&self[..loc]
116+
}
117+
}
118+
119+
120+
impl Break for Vec<u8> {
121+
#[inline]
122+
fn empty<'a>() -> &'a [u8] {
123+
<&'a [u8]>::default()
124+
}
125+
126+
#[inline]
127+
fn find_break(&self, loc: usize) -> &[u8] {
128+
&self[..loc]
129+
}
130+
}
131+
132+
133+
impl<'b> Break for &'b str {
134+
#[inline]
135+
fn empty<'a>() -> &'a str {
136+
<&'a str>::default()
137+
}
138+
139+
#[inline]
140+
fn find_break(&self, mut loc: usize) -> &str {
141+
while !self.is_char_boundary(loc) {
142+
loc -= 1;
143+
}
144+
145+
&self[..loc]
146+
}
147+
}
148+
149+
150+
impl Break for String {
151+
#[inline]
152+
fn empty<'a>() -> &'a str {
153+
<&'a str>::default()
154+
}
155+
156+
#[inline]
157+
fn find_break(&self, mut loc: usize) -> &str {
158+
while !self.is_char_boundary(loc) {
159+
loc -= 1;
160+
}
161+
162+
&self[..loc]
163+
}
164+
}
165+
166+
167+
macro_rules! impl_for_arrays_of_size {
168+
($($length:expr)+) => { $(
169+
impl AsKey for [u8; $length] {
170+
type Borrowed = [u8];
171+
172+
#[inline]
173+
fn as_key_slice(&self) -> &Self::Borrowed {
174+
self.as_ref()
175+
}
176+
177+
#[inline]
178+
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
179+
key
180+
}
181+
}
182+
183+
impl Break for [u8; $length] {
184+
#[inline]
185+
fn empty<'a>() -> &'a [u8] {
186+
<&'a [u8]>::default()
187+
}
188+
189+
#[inline]
190+
fn find_break(&self, loc: usize) -> &[u8] {
191+
&self.as_key_slice()[..loc]
192+
}
193+
}
194+
)+ }
195+
}
196+
197+
198+
impl_for_arrays_of_size! {
199+
0 1 2 3 4 5 6 7 8 9
200+
10 11 12 13 14 15 16 17 18 19
201+
20 21 22 23 24 25 26 27 28 29
202+
30 31 32
203+
}

src/serialization.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
use key::AsKey;
12
use trie::Trie;
23

3-
use std::borrow::Borrow;
44
use std::fmt;
55
use std::marker::PhantomData;
66

@@ -9,7 +9,7 @@ use serde::ser::{Serialize, SerializeMap, Serializer};
99

1010
impl<K, V> Serialize for Trie<K, V>
1111
where
12-
K: Serialize + Borrow<[u8]>,
12+
K: Serialize + AsKey,
1313
V: Serialize,
1414
{
1515
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -38,7 +38,7 @@ impl<K, V> TrieVisitor<K, V> {
3838

3939
impl<'de, K, V> Visitor<'de> for TrieVisitor<K, V>
4040
where
41-
K: Deserialize<'de> + Borrow<[u8]>,
41+
K: Deserialize<'de> + AsKey,
4242
V: Deserialize<'de>,
4343
{
4444
type Value = Trie<K, V>;
@@ -62,7 +62,7 @@ where
6262

6363
impl<'de, K, V> Deserialize<'de> for Trie<K, V>
6464
where
65-
K: Deserialize<'de> + Borrow<[u8]>,
65+
K: Deserialize<'de> + AsKey,
6666
V: Deserialize<'de>,
6767
{
6868
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>

0 commit comments

Comments
 (0)