Allow any kind of overflow in rust with integers

Hi,

I'm working on a custom assembly emulator and I need to allow any kind of overflow. I don't care if I'm trying to fit the number 58271935 into a u8 variable or 0xFF in an i8. In the first case I expect that it takes the 8 least significant bits and use them, on the second one I expect to get a -1.

How can I do it? Nothing I could find was very useful.

Thanks!

Casting an integer with x as i8 will truncate the integer like that. To perform addition with overflow, use x.wrapping_add(y) or use types such as Wrapping<i8>.

1 Like

I tried the following, getting an overflow error:

let number_in_code: String = "ff".to_string();
let num: u8 = i8::from_str_radix(number_in_code, 16).unwrap() as u8;

I'm doing that because I need to be able to receive a "FFh" or a "-1" and map it to the number 0b11111111.

I'm going to read abbout the Wrapping data types.
Update: Wrapping::<i8>::from_str_radix(number_in_code, 16).unwrap() as u8 didn't works :c

When parsing a string, you must parse into an integer type that is large enough to hold the result without wrapping. You can cast it to the type you want after parsing.

Can we expect a zero cost for using wrapping_xxx() when building a release since, it's default the behavior (with flag register update) on x86 architectures ? I'm used to rely on this hardware wrapping (emulators too), and I'm a bit reluctant to add 'overhead' on this operation. Nevertheless, I understand that's its done to be explicit rather than implicit behavior, which is a good thing.

Yes, wrapping_xxx() will compile down to an add instruction.

I'm not sure that the Rust standard library has a built in way to do this. I think that essentially you want to parse either a u8 or an i8 and then cast to a u8. One way to do that is to try to parse one way then fallback to the other way:

use std::num::ParseIntError;

fn parse_u8(s: &str) -> Result<u8, ParseIntError> {
    match i8::from_str_radix(s, 16) {
        Ok(n) => Ok(n as u8),
        Err(_) => u8::from_str_radix(s, 16)
    }
}

Or test for a minus sign yourself:

use std::num::ParseIntError;

fn parse_u8(s: &str) -> Result<u8, ParseIntError> {
    match s.chars().next() {
        Some('-') => i8::from_str_radix(s, 16).map(|n| n as u8),
        _ => u8::from_str_radix(s, 16),
    }
}

Parsing into a larger type such as i32 and then casting should work fine. No need to try parsing as u8 and then i8.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.