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

(do not merge yet) Erase generic parameter by boxing Storage as trait object #113

Closed
wants to merge 4 commits into from
Closed
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 @@ -38,6 +38,7 @@ tree-index = "0.6.0"
bitfield-rle = "0.2.0"
futures = "0.3.4"
async-std = "1.5.0"
async-trait = "0.1.30"

[dev-dependencies]
quickcheck = "0.9.2"
Expand Down
9 changes: 3 additions & 6 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ use test::Bencher;

use hypercore::{Feed, Storage};

async fn create_feed(page_size: usize) -> Result<Feed<RandomAccessMemory>, Error> {
let storage = Storage::new(
|_| Box::pin(async move { Ok(RandomAccessMemory::new(page_size)) }),
true,
)
.await?;
async fn create_feed(page_size: usize) -> Result<Feed, Error> {
let storage =
Storage::new(|_| Box::pin(async move { Ok(RandomAccessMemory::new(page_size)) })).await?;
Feed::with_storage(storage).await
}

Expand Down
15 changes: 3 additions & 12 deletions examples/async.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,18 @@
use async_std::task;
use hypercore::Feed;
use random_access_storage::RandomAccess;
use std::fmt::Debug;

async fn append<T>(feed: &mut Feed<T>, content: &[u8])
where
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send,
{
async fn append(feed: &mut Feed, content: &[u8]) {
feed.append(content).await.unwrap();
}

async fn print<T>(feed: &mut Feed<T>)
where
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send,
{
async fn print(feed: &mut Feed) {
println!("{:?}", feed.get(0).await);
println!("{:?}", feed.get(1).await);
}

fn main() {
task::block_on(task::spawn(async {
let mut feed = Feed::default();

let mut feed = Feed::open_in_memory().await.unwrap();
append(&mut feed, b"hello").await;
append(&mut feed, b"world").await;
print(&mut feed).await;
Expand Down
62 changes: 32 additions & 30 deletions src/feed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

use crate::feed_builder::FeedBuilder;
use crate::replicate::{Message, Peer};
pub use crate::storage::{Node, NodeTrait, Storage, Store};
pub use crate::storage::{
storage_disk, storage_memory, BoxStorage, Node, NodeTrait, Storage, Store,
};

use crate::audit::Audit;
use crate::bitfield::Bitfield;
Expand All @@ -13,12 +15,8 @@ use crate::proof::Proof;
use anyhow::{bail, ensure, Result};
use flat_tree as flat;
use pretty_hash::fmt as pretty_fmt;
use random_access_disk::RandomAccessDisk;
use random_access_memory::RandomAccessMemory;
use random_access_storage::RandomAccess;
use tree_index::TreeIndex;

use std::borrow::Borrow;
use std::cmp;
use std::fmt::{self, Debug, Display};
use std::ops::Range;
Expand Down Expand Up @@ -55,15 +53,12 @@ use std::sync::Arc;
/// [builder]: crate::feed_builder::FeedBuilder
/// [with_storage]: crate::feed::Feed::with_storage
#[derive(Debug)]
pub struct Feed<T>
where
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug,
{
pub struct Feed {
/// Merkle tree instance.
pub(crate) merkle: Merkle,
pub(crate) public_key: PublicKey,
pub(crate) secret_key: Option<SecretKey>,
pub(crate) storage: Storage<T>,
pub(crate) storage: BoxStorage,
/// Total length of raw data stored in bytes.
pub(crate) byte_length: u64,
/// Total number of entries stored in the `Feed`
Expand All @@ -74,12 +69,9 @@ where
pub(crate) peers: Vec<Peer>,
}

impl<T> Feed<T>
where
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send,
{
impl Feed {
/// Create a new instance with a custom storage backend.
pub async fn with_storage(mut storage: crate::storage::Storage<T>) -> Result<Self> {
pub async fn with_storage(mut storage: BoxStorage) -> Result<Self> {
match storage.read_partial_keypair().await {
Some(partial_keypair) => {
let builder = FeedBuilder::new(partial_keypair.public, storage);
Expand Down Expand Up @@ -113,11 +105,27 @@ where
}

/// Starts a `FeedBuilder` with the provided `PublicKey` and `Storage`.
pub fn builder(public_key: PublicKey, storage: Storage<T>) -> FeedBuilder<T> {
pub fn builder(public_key: PublicKey, storage: BoxStorage) -> FeedBuilder {
FeedBuilder::new(public_key, storage)
}

/// Get the number of entries in the feed.
/// Create a new instance that persists to disk at the location of `dir`.
// TODO: Ensure that dir is always a directory.
// NOTE: Should we `mkdirp` here?
// NOTE: Should we call these `data.bitfield` / `data.tree`?
pub async fn open_from_disk<P: AsRef<Path>>(path: P) -> Result<Self> {
let dir = path.as_ref().to_owned();
let storage = storage_disk(&dir).await?;
Self::with_storage(storage).await
}

/// Create a new in-memory instance.
pub async fn open_in_memory() -> Result<Self> {
let storage = storage_memory().await.unwrap();
Self::with_storage(storage).await
}

/// Get the amount of entries in the feed.
#[inline]
pub fn len(&self) -> u64 {
self.length
Expand Down Expand Up @@ -159,7 +167,7 @@ where
let index = self.length;
let message = hash_with_length_as_bytes(hash, index + 1);
let signature = sign(&self.public_key, key, &message);
self.storage.put_signature(index, signature).await?;
self.storage.put_signature(index, &signature).await?;

for node in self.merkle.nodes() {
self.storage.put_node(node).await?;
Expand Down Expand Up @@ -397,8 +405,7 @@ where
}

if let Some(sig) = sig {
let sig = sig.borrow();
self.storage.put_signature(index, sig).await?;
self.storage.put_signature(index, &sig).await?;
}

for node in nodes {
Expand Down Expand Up @@ -603,7 +610,7 @@ where
}
}

impl Feed<RandomAccessDisk> {
impl Feed {
/// Create a new instance that persists to disk at the location of `dir`.
/// If dir was not there, it will be created.
// NOTE: Should we call these `data.bitfield` / `data.tree`?
Expand All @@ -618,7 +625,7 @@ impl Feed<RandomAccessDisk> {

let dir = path.as_ref().to_owned();

let storage = Storage::new_disk(&dir, false).await?;
let storage = storage_disk(&dir).await?;
Self::with_storage(storage).await
}
}
Expand All @@ -628,18 +635,13 @@ impl Feed<RandomAccessDisk> {
/// ## Panics
/// Can panic if constructing the in-memory store fails, which is highly
/// unlikely.
impl Default for Feed<RandomAccessMemory> {
impl Default for Feed {
fn default() -> Self {
async_std::task::block_on(async {
let storage = Storage::new_memory().await.unwrap();
Self::with_storage(storage).await.unwrap()
})
async_std::task::block_on(async { Self::open_in_memory().await.unwrap() })
}
}

impl<T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send> Display
for Feed<T>
{
impl Display for Feed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO: yay, we should find a way to convert this .unwrap() to an error
// type that's accepted by `fmt::Result<(), fmt::Error>`.
Expand Down
19 changes: 6 additions & 13 deletions src/feed_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use ed25519_dalek::{PublicKey, SecretKey};

use crate::bitfield::Bitfield;
use crate::crypto::Merkle;
use crate::storage::Storage;
use random_access_storage::RandomAccess;
use crate::storage::BoxStorage;
use std::fmt::Debug;
use tree_index::TreeIndex;

Expand All @@ -14,22 +13,16 @@ use anyhow::Result;
// TODO: make this an actual builder pattern.
// https://deterministic.space/elegant-apis-in-rust.html#builder-pattern
#[derive(Debug)]
pub struct FeedBuilder<T>
where
T: RandomAccess + Debug,
{
storage: Storage<T>,
pub struct FeedBuilder {
storage: BoxStorage,
public_key: PublicKey,
secret_key: Option<SecretKey>,
}

impl<T> FeedBuilder<T>
where
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send,
{
impl FeedBuilder {
/// Create a new instance.
#[inline]
pub fn new(public_key: PublicKey, storage: Storage<T>) -> Self {
pub fn new(public_key: PublicKey, storage: BoxStorage) -> Self {
Self {
storage,
public_key,
Expand All @@ -45,7 +38,7 @@ where

/// Finalize the builder.
#[inline]
pub async fn build(mut self) -> Result<Feed<T>> {
pub async fn build(mut self) -> Result<Feed> {
let (bitfield, tree) = if let Ok(bitfield) = self.storage.read_bitfield().await {
Bitfield::from_slice(&bitfield)
} else {
Expand Down
10 changes: 5 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ pub use crate::feed::Feed;
pub use crate::feed_builder::FeedBuilder;
pub use crate::proof::Proof;
pub use crate::replicate::Peer;
pub use crate::storage::{Node, NodeTrait, Storage, Store};
pub use crate::storage::{
storage_disk, storage_memory, BoxStorage, Node, NodeTrait, Storage, Store,
};
pub use ed25519_dalek::{PublicKey, SecretKey};

use std::path::Path;

/// Create a new Hypercore `Feed`.
pub async fn open<P: AsRef<Path>>(
path: P,
) -> anyhow::Result<Feed<random_access_disk::RandomAccessDisk>> {
Feed::open(path).await
pub async fn open<P: AsRef<Path>>(path: P) -> anyhow::Result<Feed> {
Feed::open_from_disk(path).await
}
Loading