diff --git a/betree/Cargo.toml b/betree/Cargo.toml index e0b8a029..63507ced 100644 --- a/betree/Cargo.toml +++ b/betree/Cargo.toml @@ -59,6 +59,7 @@ lfu_cache = { git = "https://github.com/parcio/lfu-cache", rev = "haura-v5" } rand = { version = "0.8", features = ["std_rng"] } pmdk = { path = "./pmdk", optional = true } +rustc-hash = "1.1.0" [dev-dependencies] rand_xorshift = "0.3" diff --git a/betree/src/checksum.rs b/betree/src/checksum.rs deleted file mode 100644 index ee194c03..00000000 --- a/betree/src/checksum.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! This module provides a `Checksum` trait for verifying data integrity. - -use crate::size::{Size, StaticSize}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use std::{error::Error, fmt, hash::Hasher, iter::once}; -use twox_hash; - -/// A checksum to verify data integrity. -pub trait Checksum: - Serialize + DeserializeOwned + Size + Clone + Send + Sync + fmt::Debug + 'static -{ - /// Builds a new `Checksum`. - type Builder: Builder; - - /// Verifies the contents of the given buffer which consists of multiple - /// `u8` slices. - fn verify_buffer, T: AsRef<[u8]>>( - &self, - data: I, - ) -> Result<(), ChecksumError>; - - /// Verifies the contents of the given buffer. - fn verify(&self, data: &[u8]) -> Result<(), ChecksumError> { - self.verify_buffer(once(data)) - } - - /// Create a valid empty builder for this checksum type. - fn builder() -> Self::Builder; -} - -/// A checksum builder -pub trait Builder: - Serialize + DeserializeOwned + Clone + Send + Sync + fmt::Debug + 'static -{ - /// The internal state of the checksum. - type State: State; - - /// Create a new state to build a checksum. - fn build(&self) -> Self::State; -} - -/// Holds a state for building a new `Checksum`. -pub trait State { - /// The resulting `Checksum`. - type Checksum: Checksum; - - /// Ingests the given data into the state. - fn ingest(&mut self, data: &[u8]); - - /// Builds the actual `Checksum`. - fn finish(self) -> Self::Checksum; -} - -/// This is the error that will be returned when a `Checksum` does not match. -#[derive(Debug)] -pub struct ChecksumError; - -impl fmt::Display for ChecksumError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "Failed to verify the integrity") - } -} - -impl Error for ChecksumError { - fn description(&self) -> &str { - "a checksum error occurred" - } -} - -/// `XxHash` contains a digest of `xxHash` -/// which is an "extremely fast non-cryptographic hash algorithm" -/// () -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] -pub struct XxHash(u64); - -impl StaticSize for XxHash { - fn static_size() -> usize { - 8 - } -} - -impl Checksum for XxHash { - type Builder = XxHashBuilder; - - fn verify_buffer, T: AsRef<[u8]>>( - &self, - data: I, - ) -> Result<(), ChecksumError> { - let mut state = XxHashBuilder.build(); - for x in data { - state.ingest(x.as_ref()); - } - let other = state.finish(); - if *self == other { - Ok(()) - } else { - Err(ChecksumError) - } - } - - fn builder() -> Self::Builder { - XxHashBuilder - } -} - -/// The corresponding `Builder` for `XxHash`. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct XxHashBuilder; - -impl Builder for XxHashBuilder { - type State = XxHashState; - - fn build(&self) -> Self::State { - XxHashState(twox_hash::XxHash::with_seed(0)) - } -} - -/// The internal state of `XxHash`. -pub struct XxHashState(twox_hash::XxHash); - -impl State for XxHashState { - type Checksum = XxHash; - - fn ingest(&mut self, data: &[u8]) { - self.0.write(data); - } - - fn finish(self) -> Self::Checksum { - XxHash(self.0.finish()) - } -} - -/// The rustc own hash impl originally from Firefox. -#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] -pub struct FxHash(u64); - -impl StaticSize for FxHash { - fn static_size() -> usize { - 8 - } -} - -impl Checksum for FxHash { - type Builder = FxHashBuilder; - - fn verify_buffer, T: AsRef<[u8]>>( - &self, - data: I, - ) -> Result<(), ChecksumError> { - let mut state = FxHashBuilder.build(); - for x in data { - state.ingest(x.as_ref()); - } - let other = state.finish(); - if *self == other { - Ok(()) - } else { - Err(ChecksumError) - } - } - - fn builder() -> Self::Builder { - FxHashBuilder - } -} - -/// The corresponding `Builder` for `XxHash`. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FxHashBuilder; - -impl Builder for FxHashBuilder { - type State = FxHashState; - - fn build(&self) -> Self::State { - FxHashState(FxHasher::default()) - } -} - -use rustc_hash::FxHasher; - -/// The internal state of `XxHash`. -pub struct FxHashState(FxHasher); - -impl State for FxHashState { - type Checksum = FxHash; - - fn ingest(&mut self, data: &[u8]) { - self.0.write(data); - } - - fn finish(self) -> Self::Checksum { - FxHash(self.0.finish()) - } -} diff --git a/betree/src/checksum/fxhash.rs b/betree/src/checksum/fxhash.rs new file mode 100644 index 00000000..dd56c985 --- /dev/null +++ b/betree/src/checksum/fxhash.rs @@ -0,0 +1,67 @@ +/// Impl for Checksum for FxHash. +use super::{Builder, Checksum, ChecksumError, State}; +use crate::size::StaticSize; +use rustc_hash::FxHasher; +use serde::{Deserialize, Serialize}; +use std::hash::Hasher; + +/// The rustc own hash impl originally from Firefox. +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] +pub struct FxHash(u64); + +impl StaticSize for FxHash { + fn static_size() -> usize { + 8 + } +} + +impl Checksum for FxHash { + type Builder = FxHashBuilder; + + fn verify_buffer, T: AsRef<[u8]>>( + &self, + data: I, + ) -> Result<(), ChecksumError> { + let mut state = FxHashBuilder.build(); + for x in data { + state.ingest(x.as_ref()); + } + let other = state.finish(); + if *self == other { + Ok(()) + } else { + Err(ChecksumError) + } + } + + fn builder() -> Self::Builder { + FxHashBuilder + } +} + +/// The corresponding `Builder` for `FxHash`. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FxHashBuilder; + +impl Builder for FxHashBuilder { + type State = FxHashState; + + fn build(&self) -> Self::State { + FxHashState(FxHasher::default()) + } +} + +/// The internal state of `XxHash`. +pub struct FxHashState(FxHasher); + +impl State for FxHashState { + type Checksum = FxHash; + + fn ingest(&mut self, data: &[u8]) { + self.0.write(data); + } + + fn finish(self) -> Self::Checksum { + FxHash(self.0.finish()) + } +} diff --git a/betree/src/checksum/mod.rs b/betree/src/checksum/mod.rs new file mode 100644 index 00000000..c4d5c0c4 --- /dev/null +++ b/betree/src/checksum/mod.rs @@ -0,0 +1,73 @@ +//! This module provides a `Checksum` trait for verifying data integrity. + +use crate::size::Size; +use serde::{de::DeserializeOwned, Serialize}; +use std::{error::Error, fmt, iter::once}; + +mod fxhash; +mod xxhash; + +pub use fxhash::{FxHash, FxHashBuilder}; +pub use xxhash::{XxHash, XxHashBuilder}; + +/// A checksum to verify data integrity. +pub trait Checksum: + Serialize + DeserializeOwned + Size + Clone + Send + Sync + fmt::Debug + 'static +{ + /// Builds a new `Checksum`. + type Builder: Builder; + + /// Verifies the contents of the given buffer which consists of multiple + /// `u8` slices. + fn verify_buffer, T: AsRef<[u8]>>( + &self, + data: I, + ) -> Result<(), ChecksumError>; + + /// Verifies the contents of the given buffer. + fn verify(&self, data: &[u8]) -> Result<(), ChecksumError> { + self.verify_buffer(once(data)) + } + + /// Create a valid empty builder for this checksum type. + fn builder() -> Self::Builder; +} + +/// A checksum builder +pub trait Builder: + Serialize + DeserializeOwned + Clone + Send + Sync + fmt::Debug + 'static +{ + /// The internal state of the checksum. + type State: State; + + /// Create a new state to build a checksum. + fn build(&self) -> Self::State; +} + +/// Holds a state for building a new `Checksum`. +pub trait State { + /// The resulting `Checksum`. + type Checksum: Checksum; + + /// Ingests the given data into the state. + fn ingest(&mut self, data: &[u8]); + + /// Builds the actual `Checksum`. + fn finish(self) -> Self::Checksum; +} + +/// This is the error that will be returned when a `Checksum` does not match. +#[derive(Debug)] +pub struct ChecksumError; + +impl fmt::Display for ChecksumError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "Failed to verify the integrity") + } +} + +impl Error for ChecksumError { + fn description(&self) -> &str { + "a checksum error occurred" + } +} diff --git a/betree/src/checksum/xxhash.rs b/betree/src/checksum/xxhash.rs new file mode 100644 index 00000000..de0c0afd --- /dev/null +++ b/betree/src/checksum/xxhash.rs @@ -0,0 +1,67 @@ +/// `XxHash` contains a digest of `xxHash` +/// which is an "extremely fast non-cryptographic hash algorithm" +/// () +use super::{Builder, Checksum, ChecksumError, State}; +use crate::size::StaticSize; +use serde::{Deserialize, Serialize}; +use std::hash::Hasher; + +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] +pub struct XxHash(u64); + +impl StaticSize for XxHash { + fn static_size() -> usize { + 8 + } +} + +impl Checksum for XxHash { + type Builder = XxHashBuilder; + + fn verify_buffer, T: AsRef<[u8]>>( + &self, + data: I, + ) -> Result<(), ChecksumError> { + let mut state = XxHashBuilder.build(); + for x in data { + state.ingest(x.as_ref()); + } + let other = state.finish(); + if *self == other { + Ok(()) + } else { + Err(ChecksumError) + } + } + + fn builder() -> Self::Builder { + XxHashBuilder + } +} + +/// The corresponding `Builder` for `XxHash`. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct XxHashBuilder; + +impl Builder for XxHashBuilder { + type State = XxHashState; + + fn build(&self) -> Self::State { + XxHashState(twox_hash::XxHash::with_seed(0)) + } +} + +/// The internal state of `XxHash`. +pub struct XxHashState(twox_hash::XxHash); + +impl State for XxHashState { + type Checksum = XxHash; + + fn ingest(&mut self, data: &[u8]) { + self.0.write(data); + } + + fn finish(self) -> Self::Checksum { + XxHash(self.0.finish()) + } +}