use std::fmt::{self, Debug, Display};
use cid::CidGeneric;
use crate::{Block, Blockstore, CondSend, CondSync, Result};
pub enum EitherBlockstore<L, R>
where
L: Blockstore,
R: Blockstore,
{
Left(L),
Right(R),
}
impl<L, R> EitherBlockstore<L, R>
where
L: Blockstore,
R: Blockstore,
{
pub fn is_left(&self) -> bool {
match self {
EitherBlockstore::Left(_) => true,
EitherBlockstore::Right(_) => false,
}
}
pub fn is_right(&self) -> bool {
match self {
EitherBlockstore::Left(_) => false,
EitherBlockstore::Right(_) => true,
}
}
pub fn left(&self) -> Option<&L> {
match self {
EitherBlockstore::Left(store) => Some(store),
EitherBlockstore::Right(_) => None,
}
}
pub fn right(&self) -> Option<&R> {
match self {
EitherBlockstore::Left(_) => None,
EitherBlockstore::Right(store) => Some(store),
}
}
pub fn left_mut(&mut self) -> Option<&mut L> {
match self {
EitherBlockstore::Left(store) => Some(store),
EitherBlockstore::Right(_) => None,
}
}
pub fn right_mut(&mut self) -> Option<&mut R> {
match self {
EitherBlockstore::Left(_) => None,
EitherBlockstore::Right(store) => Some(store),
}
}
pub fn into_left(self) -> Option<L> {
match self {
EitherBlockstore::Left(store) => Some(store),
EitherBlockstore::Right(_) => None,
}
}
pub fn into_right(self) -> Option<R> {
match self {
EitherBlockstore::Left(_) => None,
EitherBlockstore::Right(store) => Some(store),
}
}
}
impl<L, R> Clone for EitherBlockstore<L, R>
where
L: Blockstore + Clone,
R: Blockstore + Clone,
{
fn clone(&self) -> Self {
match self {
EitherBlockstore::Left(store) => EitherBlockstore::Left(store.clone()),
EitherBlockstore::Right(store) => EitherBlockstore::Right(store.clone()),
}
}
fn clone_from(&mut self, source: &Self) {
match source {
EitherBlockstore::Left(source_store) => match self {
EitherBlockstore::Left(ref mut self_store) => self_store.clone_from(source_store),
EitherBlockstore::Right(_) => *self = EitherBlockstore::Left(source_store.clone()),
},
EitherBlockstore::Right(source_store) => match self {
EitherBlockstore::Left(_) => *self = EitherBlockstore::Right(source_store.clone()),
EitherBlockstore::Right(ref mut self_store) => self_store.clone_from(source_store),
},
};
}
}
impl<L, R> Debug for EitherBlockstore<L, R>
where
L: Blockstore + Debug,
R: Blockstore + Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EitherBlockstore::Left(ref store) => Debug::fmt(store, f),
EitherBlockstore::Right(ref store) => Debug::fmt(store, f),
}
}
}
impl<L, R> Display for EitherBlockstore<L, R>
where
L: Blockstore + Display,
R: Blockstore + Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EitherBlockstore::Left(ref store) => Display::fmt(store, f),
EitherBlockstore::Right(ref store) => Display::fmt(store, f),
}
}
}
macro_rules! call {
($self:ident, $method:ident($($param:expr),*)) => {
match $self {
EitherBlockstore::Left(store) => store.$method($($param),*).await,
EitherBlockstore::Right(store) => store.$method($($param),*).await,
}
};
}
impl<L, R> Blockstore for EitherBlockstore<L, R>
where
L: Blockstore,
R: Blockstore,
{
async fn get<const S: usize>(&self, cid: &CidGeneric<S>) -> Result<Option<Vec<u8>>> {
call!(self, get(cid))
}
async fn put_keyed<const S: usize>(&self, cid: &CidGeneric<S>, data: &[u8]) -> Result<()> {
call!(self, put_keyed(cid, data))
}
async fn remove<const S: usize>(&self, cid: &CidGeneric<S>) -> Result<()> {
call!(self, remove(cid))
}
async fn has<const S: usize>(&self, cid: &CidGeneric<S>) -> Result<bool> {
call!(self, has(cid))
}
async fn put<const S: usize, B>(&self, block: B) -> Result<()>
where
B: Block<S>,
{
call!(self, put(block))
}
async fn put_many<const S: usize, B, I>(&self, blocks: I) -> Result<()>
where
B: Block<S>,
I: IntoIterator<Item = B> + CondSend,
<I as IntoIterator>::IntoIter: Send,
{
call!(self, put_many(blocks))
}
async fn put_many_keyed<const S: usize, D, I>(&self, blocks: I) -> Result<()>
where
D: AsRef<[u8]> + CondSync,
I: IntoIterator<Item = (CidGeneric<S>, D)> + CondSend,
<I as IntoIterator>::IntoIter: Send,
{
call!(self, put_many_keyed(blocks))
}
async fn close(self) -> Result<()> {
call!(self, close())
}
}