diff --git a/rust/radix204/Cargo.toml b/rust/radix204/Cargo.toml new file mode 100644 --- /dev/null +++ b/rust/radix204/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "radix204" +version = "0.1.0" + +[dependencies] +error-chain = "0.11" + +[dev-dependencies] +quickcheck = "0.4" +rand = "0.3" +rand_derive = "0.3" +rustc-test = "0.2" diff --git a/rust/radix204/README.md b/rust/radix204/README.md new file mode 100644 --- /dev/null +++ b/rust/radix204/README.md @@ -0,0 +1,19 @@ +# radix204 + +20-byte to 4-byte mapping using a radix tree stored on plain buffers. + +There are 2 plain buffers: + + - KeyBuffer: store 20-bytes keys and look them up using their offsets, read-only to the library. + - RadixBuffer: store radix tree nodes and key offsets, managed, read-write by the library. + +`radix204` was designed for some specific use-cases efficiently. So it does not have some generic interface, like: + + - Storing extra values + - Deletion + - Variant-length keys + - Long offset (64-bit integer) support + +Applications may want to change KeyBuffer format so a `Key` is followed by a `Value` that the application cares about. The `Value` could be a complex structure that includes a deletion flag or a link to another `Value` (linked list). + +Variant-length keys and long offsets could in theory be added at the cost of introducing many type parameters (especially around the iterator interface), and double the storage size. diff --git a/rust/radix204/src/errors.rs b/rust/radix204/src/errors.rs new file mode 100644 --- /dev/null +++ b/rust/radix204/src/errors.rs @@ -0,0 +1,15 @@ +// Copyright 2017 Facebook, Inc. +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +use types::KeyId; + +error_chain! { + errors { + OffsetOverflow(offset: usize) { + description("offset overflow") + display("offset {} is out of range", offset) + } + } +} diff --git a/rust/radix204/src/lib.rs b/rust/radix204/src/lib.rs new file mode 100644 --- /dev/null +++ b/rust/radix204/src/lib.rs @@ -0,0 +1,24 @@ +// Copyright 2017 Facebook, Inc. +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +#[cfg(test)] +extern crate test; + +#[macro_use] +extern crate error_chain; + +#[cfg(test)] +#[macro_use] +extern crate quickcheck; + +#[cfg(test)] +extern crate rand; + +#[cfg(test)] +#[macro_use] +extern crate rand_derive; + +pub mod types; +pub mod errors; diff --git a/rust/radix204/src/types.rs b/rust/radix204/src/types.rs new file mode 100644 --- /dev/null +++ b/rust/radix204/src/types.rs @@ -0,0 +1,77 @@ +// Copyright 2017 Facebook, Inc. +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +use std::borrow::Borrow; +use std::cell::RefCell; +use std::rc::Rc; +use std::ops::Deref; +use std::convert::{From, Into}; +use errors::{Result, ErrorKind}; + +pub type Shared = Rc>; + +#[cfg(not(test))] +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Default, Hash)] +pub struct Key([u8; 20]); + +#[cfg(test)] +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Default, Hash, Rand)] +pub struct Key([u8; 20]); + +impl Key { + #[inline] + pub fn fixed_len() -> usize { 20 } +} + +impl> From for Key { + #[inline] + fn from(v: T) -> Self { Key(*v.borrow()) } +} + +impl Deref for Key { + type Target = [u8; 20]; + + #[inline] + fn deref(&self) -> &Self::Target { &self.0 } +} + +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Default)] +pub struct KeyId(u32); + +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Default)] +pub struct Offset(u32); + +macro_rules! impl_u32_type { + ($T: ident) => ( + impl $T { + #[inline] + pub fn to_usize(&self) -> usize { self.0 as usize } + } + + impl From for $T { + #[inline] + fn from(v: u32) -> Self { $T(v) } + } + + impl Into for $T { + #[inline] + fn into(self) -> u32 { self.0 } + } + ) +} + +impl_u32_type!(KeyId); +impl_u32_type!(Offset); + +impl KeyId { + /// The LSB of Offset is reserved to indicate whether it is a KeyId or not + #[inline] + pub fn to_encoded_offset(&self) -> Result { + if self.0 as usize > 0x7fff_ffff { + return Err(ErrorKind::OffsetOverflow(self.0 as usize).into()) + } + Ok((self.0 << 1 | 1).into()) + } +}