Skip to content

Commit

Permalink
Merge pull request #139 from cowlicks/type-erase
Browse files Browse the repository at this point in the history
Remove generic parameters from `Hypercore` and `Storage`
  • Loading branch information
ttiurani authored Jul 4, 2024
2 parents 8a97ff4 + 44eb767 commit 16acbff
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 75 deletions.
5 changes: 2 additions & 3 deletions benches/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::time::{Duration, Instant};
use criterion::async_executor::AsyncStdExecutor;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use hypercore::{Hypercore, HypercoreBuilder, HypercoreError, Storage};
use random_access_disk::RandomAccessDisk;
use tempfile::Builder as TempfileBuilder;

fn bench_create_disk(c: &mut Criterion) {
Expand All @@ -24,7 +23,7 @@ fn bench_create_disk(c: &mut Criterion) {
}

#[cfg(feature = "cache")]
async fn create_hypercore(name: &str) -> Result<Hypercore<RandomAccessDisk>, HypercoreError> {
async fn create_hypercore(name: &str) -> Result<Hypercore, HypercoreError> {
let dir = TempfileBuilder::new()
.prefix(name)
.tempdir()
Expand All @@ -38,7 +37,7 @@ async fn create_hypercore(name: &str) -> Result<Hypercore<RandomAccessDisk>, Hyp
}

#[cfg(not(feature = "cache"))]
async fn create_hypercore(name: &str) -> Result<Hypercore<RandomAccessDisk>, HypercoreError> {
async fn create_hypercore(name: &str) -> Result<Hypercore, HypercoreError> {
let dir = TempfileBuilder::new()
.prefix(name)
.tempdir()
Expand Down
24 changes: 16 additions & 8 deletions benches/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ fn bench_create_memory(c: &mut Criterion) {
}

#[cfg(feature = "cache")]
async fn create_hypercore(
page_size: usize,
) -> Result<Hypercore<RandomAccessMemory>, HypercoreError> {
async fn create_hypercore(page_size: usize) -> Result<Hypercore, HypercoreError> {
use hypercore::StorageTraits;

let storage = Storage::open(
|_| Box::pin(async move { Ok(RandomAccessMemory::new(page_size)) }),
|_| {
Box::pin(async move {
Ok(Box::new(RandomAccessMemory::new(page_size)) as Box<dyn StorageTraits>)
})
},
false,
)
.await?;
Expand All @@ -34,11 +38,15 @@ async fn create_hypercore(
}

#[cfg(not(feature = "cache"))]
async fn create_hypercore(
page_size: usize,
) -> Result<Hypercore<RandomAccessMemory>, HypercoreError> {
async fn create_hypercore(page_size: usize) -> Result<Hypercore, HypercoreError> {
use hypercore::StorageTraits;

let storage = Storage::open(
|_| Box::pin(async move { Ok(RandomAccessMemory::new(page_size)) }),
|_| {
Box::pin(async move {
Ok(Box::new(RandomAccessMemory::new(page_size)) as Box<dyn StorageTraits>)
})
},
false,
)
.await?;
Expand Down
6 changes: 2 additions & 4 deletions examples/replication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use hypercore::{
Hypercore, HypercoreBuilder, HypercoreError, PartialKeypair, RequestBlock, RequestUpgrade,
Storage,
};
use random_access_disk::RandomAccessDisk;
use random_access_memory::RandomAccessMemory;
use tempfile::Builder;
#[cfg(feature = "tokio")]
use tokio::main as async_main;
Expand Down Expand Up @@ -73,8 +71,8 @@ async fn main() {
}

async fn replicate_index(
origin_hypercore: &mut Hypercore<RandomAccessDisk>,
replicated_hypercore: &mut Hypercore<RandomAccessMemory>,
origin_hypercore: &mut Hypercore,
replicated_hypercore: &mut Hypercore,
request_index: u64,
) {
let missing_nodes = origin_hypercore
Expand Down
17 changes: 5 additions & 12 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use random_access_storage::RandomAccess;
use std::fmt::Debug;
#[cfg(feature = "cache")]
use std::time::Duration;
Expand Down Expand Up @@ -53,20 +52,14 @@ impl CacheOptionsBuilder {

/// Build a Hypercore instance with options.
#[derive(Debug)]
pub struct HypercoreBuilder<T>
where
T: RandomAccess + Debug + Send,
{
storage: Storage<T>,
pub struct HypercoreBuilder {
storage: Storage,
options: HypercoreOptions,
}

impl<T> HypercoreBuilder<T>
where
T: RandomAccess + Debug + Send,
{
impl HypercoreBuilder {
/// Create a hypercore builder with a given storage
pub fn new(storage: Storage<T>) -> Self {
pub fn new(storage: Storage) -> Self {
Self {
storage,
options: HypercoreOptions::new(),
Expand Down Expand Up @@ -94,7 +87,7 @@ where

/// Build a new Hypercore.
#[instrument(err, skip_all)]
pub async fn build(self) -> Result<Hypercore<T>, HypercoreError> {
pub async fn build(self) -> Result<Hypercore, HypercoreError> {
Hypercore::new(self.storage, self.options).await
}
}
24 changes: 7 additions & 17 deletions src/core.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Hypercore's main abstraction. Exposes an append-only, secure log structure.
use ed25519_dalek::Signature;
use futures::future::Either;
use random_access_storage::RandomAccess;
use std::convert::TryFrom;
use std::fmt::Debug;
use tracing::instrument;
Expand Down Expand Up @@ -40,12 +39,9 @@ impl HypercoreOptions {

/// Hypercore is an append-only log structure.
#[derive(Debug)]
pub struct Hypercore<T>
where
T: RandomAccess + Debug,
{
pub struct Hypercore {
pub(crate) key_pair: PartialKeypair,
pub(crate) storage: Storage<T>,
pub(crate) storage: Storage,
pub(crate) oplog: Oplog,
pub(crate) tree: MerkleTree,
pub(crate) block_store: BlockStore,
Expand Down Expand Up @@ -79,15 +75,12 @@ pub struct Info {
pub writeable: bool,
}

impl<T> Hypercore<T>
where
T: RandomAccess + Debug + Send,
{
impl Hypercore {
/// Creates/opens new hypercore using given storage and options
pub(crate) async fn new(
mut storage: Storage<T>,
mut storage: Storage,
mut options: HypercoreOptions,
) -> Result<Hypercore<T>, HypercoreError> {
) -> Result<Hypercore, HypercoreError> {
let key_pair: Option<PartialKeypair> = if options.open {
if options.key_pair.is_some() {
return Err(HypercoreError::BadArgument {
Expand Down Expand Up @@ -734,7 +727,6 @@ fn update_contiguous_length(
#[cfg(test)]
mod tests {
use super::*;
use random_access_memory::RandomAccessMemory;

#[async_std::test]
async fn core_create_proof_block_only() -> Result<(), HypercoreError> {
Expand Down Expand Up @@ -1099,9 +1091,7 @@ mod tests {
Ok(())
}

async fn create_hypercore_with_data(
length: u64,
) -> Result<Hypercore<RandomAccessMemory>, HypercoreError> {
async fn create_hypercore_with_data(length: u64) -> Result<Hypercore, HypercoreError> {
let signing_key = generate_signing_key();
create_hypercore_with_data_and_key_pair(
length,
Expand All @@ -1116,7 +1106,7 @@ mod tests {
async fn create_hypercore_with_data_and_key_pair(
length: u64,
key_pair: PartialKeypair,
) -> Result<Hypercore<RandomAccessMemory>, HypercoreError> {
) -> Result<Hypercore, HypercoreError> {
let storage = Storage::new_memory().await?;
let mut hypercore = Hypercore::new(
storage,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub use crate::common::{
};
pub use crate::core::{AppendOutcome, Hypercore, Info};
pub use crate::crypto::{generate_signing_key, sign, verify, PartialKeypair};
pub use crate::storage::Storage;
pub use crate::storage::{Storage, StorageTraits};
pub use ed25519_dalek::{
SecretKey, Signature, SigningKey, VerifyingKey, KEYPAIR_LENGTH, PUBLIC_KEY_LENGTH,
SECRET_KEY_LENGTH,
Expand Down
62 changes: 35 additions & 27 deletions src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ use crate::{
HypercoreError,
};

/// Supertrait for Storage
pub trait StorageTraits: RandomAccess + Debug {}
impl<T: RandomAccess + Debug> StorageTraits for T {}

/// Save data to a desired storage backend.
#[derive(Debug)]
pub struct Storage<T>
where
T: RandomAccess + Debug,
{
tree: T,
data: T,
bitfield: T,
oplog: T,
pub struct Storage {
tree: Box<dyn StorageTraits + Send>,
data: Box<dyn StorageTraits + Send>,
bitfield: Box<dyn StorageTraits + Send>,
oplog: Box<dyn StorageTraits + Send>,
}

pub(crate) fn map_random_access_err(err: RandomAccessError) -> HypercoreError {
Expand All @@ -51,17 +52,18 @@ pub(crate) fn map_random_access_err(err: RandomAccessError) -> HypercoreError {
}
}

impl<T> Storage<T>
where
T: RandomAccess + Debug + Send,
{
impl Storage {
/// Create a new instance. Takes a callback to create new storage instances and overwrite flag.
pub async fn open<Cb>(create: Cb, overwrite: bool) -> Result<Self, HypercoreError>
where
Cb: Fn(
Store,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Result<T, RandomAccessError>> + Send>,
Box<
dyn std::future::Future<
Output = Result<Box<dyn StorageTraits + Send>, RandomAccessError>,
> + Send,
>,
>,
{
let mut tree = create(Store::Tree).await.map_err(map_random_access_err)?;
Expand Down Expand Up @@ -235,39 +237,45 @@ where
Ok(())
}

fn get_random_access(&mut self, store: &Store) -> &mut T {
fn get_random_access(&mut self, store: &Store) -> &mut Box<dyn StorageTraits + Send> {
match store {
Store::Tree => &mut self.tree,
Store::Data => &mut self.data,
Store::Bitfield => &mut self.bitfield,
Store::Oplog => &mut self.oplog,
}
}
}

impl Storage<RandomAccessMemory> {
/// New storage backed by a `RandomAccessMemory` instance.
#[instrument(err)]
pub async fn new_memory() -> Result<Self, HypercoreError> {
let create = |_| async { Ok(RandomAccessMemory::default()) }.boxed();
let create = |_| {
async { Ok(Box::new(RandomAccessMemory::default()) as Box<dyn StorageTraits + Send>) }
.boxed()
};
// No reason to overwrite, as this is a new memory segment
Self::open(create, false).await
}
}

#[cfg(not(target_arch = "wasm32"))]
impl Storage<RandomAccessDisk> {
/// New storage backed by a `RandomAccessDisk` instance.
#[cfg(not(target_arch = "wasm32"))]
#[instrument(err)]
pub async fn new_disk(dir: &PathBuf, overwrite: bool) -> Result<Self, HypercoreError> {
let storage = |store: Store| {
let name = match store {
Store::Tree => "tree",
Store::Data => "data",
Store::Bitfield => "bitfield",
Store::Oplog => "oplog",
};
RandomAccessDisk::open(dir.as_path().join(name)).boxed()
let dir = dir.clone();
async move {
let name = match store {
Store::Tree => "tree",
Store::Data => "data",
Store::Bitfield => "bitfield",
Store::Oplog => "oplog",
};
Ok(
Box::new(RandomAccessDisk::open(dir.as_path().join(name)).await?)
as Box<dyn StorageTraits + Send>,
)
}
.boxed()
};
Self::open(storage, overwrite).await
}
Expand Down
5 changes: 2 additions & 3 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use anyhow::Result;
use ed25519_dalek::{SigningKey, VerifyingKey, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH};
use random_access_disk::RandomAccessDisk;
use sha2::{Digest, Sha256};
use std::io::prelude::*;
use std::path::Path;
Expand Down Expand Up @@ -35,7 +34,7 @@ pub fn get_test_key_pair() -> PartialKeypair {
PartialKeypair { public, secret }
}

pub async fn create_hypercore(work_dir: &str) -> Result<Hypercore<RandomAccessDisk>> {
pub async fn create_hypercore(work_dir: &str) -> Result<Hypercore> {
let path = Path::new(work_dir).to_owned();
let key_pair = get_test_key_pair();
let storage = Storage::new_disk(&path, true).await?;
Expand All @@ -45,7 +44,7 @@ pub async fn create_hypercore(work_dir: &str) -> Result<Hypercore<RandomAccessDi
.await?)
}

pub async fn open_hypercore(work_dir: &str) -> Result<Hypercore<RandomAccessDisk>> {
pub async fn open_hypercore(work_dir: &str) -> Result<Hypercore> {
let path = Path::new(work_dir).to_owned();
let storage = Storage::new_disk(&path, false).await?;
Ok(HypercoreBuilder::new(storage).open(true).build().await?)
Expand Down

0 comments on commit 16acbff

Please sign in to comment.