How to convert a &str or &[u8] like "0x124" to its numerical representation in no_std rust?

201 Views Asked by At

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)

1

There are 1 best solutions below

0
On

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.