Using the Substrate blockchain framework, how can I convert between Substrate specific types and Rust primitive types and vice versa?
For example:
T::Moment
) to a u64
T::Balance
etc...
Rust provides no implicit type conversion (coercion) between primitive types. But, explicit type conversion (casting) can be performed using the as keyword. Rules for converting between integral types follow C conventions generally, except in cases where C has undefined behavior.
The Into trait is simply the reciprocal of the From trait. That is, if you have implemented the From trait for your type, Into will call it when necessary. Using the Into trait will typically require specification of the type to convert into as the compiler is unable to determine this most of the time.
Substrate has removed As
in favor of From
/Into
. An assumption is made that all types are at least u32
.
From the trait SimpleArithmatic
, the following are implemented:
From
: u8
, u16
, u32
TryFrom
: u64
, u128
, usize
TryInto
: u8
, u16
, u32
, u64
, u128
, usize
Another trait is also provided to provide ergonomic infallible conversion when you don't care if the value saturates.
UniqueSaturatedInto
: u8
, u16
, u32
, u64
, u128
UniqueSaturatedFrom
: u64
, u128
NOTE on
SaturatedConversion
from Gav
SaturatedConversion
(saturated_into
andsaturated_from
) should not be used unless you know what you're doing, you've thought and considered all options and your use-case implies that saturation is fundamentally correct. The only time I imagine this is the case is deep in runtime arithmetic where you are logically certain it will not overflow, but can't provide a proof because it would depend on consistent pre-existing state.
This means that working from u32
to Substrate specific types should be easy:
pub fn u32_to_balance(input: u32) -> T::Balance {
input.into()
}
For larger types, you need to handle the case where the Balance
type for a runtime is smaller than what is available:
pub fn u64_to_balance_option(input: u64) -> Option<T::Balance> {
input.try_into().ok()
}
// Note the warning above about saturated conversions
pub fn u64_to_balance_saturated(input: u64) -> T::Balance {
input.saturated_into()
}
When converting from T::Balance
to a rust primitive, you need to also handle conversion between incompatible types:
pub fn balance_to_u64(input: T::Balance) -> Option<u64> {
TryInto::<u64>::try_into(input).ok()
}
// Note the warning above about saturated conversions
pub fn balance_to_u64_saturated(input: T::Balance) -> u64 {
input.saturated_into::<u64>()
}
Substrate provides pub trait As<T>
in the sr-primitives
crate:
/// Simple trait similar to `Into`, except that it can be used to convert numerics between each
/// other.
pub trait As<T> {
/// Convert forward (ala `Into::into`).
fn as_(self) -> T;
/// Convert backward (ala `From::from`).
fn sa(_: T) -> Self;
}
Here are some working examples of how it can be used:
impl<T: Trait> Module<T> {
// `as_` will turn T::Balance into a u64
pub fn balance_to_u64(input: T::Balance) -> u64 {
input.as_()
}
// Being explicit, you can convert a `u64` to a T::Balance
// using the `As` trait, with `T: u64`, and then calling `sa`
pub fn u64_to_balance(input: u64) -> T::Balance {
<T::Balance as As<u64>>::sa(input)
}
// You can also let Rust figure out what `T` is
pub fn u64_to_balance_implied(input: u64) -> T::Balance {
<T::Balance as As<_>>::sa(input)
}
// You can also let Rust figure out where `sa` is implemented
pub fn u64_to_balance_implied_more(input: u64) -> T::Balance {
T::Balance::sa(input)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With