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>
foru32
is dependent on havingFrom<usize>
foru32
, 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
andu32
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.