Skip to content

Commit

Permalink
Implemented SortedSet key-value entry type
Browse files Browse the repository at this point in the history
Need to design an API to expose it, but this functionality should be all
that's needed for the initial implementation.
  • Loading branch information
ecton committed Jan 27, 2022
1 parent 61b6cde commit 06490ab
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 44 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ members = [
# nebari = { path = "../nebari/nebari", version = "0.1" }
# nebari = { git = "https://github.com/khonsulabs/nebari.git", branch = "main" }
# arc-bytes = { path = "../shared-buffer" }
arc-bytes = { git = "https://github.com/khonsulabs/arc-bytes.git", branch = "main" }

# [patch."https://github.com/khonsulabs/custodian.git"]
# custodian-password = { path = "../custodian/password" }
Expand Down
1 change: 1 addition & 0 deletions crates/bonsaidb-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ tokio = { version = "1", features = ["full"] }
futures = { version = "0.3" }
num-derive = "0.3"
anyhow = "1"
rand = "0.8"

[package.metadata.docs.rs]
all-features = true
62 changes: 36 additions & 26 deletions crates/bonsaidb-core/src/keyvalue.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use arc_bytes::serde::Bytes;
use serde::{Deserialize, Serialize};

mod sorted_set;
mod timestamp;

pub use self::timestamp::Timestamp;
use crate::Error;
use crate::{keyvalue::sorted_set::SortedSet, Error};

mod implementation {
use arc_bytes::serde::Bytes;
Expand Down Expand Up @@ -286,85 +287,94 @@ pub struct SetCommand {
}

/// A value stored in a key.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Value {
/// A value stored as a byte array.
Bytes(Bytes),
/// A numeric value.
Numeric(Numeric),
/// A set of values sorted by an associated value.
SortedSet(SortedSet),
}

impl Value {
/// Validates this value to ensure it is safe to store.
pub fn validate(self) -> Result<Self, Error> {
match self {
Self::Numeric(numeric) => numeric.validate().map(Self::Numeric),
Self::Bytes(vec) => Ok(Self::Bytes(vec)),
other => Ok(other),
}
}

/// Deserializes the bytes contained inside of this value. Returns an error
/// if this value doesn't contain bytes.
pub fn deserialize<V: for<'de> Deserialize<'de>>(&self) -> Result<V, Error> {
match self {
Self::Bytes(bytes) => Ok(pot::from_slice(bytes)?),
Self::Numeric(_) => Err(Error::Database(String::from(
"key contains numeric value, not serialized data",
))),
if let Self::Bytes(bytes) = self {
pot::from_slice(bytes).map_err(Error::from)
} else {
Err(Error::Database(String::from(
"key contains another type of data",
)))
}
}

/// Returns this value as an `i64`, allowing for precision to be lost if the type was not an `i64` originally. If saturating is true, the conversion will not allow overflows. Returns None if the value is bytes.
#[must_use]
pub fn as_i64_lossy(&self, saturating: bool) -> Option<i64> {
match self {
Self::Bytes(_) => None,
Self::Numeric(value) => Some(value.as_i64_lossy(saturating)),
if let Self::Numeric(value) = self {
Some(value.as_i64_lossy(saturating))
} else {
None
}
}

/// Returns this value as an `u64`, allowing for precision to be lost if the type was not an `u64` originally. If saturating is true, the conversion will not allow overflows. Returns None if the value is bytes.
#[must_use]
pub fn as_u64_lossy(&self, saturating: bool) -> Option<u64> {
match self {
Self::Bytes(_) => None,
Self::Numeric(value) => Some(value.as_u64_lossy(saturating)),
if let Self::Numeric(value) = self {
Some(value.as_u64_lossy(saturating))
} else {
None
}
}

/// Returns this value as an `f64`, allowing for precision to be lost if the type was not an `f64` originally. Returns None if the value is bytes.
#[must_use]
pub const fn as_f64_lossy(&self) -> Option<f64> {
match self {
Self::Bytes(_) => None,
Self::Numeric(value) => Some(value.as_f64_lossy()),
if let Self::Numeric(value) = self {
Some(value.as_f64_lossy())
} else {
None
}
}

/// Returns this numeric as an `i64`, allowing for precision to be lost if the type was not an `i64` originally. Returns None if the value is bytes.
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
match self {
Self::Bytes(_) => None,
Self::Numeric(value) => value.as_i64(),
if let Self::Numeric(value) = self {
value.as_i64()
} else {
None
}
}

/// Returns this numeric as an `u64`, allowing for precision to be lost if the type was not an `u64` originally. Returns None if the value is bytes.
#[must_use]
pub fn as_u64(&self) -> Option<u64> {
match self {
Self::Bytes(_) => None,
Self::Numeric(value) => value.as_u64(),
if let Self::Numeric(value) = self {
value.as_u64()
} else {
None
}
}

/// Returns this numeric as an `f64`, allowing for precision to be lost if the type was not an `f64` originally. Returns None if the value is bytes.
#[must_use]
pub const fn as_f64(&self) -> Option<f64> {
match self {
Self::Bytes(_) => None,
Self::Numeric(value) => value.as_f64(),
if let Self::Numeric(value) = self {
value.as_f64()
} else {
None
}
}
}
Expand Down
Loading

0 comments on commit 06490ab

Please sign in to comment.