use super::error::{Error, Result};
use super::Value;
pub trait TryFromValue<'a>: Sized + 'a {
fn try_from_value(opt: Option<&'a dyn Value>) -> Result<Self>;
}
pub trait TryFromValues<'a>: Sized + 'a {
fn try_from_values<V>(values: V) -> Result<Self>
where
V: IntoIterator<Item = Option<&'a dyn Value>>;
}
impl<'a, T> TryFromValue<'a> for &'a T
where
T: Value,
{
#[inline]
fn try_from_value(opt: Option<&'a dyn Value>) -> Result<Self> {
opt.map_or(Err(Error::Presence), |value| {
value.downcast_ref::<T>().ok_or(Error::Downcast)
})
}
}
impl<'a, T> TryFromValue<'a> for Option<&'a T>
where
T: Value,
{
#[inline]
fn try_from_value(opt: Option<&'a dyn Value>) -> Result<Self> {
opt.map_or(Ok(None), |value| {
value.downcast_ref::<T>().ok_or(Error::Downcast).map(Some)
})
}
}
impl<'a, T> TryFromValues<'a> for T
where
T: TryFromValue<'a>,
{
#[inline]
fn try_from_values<V>(values: V) -> Result<Self>
where
V: IntoIterator<Item = Option<&'a dyn Value>>,
{
let mut iter = values.into_iter();
if let (Some(opt), None) = (iter.next(), iter.next()) {
T::try_from_value(opt)
} else {
Err(Error::Mismatch)
}
}
}
impl<'a, T> TryFromValues<'a> for Vec<T>
where
T: TryFromValue<'a>,
{
#[inline]
fn try_from_values<V>(values: V) -> Result<Self>
where
V: IntoIterator<Item = Option<&'a dyn Value>>,
{
values.into_iter().map(T::try_from_value).collect()
}
}
impl<'a> TryFromValues<'a> for () {
#[inline]
fn try_from_values<V>(values: V) -> Result<Self>
where
V: IntoIterator<Item = Option<&'a dyn Value>>,
{
match values.into_iter().next() {
Some(_) => Err(Error::Mismatch),
None => Ok(()),
}
}
}
macro_rules! impl_try_from_values_for_tuple {
($($T:ident),+ $(,)?) => {
impl<'a, $($T),+> TryFromValues<'a> for ($($T,)+)
where
$($T: TryFromValue<'a>,)+
{
#[inline]
fn try_from_values<V>(values: V) -> Result<Self>
where
V: IntoIterator<Item = Option<&'a dyn Value>>,
{
let mut iter = values.into_iter();
$(
#[allow(non_snake_case)]
let $T = $T::try_from_value(iter.next()
.ok_or(Error::Mismatch)?)?;
)+
if iter.next().is_none() {
Ok(($($T,)+))
} else {
Err(Error::Mismatch)
}
}
}
};
}
impl_try_from_values_for_tuple!(T1);
impl_try_from_values_for_tuple!(T1, T2);
impl_try_from_values_for_tuple!(T1, T2, T3);
impl_try_from_values_for_tuple!(T1, T2, T3, T4);
impl_try_from_values_for_tuple!(T1, T2, T3, T4, T5);
impl_try_from_values_for_tuple!(T1, T2, T3, T4, T5, T6);
impl_try_from_values_for_tuple!(T1, T2, T3, T4, T5, T6, T7);
impl_try_from_values_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);