Skip to content

Commit

Permalink
refactor: set up the storage and encoding crates
Browse files Browse the repository at this point in the history
  • Loading branch information
uint committed Apr 15, 2024
1 parent 38ed04e commit fdde645
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 166 deletions.
13 changes: 13 additions & 0 deletions crates/storey-encoding/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "storey-encoding"
description = "Interfaces for storey encodings"
version = "0.1.0"
edition = "2021"
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
categories.workspace = true
keywords.workspace = true

[dependencies]
59 changes: 59 additions & 0 deletions crates/storey-encoding/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
pub trait Encoding {
type EncodeError;
type DecodeError;
}

pub trait EncodableWith<E: Encoding>: sealed::SealedE<E> {
fn encode(&self) -> Result<Vec<u8>, E::EncodeError>;
}

pub trait EncodableWithImpl<E: Encoding> {
fn encode_impl(self) -> Result<Vec<u8>, E::EncodeError>;
}

impl<E: Encoding, T> EncodableWith<E> for T
where
for<'a> Cover<&'a T>: EncodableWithImpl<E>,
{
fn encode(&self) -> Result<Vec<u8>, <E as Encoding>::EncodeError> {
Cover(self).encode_impl()
}
}

pub trait DecodableWith<E: Encoding>: Sized + sealed::SealedD<E> {
fn decode(data: &[u8]) -> Result<Self, E::DecodeError>;
}

pub trait DecodableWithImpl<E: Encoding>: Sized {
fn decode_impl(data: &[u8]) -> Result<Self, E::DecodeError>;
}

impl<E: Encoding, T> DecodableWith<E> for T
where
Cover<T>: DecodableWithImpl<E>,
{
fn decode(data: &[u8]) -> Result<Self, <E as Encoding>::DecodeError> {
let wrapper = <Cover<Self>>::decode_impl(data)?;
Ok(wrapper.0)
}
}

mod sealed {
// This module is private to the crate. It's used to seal the `EncodableWith` and
// `DecodableWith` traits, so that the only way they can be implemented outside
// this crate is through the blanket implementations provided by `EncodableWithImpl`
// and `DecodableWithImpl`.
//
// More information on sealed traits:
// https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed

use super::*;

pub trait SealedE<E> {}
pub trait SealedD<E> {}

impl<E: Encoding, T> SealedE<E> for T where for<'a> Cover<&'a T>: EncodableWithImpl<E> {}
impl<E: Encoding, T> SealedD<E> for T where Cover<T>: DecodableWithImpl<E> {}
}

pub struct Cover<T>(pub T);
13 changes: 13 additions & 0 deletions crates/storey-storage/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "storey-storage"
description = "Interfaces for storey storage backends"
version = "0.1.0"
edition = "2021"
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
categories.workspace = true
keywords.workspace = true

[dependencies]
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Storage, StorageMut};
use super::storage::{Storage, StorageMut};

pub trait StorageBackend {
fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
Expand Down
5 changes: 5 additions & 0 deletions crates/storey-storage/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod backend;
mod storage;

pub use backend::{StorageBackend, StorageBackendMut};
pub use storage::{IterableStorage, RevIterableStorage, Storage, StorageMut};
100 changes: 100 additions & 0 deletions crates/storey-storage/src/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
pub trait Storage {
fn get(&self, key: &[u8]) -> Option<Vec<u8>>;

fn has(&self, key: &[u8]) -> bool {
self.get(key).is_some()
}

fn get_meta(&self, _key: &[u8]) -> Option<Vec<u8>>;
fn has_meta(&self, key: &[u8]) -> bool {
self.get_meta(key).is_some()
}
}

pub trait StorageMut {
fn set(&mut self, key: &[u8], value: &[u8]);
fn remove(&mut self, key: &[u8]);

fn set_meta(&mut self, _key: &[u8], _value: &[u8]);
fn remove_meta(&mut self, _key: &[u8]);
}

pub trait IterableStorage {
type KeysIterator<'a>: Iterator<Item = Vec<u8>>
where
Self: 'a;
type ValuesIterator<'a>: Iterator<Item = Vec<u8>>
where
Self: 'a;
type PairsIterator<'a>: Iterator<Item = (Vec<u8>, Vec<u8>)>
where
Self: 'a;

fn keys<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::KeysIterator<'a>;
fn values<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::ValuesIterator<'a>;
fn pairs<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::PairsIterator<'a>;
}

impl<T: IterableStorage> IterableStorage for &T {
type KeysIterator<'a> = T::KeysIterator<'a> where Self: 'a;
type ValuesIterator<'a> = T::ValuesIterator<'a> where Self: 'a;
type PairsIterator<'a> = T::PairsIterator<'a> where Self: 'a;

fn keys<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::KeysIterator<'a> {
(**self).keys(start, end)
}

fn values<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::ValuesIterator<'a> {
(**self).values(start, end)
}

fn pairs<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::PairsIterator<'a> {
(**self).pairs(start, end)
}
}

impl<T: IterableStorage> IterableStorage for &mut T {
type KeysIterator<'a> = T::KeysIterator<'a> where Self: 'a;
type ValuesIterator<'a> = T::ValuesIterator<'a> where Self: 'a;
type PairsIterator<'a> = T::PairsIterator<'a> where Self: 'a;

fn keys<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::KeysIterator<'a> {
(**self).keys(start, end)
}

fn values<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::ValuesIterator<'a> {
(**self).values(start, end)
}

fn pairs<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::PairsIterator<'a> {
(**self).pairs(start, end)
}
}

pub trait RevIterableStorage {
type RevKeysIterator<'a>: Iterator<Item = Vec<u8>>
where
Self: 'a;
type RevValuesIterator<'a>: Iterator<Item = Vec<u8>>
where
Self: 'a;
type RevPairsIterator<'a>: Iterator<Item = (Vec<u8>, Vec<u8>)>
where
Self: 'a;

fn rev_keys<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
) -> Self::RevKeysIterator<'a>;
fn rev_values<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
) -> Self::RevValuesIterator<'a>;
fn rev_pairs<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
) -> Self::RevPairsIterator<'a>;
}
15 changes: 9 additions & 6 deletions crates/storey/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
name = "storey"
description = "Storage abstractions for blockchains"
readme = "../../README.md"
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
categories = { workspace = true }
keywords = { workspace = true }
version = "0.1.0"
edition = "2021"
rust-version = "1.65" # https://caniuse.rs/features/generic_associated_types
license = { workspace = true }
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
categories.workspace = true
keywords.workspace = true

[dependencies]
thiserror = "1"

storey-encoding = { version = "0.1.0", path = "../storey-encoding" }
storey-storage = { version = "0.1.0", path = "../storey-storage" }
1 change: 1 addition & 0 deletions crates/storey/src/containers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod column;
mod item;
mod map;
mod test_mocks;

use std::marker::PhantomData;

Expand Down
1 change: 1 addition & 0 deletions crates/storey/src/containers/test_mocks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

62 changes: 6 additions & 56 deletions crates/storey/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,7 @@
/// A trait for types that serve as "markers" for a particular encoding.
/// These types are expected to be empty structs.
pub trait Encoding {
type EncodeError;
type DecodeError;
}
pub use storey_encoding::Encoding;

/// A trait for types that can be encoded with a particular encoding.
///
Expand All @@ -109,9 +106,7 @@ pub trait Encoding {
/// [See the module-level documentation for an example.](self)
///
/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
pub trait EncodableWith<E: Encoding>: sealed::SealedE<E> {
fn encode(&self) -> Result<Vec<u8>, E::EncodeError>;
}
pub use storey_encoding::EncodableWith;

/// A trait for implementing [`EncodableWith`] for a particular encoding.
///
Expand All @@ -122,19 +117,7 @@ pub trait EncodableWith<E: Encoding>: sealed::SealedE<E> {
/// rules.
///
/// [See the module-level documentation for usage.](self)
pub trait EncodableWithImpl<E: Encoding> {
fn encode_impl(self) -> Result<Vec<u8>, E::EncodeError>;
}

impl<E: Encoding, T> EncodableWith<E> for T
where
for<'a> Cover<&'a T>: EncodableWithImpl<E>,
{
fn encode(&self) -> Result<Vec<u8>, <E as Encoding>::EncodeError> {
Cover(self).encode_impl()
}
}
pub use storey_encoding::EncodableWithImpl;

/// A trait for types that can be decoded with a particular encoding.
///
Expand All @@ -146,9 +129,7 @@ where
/// [See the module-level documentation for an example.](self)
///
/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
pub trait DecodableWith<E: Encoding>: Sized + sealed::SealedD<E> {
fn decode(data: &[u8]) -> Result<Self, E::DecodeError>;
}
pub use storey_encoding::DecodableWith;

/// A trait for implementing [`DecodableWith`] for a particular encoding.
///
Expand All @@ -159,38 +140,7 @@ pub trait DecodableWith<E: Encoding>: Sized + sealed::SealedD<E> {
/// rules.
///
/// [See the module-level documentation for usage.](self)
pub trait DecodableWithImpl<E: Encoding>: Sized {
fn decode_impl(data: &[u8]) -> Result<Self, E::DecodeError>;
}

impl<E: Encoding, T> DecodableWith<E> for T
where
Cover<T>: DecodableWithImpl<E>,
{
fn decode(data: &[u8]) -> Result<Self, <E as Encoding>::DecodeError> {
let wrapper = <Cover<Self>>::decode_impl(data)?;
Ok(wrapper.0)
}
}

mod sealed {
// This module is private to the crate. It's used to seal the `EncodableWith` and
// `DecodableWith` traits, so that the only way they can be implemented outside
// this crate is through the blanket implementations provided by `EncodableWithImpl`
// and `DecodableWithImpl`.
//
// More information on sealed traits:
// https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed

use super::*;

pub trait SealedE<E> {}
pub trait SealedD<E> {}

impl<E: Encoding, T> SealedE<E> for T where for<'a> Cover<&'a T>: EncodableWithImpl<E> {}
impl<E: Encoding, T> SealedD<E> for T where Cover<T>: DecodableWithImpl<E> {}
}
pub use storey_encoding::DecodableWithImpl;

/// A wrapper type used to [cover] type arguments when providing blanket implementations of
/// [`EncodableWithImpl`] and [`DecodableWithImpl`].
Expand All @@ -205,4 +155,4 @@ mod sealed {
///
/// [orphan rules]: https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
/// [cover]: https://doc.rust-lang.org/reference/glossary.html#uncovered-type
pub struct Cover<T>(pub T);
pub use storey_encoding::Cover;
Loading

0 comments on commit fdde645

Please sign in to comment.