Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement SortedSet key-value entry type #154

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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