Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you convert between Substrate specific types and Rust primitive types?

Using the Substrate blockchain framework, how can I convert between Substrate specific types and Rust primitive types and vice versa?

For example:

  • Convert a time (T::Moment) to a u64
  • Convert a u64 to a T::Balance

etc...

like image 739
Shawn Tabrizi Avatar asked May 10 '19 15:05

Shawn Tabrizi


People also ask

How do you change types in Rust?

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.

What is Into in Rust?

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.


1 Answers

For the latest in Substrate master

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 and saturated_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>()
}

For Substrate v1.0

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)
    }
}
like image 108
Shawn Tabrizi Avatar answered Oct 16 '22 06:10

Shawn Tabrizi