Skip to content

support compile-time number conversions #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 1, 2025
Merged

Conversation

master-hax
Copy link
Contributor

@master-hax master-hax commented Jun 1, 2025

background

the NumToA trait is convenient, but currently cannot be used in const contexts

we cannot define const functions on the existing NumToA trait (for now), so instead, we can define const library functions. this change will allow numtoa to convert numbers into strings 100% at compile time!

the PR contains mostly simple refactors to move the core logic into const functions of the format numtoa_u16, numtoa_str_u16, etc. and is fully backwards compatible, with the following notable changes:

  1. slicing doesn't work in const contexts, so copy_from_slice was replaced with a new macro copy_2_dec_lut_bytes
  2. slicing doesn't work in const contexts, so &string[x..] was replaced with string.split_at(x).1
  3. macros were renamed from "sized/unsized" to "signed/unsigned" (i think this was a typo)

here is a usage example of the new const functions:

extern crate numtoa;

use numtoa::{numtoa_u16, NumToA};

const NUMBER: u16 = 12345;
const BUFFER_AND_LEN: ([u8; 20], usize) = {
    let mut buffer = [0_u8; 20];
    // our new function! 12345.numtoa() is not const so cannot be used here
    let n = numtoa_u16(NUMBER, 10, &mut buffer).len();
    (buffer, n)
};
const STRING: &str = unsafe { core::str::from_utf8_unchecked(BUFFER_AND_LEN.0.split_at(BUFFER_AND_LEN.0.len() - BUFFER_AND_LEN.1).1) };

fn main() {
    println!("hello world: {}", STRING);
}

the number 12345 is converted to ascii form purely at compile time. if we inspect the binary, we can see that numtoa code is not present in the final binary. using the strings tool additionally shows that the decimal lookup table is not present, whereas it is easily noticeable in a binary that was compiled with e.g. println!("hello world: {}", 12345.numtoa_str(10, &mut [0_u8; 20])); making the code much more efficient.

the boilerplate code is a bit unfortunate & unwieldy but i have a future PR that will make compile-time conversion much easier & more ergonomic as a one-liner.

@master-hax master-hax changed the title const context support support compile-time number conversions Jun 1, 2025
@master-hax master-hax changed the title support compile-time number conversions [WIP] support compile-time number conversions Jun 1, 2025
@master-hax master-hax changed the title [WIP] support compile-time number conversions support compile-time number conversions Jun 1, 2025
@master-hax
Copy link
Contributor Author

cc @mmstick when you get a chance

@mmstick mmstick merged commit 3c82d9d into mmstick:master Jun 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants