diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index 78f2e39301..5bd7358e4f 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -530,7 +530,7 @@ morph_types! { } where L::Type: Ord, M: TryMorph; } -/// Extensible conversion trait. Generic over both source and destination types. +/// Infallible conversion trait. Generic over both source and destination types. pub trait Convert { /// Make conversion. fn convert(a: A) -> B; @@ -542,7 +542,125 @@ impl Convert for () { } } -/// Adapter which turns a `Get` implementation into a `Convert` implementation which always returns +/// Reversing infallible conversion trait. Generic over both source and destination types. +/// +/// This specifically reverses the conversion. +pub trait ConvertBack: Convert { + /// Make conversion back. + fn convert_back(b: B) -> A; +} + +/// Fallible conversion trait returning an [Option]. Generic over both source and destination types. +pub trait MaybeConvert { + /// Attempt to make conversion. + fn maybe_convert(a: A) -> Option; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl MaybeConvert for Tuple { + fn maybe_convert(a: A) -> Option { + for_tuples!( #( + match Tuple::maybe_convert(a.clone()) { + Some(b) => return Some(b), + None => {}, + } + )* ); + None + } +} + +/// Reversing fallible conversion trait returning an [Option]. Generic over both source and +/// destination types. +pub trait MaybeConvertBack: MaybeConvert { + /// Attempt to make conversion back. + fn maybe_convert_back(b: B) -> Option; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl MaybeConvertBack for Tuple { + fn maybe_convert_back(b: B) -> Option { + for_tuples!( #( + match Tuple::maybe_convert_back(b.clone()) { + Some(a) => return Some(a), + None => {}, + } + )* ); + None + } +} + +/// Fallible conversion trait which returns the argument in the case of being unable to convert. +/// Generic over both source and destination types. +pub trait TryConvert { + /// Attempt to make conversion. If returning [Result::Err], the inner must always be `a`. + fn try_convert(a: A) -> Result; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl TryConvert for Tuple { + fn try_convert(a: A) -> Result { + for_tuples!( #( + let a = match Tuple::try_convert(a) { + Ok(b) => return Ok(b), + Err(a) => a, + }; + )* ); + Err(a) + } +} + +/// Reversing fallible conversion trait which returns the argument in the case of being unable to +/// convert back. Generic over both source and destination types. +pub trait TryConvertBack: TryConvert { + /// Attempt to make conversion back. If returning [Result::Err], the inner must always be `b`. + + fn try_convert_back(b: B) -> Result; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl TryConvertBack for Tuple { + fn try_convert_back(b: B) -> Result { + for_tuples!( #( + let b = match Tuple::try_convert_back(b) { + Ok(a) => return Ok(a), + Err(b) => b, + }; + )* ); + Err(b) + } +} + +/// Definition for a bi-directional, fallible conversion between two types. +pub trait MaybeEquivalence { + /// Attempt to convert reference of `A` into value of `B`, returning `None` if not possible. + fn convert(a: &A) -> Option; + /// Attempt to convert reference of `B` into value of `A`, returning `None` if not possible. + fn convert_back(b: &B) -> Option; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl MaybeEquivalence for Tuple { + fn convert(a: &A) -> Option { + for_tuples!( #( + match Tuple::convert(a) { + Some(b) => return Some(b), + None => {}, + } + )* ); + None + } + fn convert_back(b: &B) -> Option { + for_tuples!( #( + match Tuple::convert_back(b) { + Some(a) => return Some(a), + None => {}, + } + )* ); + None + } +} + +/// Adapter which turns a [Get] implementation into a [Convert] implementation which always returns /// in the same value no matter the input. pub struct ConvertToValue(sp_std::marker::PhantomData); impl> Convert for ConvertToValue { @@ -550,6 +668,34 @@ impl> Convert for ConvertToValue { T::get() } } +impl> MaybeConvert for ConvertToValue { + fn maybe_convert(_: X) -> Option { + Some(T::get()) + } +} +impl> MaybeConvertBack for ConvertToValue { + fn maybe_convert_back(_: Y) -> Option { + None + } +} +impl> TryConvert for ConvertToValue { + fn try_convert(_: X) -> Result { + Ok(T::get()) + } +} +impl> TryConvertBack for ConvertToValue { + fn try_convert_back(y: Y) -> Result { + Err(y) + } +} +impl> MaybeEquivalence for ConvertToValue { + fn convert(_: &X) -> Option { + Some(T::get()) + } + fn convert_back(_: &Y) -> Option { + None + } +} /// A structure that performs identity conversion. pub struct Identity; @@ -563,19 +709,100 @@ impl ConvertBack for Identity { a } } +impl MaybeConvert for Identity { + fn maybe_convert(a: T) -> Option { + Some(a) + } +} +impl MaybeConvertBack for Identity { + fn maybe_convert_back(a: T) -> Option { + Some(a) + } +} +impl TryConvert for Identity { + fn try_convert(a: T) -> Result { + Ok(a) + } +} +impl TryConvertBack for Identity { + fn try_convert_back(a: T) -> Result { + Ok(a) + } +} +impl MaybeEquivalence for Identity { + fn convert(a: &T) -> Option { + Some(a.clone()) + } + fn convert_back(a: &T) -> Option { + Some(a.clone()) + } +} /// A structure that performs standard conversion using the standard Rust conversion traits. pub struct ConvertInto; -impl> Convert for ConvertInto { +impl, B> Convert for ConvertInto { fn convert(a: A) -> B { a.into() } } +impl, B> MaybeConvert for ConvertInto { + fn maybe_convert(a: A) -> Option { + Some(a.into()) + } +} +impl, B: Into> MaybeConvertBack for ConvertInto { + fn maybe_convert_back(b: B) -> Option { + Some(b.into()) + } +} +impl, B> TryConvert for ConvertInto { + fn try_convert(a: A) -> Result { + Ok(a.into()) + } +} +impl, B: Into> TryConvertBack for ConvertInto { + fn try_convert_back(b: B) -> Result { + Ok(b.into()) + } +} +impl, B: Clone + Into> MaybeEquivalence for ConvertInto { + fn convert(a: &A) -> Option { + Some(a.clone().into()) + } + fn convert_back(b: &B) -> Option { + Some(b.clone().into()) + } +} -/// Extensible conversion trait. Generic over both source and destination types. -pub trait ConvertBack: Convert { - /// Make conversion back. - fn convert_back(b: B) -> A; +/// A structure that performs standard conversion using the standard Rust conversion traits. +pub struct TryConvertInto; +impl, B> MaybeConvert for TryConvertInto { + fn maybe_convert(a: A) -> Option { + a.clone().try_into().ok() + } +} +impl, B: Clone + TryInto> MaybeConvertBack for TryConvertInto { + fn maybe_convert_back(b: B) -> Option { + b.clone().try_into().ok() + } +} +impl, B> TryConvert for TryConvertInto { + fn try_convert(a: A) -> Result { + a.clone().try_into().map_err(|_| a) + } +} +impl, B: Clone + TryInto> TryConvertBack for TryConvertInto { + fn try_convert_back(b: B) -> Result { + b.clone().try_into().map_err(|_| b) + } +} +impl, B: Clone + TryInto> MaybeEquivalence for TryConvertInto { + fn convert(a: &A) -> Option { + a.clone().try_into().ok() + } + fn convert_back(b: &B) -> Option { + b.clone().try_into().ok() + } } /// Convenience type to work around the highly unergonomic syntax needed