use std::any::Any;
use std::fmt::Debug;
use zrx_store::{Key, Value};
use super::{Error, Result, Storage};
pub trait TryAsStorage<K>: Value {
type Target<'a>: Debug;
fn try_as_storage(item: &dyn Any) -> Result<Self::Target<'_>>;
}
pub trait TryAsStorageMut<K>: Value {
type Target<'a>: Debug;
fn try_as_storage_mut(item: &mut dyn Any) -> Result<Self::Target<'_>>;
}
pub trait TryAsStorages<K> {
type Target<'a>: Debug;
fn try_as_storages<'a, T>(iter: T) -> Result<Self::Target<'a>>
where
T: IntoIterator<Item = &'a dyn Any>;
}
impl<K, V> TryAsStorage<K> for V
where
K: Key,
V: Value,
{
type Target<'a> = &'a Storage<K, V>;
#[inline]
fn try_as_storage(item: &dyn Any) -> Result<Self::Target<'_>> {
item.downcast_ref().ok_or(Error::Downcast)
}
}
impl<K, V> TryAsStorageMut<K> for V
where
K: Key,
V: Value,
{
type Target<'a> = &'a mut Storage<K, V>;
#[inline]
fn try_as_storage_mut(item: &mut dyn Any) -> Result<Self::Target<'_>> {
item.downcast_mut().ok_or(Error::Downcast)
}
}
impl<K> TryAsStorages<K> for ()
where
K: Key,
{
type Target<'a> = ();
#[inline]
fn try_as_storages<'a, T>(iter: T) -> Result<Self::Target<'a>>
where
T: IntoIterator<Item = &'a dyn Any>,
{
match iter.into_iter().next() {
Some(_) => Err(Error::Mismatch),
None => Ok(()),
}
}
}
impl<K, V> TryAsStorages<K> for [V]
where
K: Key,
V: TryAsStorage<K>,
{
type Target<'a> = Vec<V::Target<'a>>;
#[inline]
fn try_as_storages<'a, T>(iter: T) -> Result<Self::Target<'a>>
where
T: IntoIterator<Item = &'a dyn Any>,
{
iter.into_iter().map(V::try_as_storage).collect()
}
}
macro_rules! impl_try_as_storages_for_tuple {
($($V:ident),+ $(,)?) => {
impl<K, $($V),+> TryAsStorages<K> for ($($V,)+)
where
K: Key,
$($V: TryAsStorage<K>,)+
{
#[allow(unused_parens)]
type Target<'a> = ($($V::Target<'a>),+);
#[inline]
fn try_as_storages<'a, T>(iter: T) -> Result<Self::Target<'a>>
where
T: IntoIterator<Item = &'a dyn Any>,
{
let mut iter = iter.into_iter();
$(
#[allow(non_snake_case)]
let $V = $V::try_as_storage(
iter.next().ok_or(Error::Mismatch)?
)?;
)+
if iter.next().is_none() {
Ok(($($V),+))
} else {
Err(Error::Mismatch)
}
}
}
};
}
impl_try_as_storages_for_tuple!(V1);
impl_try_as_storages_for_tuple!(V1, V2);
impl_try_as_storages_for_tuple!(V1, V2, V3);
impl_try_as_storages_for_tuple!(V1, V2, V3, V4);
impl_try_as_storages_for_tuple!(V1, V2, V3, V4, V5);
impl_try_as_storages_for_tuple!(V1, V2, V3, V4, V5, V6);
impl_try_as_storages_for_tuple!(V1, V2, V3, V4, V5, V6, V7);
impl_try_as_storages_for_tuple!(V1, V2, V3, V4, V5, V6, V7, V8);