0

I have this function created in rust that will take an input like "0x152" and return its integer value. For example, "123" would be 123 as u32. This works in a std environment, but after testing on a MCU, I realized there are functional differences between chars in std and no_std rust, and the comparisions and casting I am doing do not work. How can I perform the same function??

pub fn bytes_to_number(s: &str) -> Result<u32, &'static str> {
    let mut result: u32 = 0;

    // Check if the input is hex or decimal
    let mut chars = s.chars();
    if let Some(c) = chars.next() {
        if c != '0' || chars.next() != Some('x') {
            if '0' <= c && c <= '9' {
                result += c as u32 - '0' as u32;
                for c in chars {
                    let digit= match c {
                        '0'..='9' => c as u32 - '0' as u32,
                        _ => return Err("Invalid decimal character"),
                    };
                    if result >= 429_496_720 {
                        return Err("Integer number too large!")
                    }
                    result = result * 10 + digit;
                    
                }
                return Ok(result)
            }
            return Err("Not a hex or decimal string")
        }
    }
    if chars.clone().count() > 8 {
        return Err("Integer number too large!")
    }
    for c in chars {
        let digit =  match c {
            '0'..='9' => c as u32 - '0' as u32,
            'a'..='f' => c as u32 - 'a' as u32 + 10,
            'A'..='F' => c as u32 - 'A' as u32 + 10,
            _ => return Err("Invalid hex character"),
        };
        result = result * 16 + digit;
    }
    Ok(result)
}

Input: 45, returns: Err(Invalid decimal character)
Input: 3, returns: Err(Not a hex or decimal string)

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Which specific lines are behaving differently? Compiling in `std` vs. `no_std` doesn't change how language features like `char` or casting work. It merely changes what standard library functions are available. – John Kugelman Feb 04 '23 at 19:16
  • By the way, your function already does weird stuff if the first digit is `"0"` but there's not an `x` after it (e.g. passing "045" results in `5`). – kmdreko Feb 04 '23 at 20:28

1 Answers1

2

Your function could best be written like so:

use core::num::ParseIntError;
use core::str::FromStr;

pub fn bytes_to_number(s: &str) -> Result<u32, ParseIntError> {
    if let Some(s) = s.strip_prefix("0x") {
        u32::from_str_radix(s, 16)
    } else {
        u32::from_str(s)
    }
}

This only uses functions available in a #![no_std] environment. To use it with &[u8] as well, you would first use core::str::from_utf8 to convert it to a &str.

kmdreko
  • 42,554
  • 6
  • 57
  • 106