Skip to content

Commit

Permalink
Add example on how to use bincode for keys and values
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreichold authored and cberner committed Jun 16, 2024
1 parent 9192b34 commit 2036664
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 4 deletions.
10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ crate-type = ["cdylib", "rlib"]
pyo3-build-config = { version = "0.20.0", optional = true }

[dependencies]
log = {version = "0.4.17", optional = true }
pyo3 = {version = "0.20.0", features=["extension-module", "abi3-py37"], optional = true }
log = { version = "0.4.17", optional = true }
pyo3 = { version = "0.20.0", features=["extension-module", "abi3-py37"], optional = true }

[target.'cfg(unix)'.dependencies]
libc = "0.2.104"
Expand All @@ -32,6 +32,8 @@ tempfile = "3.5.0"
redb1 = { version = "=1.0.0", package = "redb" }
# for backwards compatibility testing - pin at 2.0.0
redb2 = { version = "=2.0.0", package = "redb" }
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3.3"

# Just benchmarking dependencies
[target.'cfg(not(target_os = "wasi"))'.dev-dependencies]
Expand All @@ -51,9 +53,9 @@ io-uring = "0.6.2"

[features]
# This feature is still experimental, and is not considered stable
python = [ "pyo3", "pyo3-build-config" ]
python = ["dep:pyo3", "dep:pyo3-build-config"]
# Enables log messages
logging = ["log"]
logging = ["dep:log"]
# Enable cache hit metrics
cache_metrics = []

Expand Down
108 changes: 108 additions & 0 deletions examples/bincode_keys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use std::any::type_name;
use std::cmp::Ordering;
use std::fmt::Debug;

use bincode::{deserialize, serialize};
use redb::{Database, Error, Key, Range, TableDefinition, TypeName, Value};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
struct SomeKey {
foo: String,
bar: i32,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SomeValue {
foo: [f64; 3],
bar: bool,
}

const TABLE: TableDefinition<Bincode<SomeKey>, Bincode<SomeValue>> =
TableDefinition::new("my_data");

fn main() -> Result<(), Error> {
let some_key = SomeKey {
foo: "hello world".to_string(),
bar: 42,
};
let some_value = SomeValue {
foo: [1., 2., 3.],
bar: true,
};
let lower = SomeKey {
foo: "a".to_string(),
bar: 42,
};
let upper = SomeKey {
foo: "z".to_string(),
bar: 42,
};

let db = Database::create("bincode_keys.redb")?;
let write_txn = db.begin_write()?;
{
let mut table = write_txn.open_table(TABLE)?;

table.insert(&some_key, &some_value).unwrap();
}
write_txn.commit()?;

let read_txn = db.begin_read()?;
let table = read_txn.open_table(TABLE)?;

let mut iter: Range<Bincode<SomeKey>, Bincode<SomeValue>> = table.range(lower..upper).unwrap();
assert_eq!(iter.next().unwrap().unwrap().1.value(), some_value);
assert!(iter.next().is_none());

Ok(())
}

/// Wrapper type to handle keys and values using bincode serialization
#[derive(Debug)]
pub struct Bincode<T>(pub T);

impl<T> Value for Bincode<T>
where
T: Debug + Serialize + for<'a> Deserialize<'a>,
{
type SelfType<'a> = T
where
Self: 'a;

type AsBytes<'a> = Vec<u8>
where
Self: 'a;

fn fixed_width() -> Option<usize> {
None
}

fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
where
Self: 'a,
{
deserialize(data).unwrap()
}

fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
where
Self: 'a,
Self: 'b,
{
serialize(value).unwrap()
}

fn type_name() -> TypeName {
TypeName::new(&format!("Bincode<{}>", type_name::<T>()))
}
}

impl<T> Key for Bincode<T>
where
T: Debug + Serialize + DeserializeOwned + Ord,
{
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
Self::from_bytes(data1).cmp(&Self::from_bytes(data2))
}
}

0 comments on commit 2036664

Please sign in to comment.