Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I convert a usize to a u32 using TryFrom?

Tags:

rust

I want to convert a usize typed variable into a u32 typed variable in Rust. I am aware that the usize variable might contain a value larger than 2^32, and in that case the conversion should fail. I am trying to use the TryFrom trait to perform the conversion.

This is a simple example (Nightly Rust, Playground):

#![feature(try_from)]
use std::convert::TryFrom;

fn main() {
    let a: usize = 0x100;
    let res = u32::try_from(a);
    println!("res = {:?}", res);
}

The code doesn't compile, with the following compilation error:

error[E0277]: the trait bound `u32: std::convert::From<usize>` is not satisfied
 --> src/main.rs:6:15
  |
6 |     let res = u32::try_from(a);
  |               ^^^^^^^^^^^^^ the trait `std::convert::From<usize>` is not implemented for `u32`
  |
  = help: the following implementations were found:
            <u32 as std::convert::From<std::net::Ipv4Addr>>
            <u32 as std::convert::From<u8>>
            <u32 as std::convert::From<char>>
            <u32 as std::convert::From<u16>>
  = note: required because of the requirements on the impl of `std::convert::TryFrom<usize>` for `u32`

I deduce from the compilation error that having TryFrom<usize> for u32 is dependent on having From<usize> for u32, which seems somewhat strange to me.

Is there any other way I could utilize TryFrom to convert from usize to u32? If not, is there any other idiomatic way to perform this conversion?

I know that I can use the as keyword, but it doesn't notify me if something went wrong with the conversion. In addition, I think that I can write my own function that does the conversion, but I would be surprised if Rust doesn't have some idiomatic way to do this conversion. usize and u32 are two basic types, after all.

like image 247
real Avatar asked May 20 '18 17:05

real


People also ask

What is rust Usize?

usize is the type of Unsigned integers in rust; they meant to deal with integers in rust. Also, they allow positive integers only. we have several types available for unsigned integers, out of which usize is one of them, it stores the integer, or we can say its size in the form of an arch.


1 Answers

Since this answer was created, it was decided to have the implementation of TryFrom<usize> always allow for the possibility of failure, regardless of the current platform. The original code now compiles successfully in Rust 1.34.

Original answer

having TryFrom<usize> for u32 is dependent on having From<usize> for u32, which seems somewhat strange to me

This is because there's a blanket implementation of TryFrom for anything that implements From:

impl<T, U> TryFrom<U> for T
where
    T: From<U>,
{
    type Error = !;
}

As you mentioned, since Rust supports platforms where the native integer length is 16, 32, or 64 bits, having such an implementation of From / Into would not be lossless on some of these platforms.

This error occurs because there's no direct implementation of TryFrom / TryInto for these types. This is because users of these traits prefer that the implementations be infallible when platform-appropriate (The type Error = !).

There is a separate tracking issue 49415 specifically for deciding this issue.

I think that I can write my own function that does the conversion

Yes, that is what you should do. Something like this untested piece of code:

use std::u32;

struct SomeError;

// usize is a u16 or u32, which always fits in a u32
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
fn my_thing(a: usize) -> Result<u32, SomeError> {
    Ok(a as u32)
}

// usize is a u64, which might be too big
#[cfg(target_pointer_width = "64")]
fn my_thing(a: usize) -> Result<u32, SomeError> {
    if a > u32::MAX as usize {
        Err(SomeError)
    } else {
        Ok(a as u32)
    }
}

I would be surprised if Rust doesn't have some idiomatic way to do this conversion. usize and u32 are two basic types, after all.

The problem is that usize isn't really a "basic" type because it changes size depending on the target platform. Getting this correct, performant and ergonomic is not easy.

like image 103
Shepmaster Avatar answered Sep 22 '22 06:09

Shepmaster