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.
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>.
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.
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),
}
}