Skip to content

Commit 60166b0

Browse files
committed
Dynamic dispatch for Storage, no generics in Feed
This removes the generic argument from the Feed struct, making it simpler to work with. Instead, the Storage is internally put into a Box<dyn DynStorage>, where DynStorage is an async trait with the public Storage functions.
1 parent f41ebe3 commit 60166b0

File tree

7 files changed

+161
-117
lines changed

7 files changed

+161
-117
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tree-index = "0.6.0"
3838
bitfield-rle = "0.1.1"
3939
futures = "0.3.4"
4040
async-std = "1.5.0"
41+
async-trait = "0.1.30"
4142

4243
[dev-dependencies]
4344
quickcheck = "0.9.2"

examples/async.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,18 @@
11
use async_std::task;
22
use hypercore::Feed;
3-
use random_access_storage::RandomAccess;
4-
use std::fmt::Debug;
53

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

13-
async fn print<T>(feed: &mut Feed<T>)
14-
where
15-
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send,
16-
{
8+
async fn print(feed: &mut Feed) {
179
println!("{:?}", feed.get(0).await);
1810
println!("{:?}", feed.get(1).await);
1911
}
2012

2113
fn main() {
2214
task::block_on(task::spawn(async {
23-
let mut feed = Feed::default();
24-
15+
let mut feed = Feed::open_in_memory().await.unwrap();
2516
append(&mut feed, b"hello").await;
2617
append(&mut feed, b"world").await;
2718
print(&mut feed).await;

src/feed.rs

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
33
use crate::feed_builder::FeedBuilder;
44
use crate::replicate::{Message, Peer};
5-
pub use crate::storage::{Node, NodeTrait, Storage, Store};
5+
pub use crate::storage::{
6+
storage_disk, storage_memory, BoxStorage, Node, NodeTrait, Storage, Store,
7+
};
68

79
use crate::audit::Audit;
810
use crate::bitfield::Bitfield;
@@ -12,12 +14,8 @@ use anyhow::{bail, ensure, Result};
1214
use ed25519_dalek::{PublicKey, SecretKey, Signature};
1315
use flat_tree as flat;
1416
use pretty_hash::fmt as pretty_fmt;
15-
use random_access_disk::RandomAccessDisk;
16-
use random_access_memory::RandomAccessMemory;
17-
use random_access_storage::RandomAccess;
1817
use tree_index::TreeIndex;
1918

20-
use std::borrow::Borrow;
2119
use std::cmp;
2220
use std::fmt::{self, Debug, Display};
2321
use std::ops::Range;
@@ -26,15 +24,12 @@ use std::sync::Arc;
2624

2725
/// Append-only log structure.
2826
#[derive(Debug)]
29-
pub struct Feed<T>
30-
where
31-
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug,
32-
{
27+
pub struct Feed {
3328
/// Merkle tree instance.
3429
pub(crate) merkle: Merkle,
3530
pub(crate) public_key: PublicKey,
3631
pub(crate) secret_key: Option<SecretKey>,
37-
pub(crate) storage: Storage<T>,
32+
pub(crate) storage: BoxStorage,
3833
/// Total length of data stored.
3934
pub(crate) byte_length: u64,
4035
/// TODO: description. Length of... roots?
@@ -45,12 +40,9 @@ where
4540
pub(crate) peers: Vec<Peer>,
4641
}
4742

48-
impl<T> Feed<T>
49-
where
50-
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send,
51-
{
43+
impl Feed {
5244
/// Create a new instance with a custom storage backend.
53-
pub async fn with_storage(mut storage: crate::storage::Storage<T>) -> Result<Self> {
45+
pub async fn with_storage(mut storage: BoxStorage) -> Result<Self> {
5446
match storage.read_partial_keypair().await {
5547
Some(partial_keypair) => {
5648
let builder = FeedBuilder::new(partial_keypair.public, storage);
@@ -76,10 +68,26 @@ where
7668
}
7769

7870
/// Starts a `FeedBuilder` with the provided `Keypair` and `Storage`.
79-
pub fn builder(public_key: PublicKey, storage: Storage<T>) -> FeedBuilder<T> {
71+
pub fn builder(public_key: PublicKey, storage: BoxStorage) -> FeedBuilder {
8072
FeedBuilder::new(public_key, storage)
8173
}
8274

75+
/// Create a new instance that persists to disk at the location of `dir`.
76+
// TODO: Ensure that dir is always a directory.
77+
// NOTE: Should we `mkdirp` here?
78+
// NOTE: Should we call these `data.bitfield` / `data.tree`?
79+
pub async fn open_from_disk<P: AsRef<Path>>(path: P) -> Result<Self> {
80+
let dir = path.as_ref().to_owned();
81+
let storage = storage_disk(&dir).await?;
82+
Self::with_storage(storage).await
83+
}
84+
85+
/// Create a new in-memory instance.
86+
pub async fn open_in_memory() -> Result<Self> {
87+
let storage = storage_memory().await.unwrap();
88+
Self::with_storage(storage).await
89+
}
90+
8391
/// Get the amount of entries in the feed.
8492
#[inline]
8593
pub fn len(&self) -> u64 {
@@ -116,7 +124,7 @@ where
116124
let hash = Hash::from_roots(self.merkle.roots());
117125
let index = self.length;
118126
let signature = sign(&self.public_key, key, hash.as_bytes());
119-
self.storage.put_signature(index, signature).await?;
127+
self.storage.put_signature(index, &signature).await?;
120128

121129
for node in self.merkle.nodes() {
122130
self.storage.put_node(node).await?;
@@ -352,8 +360,7 @@ where
352360
}
353361

354362
if let Some(sig) = sig {
355-
let sig = sig.borrow();
356-
self.storage.put_signature(index, sig).await?;
363+
self.storage.put_signature(index, &sig).await?;
357364
}
358365

359366
for node in nodes {
@@ -556,35 +563,18 @@ where
556563
}
557564
}
558565

559-
impl Feed<RandomAccessDisk> {
560-
/// Create a new instance that persists to disk at the location of `dir`.
561-
// TODO: Ensure that dir is always a directory.
562-
// NOTE: Should we `mkdirp` here?
563-
// NOTE: Should we call these `data.bitfield` / `data.tree`?
564-
pub async fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
565-
let dir = path.as_ref().to_owned();
566-
let storage = Storage::new_disk(&dir).await?;
567-
Self::with_storage(storage).await
568-
}
569-
}
570-
571566
/// Create a new instance with an in-memory storage backend.
572567
///
573568
/// ## Panics
574569
/// Can panic if constructing the in-memory store fails, which is highly
575570
/// unlikely.
576-
impl Default for Feed<RandomAccessMemory> {
571+
impl Default for Feed {
577572
fn default() -> Self {
578-
async_std::task::block_on(async {
579-
let storage = Storage::new_memory().await.unwrap();
580-
Self::with_storage(storage).await.unwrap()
581-
})
573+
async_std::task::block_on(async { Self::open_in_memory().await.unwrap() })
582574
}
583575
}
584576

585-
impl<T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug + Send> Display
586-
for Feed<T>
587-
{
577+
impl Display for Feed {
588578
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
589579
// TODO: yay, we should find a way to convert this .unwrap() to an error
590580
// type that's accepted by `fmt::Result<(), fmt::Error>`.

src/feed_builder.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use ed25519_dalek::{PublicKey, SecretKey};
22

33
use crate::bitfield::Bitfield;
44
use crate::crypto::Merkle;
5-
use crate::storage::Storage;
6-
use random_access_storage::RandomAccess;
5+
use crate::storage::BoxStorage;
76
use std::fmt::Debug;
87
use tree_index::TreeIndex;
98

@@ -14,22 +13,16 @@ use anyhow::Result;
1413
// TODO: make this an actual builder pattern.
1514
// https://deterministic.space/elegant-apis-in-rust.html#builder-pattern
1615
#[derive(Debug)]
17-
pub struct FeedBuilder<T>
18-
where
19-
T: RandomAccess + Debug,
20-
{
21-
storage: Storage<T>,
16+
pub struct FeedBuilder {
17+
storage: BoxStorage,
2218
public_key: PublicKey,
2319
secret_key: Option<SecretKey>,
2420
}
2521

26-
impl<T> FeedBuilder<T>
27-
where
28-
T: RandomAccess<Error = Box<dyn std::error::Error + Send + Sync>> + Debug,
29-
{
22+
impl FeedBuilder {
3023
/// Create a new instance.
3124
#[inline]
32-
pub fn new(public_key: PublicKey, storage: Storage<T>) -> Self {
25+
pub fn new(public_key: PublicKey, storage: BoxStorage) -> Self {
3326
Self {
3427
storage,
3528
public_key,
@@ -45,7 +38,7 @@ where
4538

4639
/// Finalize the builder.
4740
#[inline]
48-
pub fn build(self) -> Result<Feed<T>> {
41+
pub fn build(self) -> Result<Feed> {
4942
Ok(Feed {
5043
merkle: Merkle::new(),
5144
byte_length: 0,

src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ pub use ed25519_dalek::{PublicKey, SecretKey};
5454
use std::path::Path;
5555

5656
/// Create a new Hypercore `Feed`.
57-
pub async fn open<P: AsRef<Path>>(
58-
path: P,
59-
) -> anyhow::Result<Feed<random_access_disk::RandomAccessDisk>> {
60-
Feed::open(path).await
57+
pub async fn open<P: AsRef<Path>>(path: P) -> anyhow::Result<Feed> {
58+
Feed::open_from_disk(path).await
6159
}

0 commit comments

Comments
 (0)