Skip to content

Commit

Permalink
Supplant the Borrow bound on keys with a new AsKey trait
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tapeinosyne committed Oct 4, 2017
1 parent e4e7c94 commit 2b65501
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 443 deletions.
18 changes: 9 additions & 9 deletions src/entry.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use std::borrow::Borrow;
use std::marker::PhantomData;
use std::mem;

use unreachable::UncheckedOptionExt;

use key::AsKey;
use node::{Node, Leaf};
use util::nybble_get_mismatch;


pub fn make_entry<'a, K: 'a + Borrow<[u8]>, V: 'a>(
pub fn make_entry<'a, K: 'a + AsKey, V: 'a>(
key: K,
root: &'a mut Option<Node<K, V>>,
) -> Entry<'a, K, V> {
Expand All @@ -27,12 +27,12 @@ pub enum Entry<'a, K: 'a, V: 'a> {
}


impl<'a, K: 'a + Borrow<[u8]>, V: 'a> Entry<'a, K, V> {
impl<'a, K: 'a + AsKey, V: 'a> Entry<'a, K, V> {
fn nonempty(key: K, root: &'a mut Option<Node<K, V>>) -> Entry<'a, K, V> {
let (exemplar_ptr, mismatch) = {
let node = unsafe { root.as_mut().unchecked_unwrap() };
let exemplar = node.get_exemplar_mut(key.borrow());
let mismatch = nybble_get_mismatch(exemplar.key_slice(), key.borrow());
let exemplar = node.get_exemplar_mut(key.as_nybbles());
let mismatch = nybble_get_mismatch(exemplar.key.as_nybbles(), key.as_nybbles());
(exemplar as *mut Leaf<K, V>, mismatch)
};

Expand Down Expand Up @@ -125,7 +125,7 @@ enum VacantEntryInner<'a, K: 'a, V: 'a> {
}


impl<'a, K: 'a + Borrow<[u8]>, V: 'a> VacantEntry<'a, K, V> {
impl<'a, K: 'a + AsKey, V: 'a> VacantEntry<'a, K, V> {
/// Get a reference to the key associated with this vacant entry.
pub fn key(&self) -> &K {
&self.key
Expand Down Expand Up @@ -168,7 +168,7 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
}


impl<'a, K: 'a + Borrow<[u8]>, V: 'a> OccupiedEntry<'a, K, V> {
impl<'a, K: 'a + AsKey, V: 'a> OccupiedEntry<'a, K, V> {
/// Get a reference to the key of the entry.
pub fn key(&self) -> &K {
let leaf = unsafe { &*self.leaf };
Expand All @@ -185,15 +185,15 @@ impl<'a, K: 'a + Borrow<[u8]>, V: 'a> OccupiedEntry<'a, K, V> {
let leaf_opt = root.take();
let leaf = unsafe { leaf_opt.unchecked_unwrap().unwrap_leaf() };

debug_assert!(leaf.key_slice() == self.key().borrow());
debug_assert!(leaf.key.as_nybbles() == self.key().as_nybbles());
(leaf.key, leaf.val)
}

Some(Node::Branch(..)) => {
let branch_opt = root.as_mut();
let branch = unsafe { branch_opt.unchecked_unwrap() };

let leaf_opt = branch.remove_validated(self.key().borrow());
let leaf_opt = branch.remove_validated(self.key().as_nybbles());

debug_assert!(leaf_opt.is_some());
let leaf = unsafe { leaf_opt.unchecked_unwrap() };
Expand Down
207 changes: 207 additions & 0 deletions src/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
use std::borrow::Borrow;


/// A trait for keys in a QP-trie.
///
/// Implementing types must be borrowable in the form of both a key slice,
/// such as `&str`, and the plain byte slice `&[u8]`. The former is used in
/// the public `trie::Trie` API, while the latter is used internally to match
/// and store keys.
///
/// Note that, as a consequence, keys which are not bytewise-equivalent will
/// not associate to the same entry, even if they are equal under `Eq`.
pub trait AsKey {
/// The borrowed form of this key type.
type Borrowed: ?Sized;

/// Borrow this key as a slice.
fn as_key_slice(&self) -> &Self::Borrowed;

/// View the key slice as a plain byte sequence.
fn as_key_bytes(key: &Self::Borrowed) -> &[u8];

/// Borrow the key as nybbles, in the form of a plain byte sequence.
#[inline]
fn as_nybbles(&self) -> &[u8] {
Self::as_key_bytes(self.as_key_slice())
}

/// View the nybbles of a value that can borrowed as a key slice.
#[inline]
fn nybbles_from<'a, Q: 'a + ?Sized>(val: &'a Q) -> &'a [u8]
where
Self::Borrowed: 'a,
Q: Borrow<Self::Borrowed>,
{
Self::as_key_bytes(val.borrow())
}
}


impl<'a> AsKey for &'a [u8] {
type Borrowed = [u8];

#[inline]
fn as_key_slice(&self) -> &Self::Borrowed {
self
}

#[inline]
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
key
}
}


impl AsKey for Vec<u8> {
type Borrowed = [u8];

#[inline]
fn as_key_slice(&self) -> &Self::Borrowed {
self.as_slice()
}

#[inline]
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
key
}
}


impl<'a> AsKey for &'a str {
type Borrowed = str;

#[inline]
fn as_key_slice(&self) -> &Self::Borrowed {
self
}

#[inline]
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
key.as_bytes()
}
}


impl AsKey for String {
type Borrowed = str;

#[inline]
fn as_key_slice(&self) -> &Self::Borrowed {
self.as_str()
}

#[inline]
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
key.as_bytes()
}
}


pub trait Break: AsKey {
fn empty<'a>() -> &'a <Self as AsKey>::Borrowed;
fn find_break(&self, loc: usize) -> &<Self as AsKey>::Borrowed;
}


impl<'b> Break for &'b [u8] {
#[inline]
fn empty<'a>() -> &'a [u8] {
<&'a [u8]>::default()
}

#[inline]
fn find_break(&self, loc: usize) -> &[u8] {
&self[..loc]
}
}


impl Break for Vec<u8> {
#[inline]
fn empty<'a>() -> &'a [u8] {
<&'a [u8]>::default()
}

#[inline]
fn find_break(&self, loc: usize) -> &[u8] {
&self[..loc]
}
}


impl<'b> Break for &'b str {
#[inline]
fn empty<'a>() -> &'a str {
<&'a str>::default()
}

#[inline]
fn find_break(&self, mut loc: usize) -> &str {
while !self.is_char_boundary(loc) {
loc -= 1;
}

&self[..loc]
}
}


impl Break for String {
#[inline]
fn empty<'a>() -> &'a str {
<&'a str>::default()
}

#[inline]
fn find_break(&self, mut loc: usize) -> &str {
while !self.is_char_boundary(loc) {
loc -= 1;
}

&self[..loc]
}
}


macro_rules! impl_for_arrays_of_size {
($($length:expr)+) => { $(
impl AsKey for [u8; $length] {
type Borrowed = [u8];

#[inline]
fn as_key_slice(&self) -> &Self::Borrowed {
self.as_ref()
}

#[inline]
fn as_key_bytes(key: &Self::Borrowed) -> &[u8] {
key
}
}

impl Break for [u8; $length] {
#[inline]
fn empty<'a>() -> &'a [u8] {
<&'a [u8]>::default()
}

#[inline]
fn find_break(&self, loc: usize) -> &[u8] {
&self.as_key_slice()[..loc]
}
}
)+ }
}


impl_for_arrays_of_size! {
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32
}




7 changes: 3 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ extern crate debug_unreachable;
extern crate unreachable;

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

#[macro_use]
Expand All @@ -16,15 +15,15 @@ mod serialization;

mod entry;
mod iter;
mod key;
mod node;
mod sparse;
mod subtrie;
mod trie;
mod util;

pub mod wrapper;

pub use entry::{Entry, OccupiedEntry, VacantEntry};
pub use iter::{Iter, IterMut, IntoIter};
pub use trie::{Trie, Break};
pub use key::{AsKey, Break};
pub use subtrie::SubTrie;
pub use trie::{Trie};
Loading

0 comments on commit 2b65501

Please sign in to comment.