From e31b45f2bfa8e24220fade5b0076edef8d4636e3 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 08:36:59 -0700 Subject: [PATCH 01/10] base 10 const compat --- src/lib.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 661596d..e9dc527 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,31 +124,38 @@ const DEC_LOOKUP: &[u8; 200] = b"0001020304050607080910111213141516171819\ 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; +macro_rules! copy_3_dec_lut_bytes { + ($to:ident,$to_index:expr,$lut_index:expr) => { + $to[($to_index as usize) % $to.len()] = DEC_LOOKUP[($lut_index as usize) % DEC_LOOKUP.len()]; + $to[($to_index as usize+1) % $to.len()] = DEC_LOOKUP[($lut_index as usize+1) % DEC_LOOKUP.len()]; + $to[($to_index as usize+2) % $to.len()] = DEC_LOOKUP[($lut_index as usize+2) % DEC_LOOKUP.len()]; + }; +} + macro_rules! base_10 { ($number:ident, $index:ident, $string:ident) => { // Decode four characters at the same time while $number > 9999 { let rem = ($number % 10000) as u16; let (frst, scnd) = ((rem / 100) * 2, (rem % 100) * 2); - $string[$index-3..$index-1].copy_from_slice(&DEC_LOOKUP[frst as usize..frst as usize+2]); - $string[$index-1..$index+1].copy_from_slice(&DEC_LOOKUP[scnd as usize..scnd as usize+2]); + copy_3_dec_lut_bytes!($string, $index-3, frst); + copy_3_dec_lut_bytes!($string, $index-1, scnd); $index = $index.wrapping_sub(4); $number /= 10000; } - if $number > 999 { let (frst, scnd) = (($number / 100) * 2, ($number % 100) * 2); - $string[$index-3..$index-1].copy_from_slice(&DEC_LOOKUP[frst as usize..frst as usize+2]); - $string[$index-1..$index+1].copy_from_slice(&DEC_LOOKUP[scnd as usize..scnd as usize+2]); + copy_3_dec_lut_bytes!($string, $index-3, frst); + copy_3_dec_lut_bytes!($string, $index-1, scnd); $index = $index.wrapping_sub(4); } else if $number > 99 { let section = ($number as u16 / 10) * 2; - $string[$index-2..$index].copy_from_slice(&DEC_LOOKUP[section as usize..section as usize+2]); + copy_3_dec_lut_bytes!($string, $index-2, section); $string[$index] = LOOKUP[($number % 10) as usize]; $index = $index.wrapping_sub(3); } else if $number > 9 { $number *= 2; - $string[$index-1..$index+1].copy_from_slice(&DEC_LOOKUP[$number as usize..$number as usize+2]); + copy_3_dec_lut_bytes!($string, $index-1, $number); $index = $index.wrapping_sub(2); } else { $string[$index] = LOOKUP[$number as usize]; From 224eb4d8ab8fee10ef4b7d65771507e6b72682d4 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 08:44:07 -0700 Subject: [PATCH 02/10] general case const compat --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e9dc527..44349fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,7 +184,7 @@ macro_rules! impl_unsized_numtoa_for { let mut index = string.len() - 1; if self == 0 { string[index] = b'0'; - return &string[index..]; + return string.split_at(index).1; } if base == 10 { @@ -199,7 +199,7 @@ macro_rules! impl_unsized_numtoa_for { } } - &string[index.wrapping_add(1)..] + string.split_at(index.wrapping_add(1)).1 } @@ -242,7 +242,7 @@ macro_rules! impl_sized_numtoa_for { }; } else if self == 0 { string[index] = b'0'; - return &string[index..]; + return string.split_at(index).1; } if base == 10 { @@ -262,7 +262,7 @@ macro_rules! impl_sized_numtoa_for { index = index.wrapping_sub(1); } - &string[index.wrapping_add(1)..] + string.split_at(index.wrapping_add(1)).1 } From ced1ac047d1e852b15e3af624c5a35e4fe5ada55 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 08:45:16 -0700 Subject: [PATCH 03/10] rename macro 'sized' -> 'signed' --- src/lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 44349fc..a1b5b5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -164,7 +164,7 @@ macro_rules! base_10 { } } -macro_rules! impl_unsized_numtoa_for { +macro_rules! impl_unsigned_numtoa_for { ($t:ty) => { impl NumToA for $t { fn numtoa(mut self, base: $t, string: &mut [u8]) -> &[u8] { @@ -210,7 +210,7 @@ macro_rules! impl_unsized_numtoa_for { } } -macro_rules! impl_sized_numtoa_for { +macro_rules! impl_signed_numtoa_for { ($t:ty) => { impl NumToA for $t { fn numtoa(mut self, base: $t, string: &mut [u8]) -> &[u8] { @@ -273,16 +273,16 @@ macro_rules! impl_sized_numtoa_for { } } -impl_sized_numtoa_for!(i16); -impl_sized_numtoa_for!(i32); -impl_sized_numtoa_for!(i64); -impl_sized_numtoa_for!(i128); -impl_sized_numtoa_for!(isize); -impl_unsized_numtoa_for!(u16); -impl_unsized_numtoa_for!(u32); -impl_unsized_numtoa_for!(u64); -impl_unsized_numtoa_for!(u128); -impl_unsized_numtoa_for!(usize); +impl_signed_numtoa_for!(i16); +impl_signed_numtoa_for!(i32); +impl_signed_numtoa_for!(i64); +impl_signed_numtoa_for!(i128); +impl_signed_numtoa_for!(isize); +impl_unsigned_numtoa_for!(u16); +impl_unsigned_numtoa_for!(u32); +impl_unsigned_numtoa_for!(u64); +impl_unsigned_numtoa_for!(u128); +impl_unsigned_numtoa_for!(usize); impl NumToA for i8 { fn numtoa(mut self, base: i8, string: &mut [u8]) -> &[u8] { From d832344b7165c3f17497e57154256681cf4271d9 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 08:51:06 -0700 Subject: [PATCH 04/10] support const context for unsigned types --- src/lib.rs | 102 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a1b5b5a..5c62536 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -165,58 +165,70 @@ macro_rules! base_10 { } macro_rules! impl_unsigned_numtoa_for { - ($t:ty) => { - impl NumToA for $t { - fn numtoa(mut self, base: $t, string: &mut [u8]) -> &[u8] { - // Check if the buffer is large enough and panic on debug builds if it isn't - if cfg!(debug_assertions) { - if base == 10 { - match size_of::<$t>() { - 2 => debug_assert!(string.len() >= 5, "u16 base 10 conversions require at least 5 bytes"), - 4 => debug_assert!(string.len() >= 10, "u32 base 10 conversions require at least 10 bytes"), - 8 => debug_assert!(string.len() >= 20, "u64 base 10 conversions require at least 20 bytes"), - 16 => debug_assert!(string.len() >= 39, "u128 base 10 conversions require at least 39 bytes"), - _ => unreachable!() - } + ( + $type_name:ty, + $core_function_name:ident, + $str_function_name:ident + ) => { + + pub const fn $core_function_name(mut num: $type_name, base: $type_name, string: &mut [u8]) -> &[u8] { + // Check if the buffer is large enough and panic on debug builds if it isn't + if cfg!(debug_assertions) { + if base == 10 { + match size_of::<$type_name>() { + 2 => debug_assert!(string.len() >= 5, "u16 base 10 conversions require at least 5 bytes"), + 4 => debug_assert!(string.len() >= 10, "u32 base 10 conversions require at least 10 bytes"), + 8 => debug_assert!(string.len() >= 20, "u64 base 10 conversions require at least 20 bytes"), + 16 => debug_assert!(string.len() >= 39, "u128 base 10 conversions require at least 39 bytes"), + _ => unreachable!() } } + } - let mut index = string.len() - 1; - if self == 0 { - string[index] = b'0'; - return string.split_at(index).1; - } + let mut index = string.len() - 1; + if num == 0 { + string[index] = b'0'; + return string.split_at(index).1; + } - if base == 10 { - // Convert using optimized base 10 algorithm - base_10!(self, index, string); - } else { - while self != 0 { - let rem = self % base; - string[index] = LOOKUP[rem as usize]; - index = index.wrapping_sub(1); - self /= base; - } + if base == 10 { + // Convert using optimized base 10 algorithm + base_10!(num, index, string); + } else { + while num != 0 { + let rem = num % base; + string[index] = LOOKUP[rem as usize]; + index = index.wrapping_sub(1); + num /= base; } - - string.split_at(index.wrapping_add(1)).1 } - - fn numtoa_str(self, base: $t, buf: &mut [u8]) -> &str { - unsafe { str::from_utf8_unchecked(self.numtoa(base, buf)) } + string.split_at(index.wrapping_add(1)).1 + } + + pub const fn $str_function_name(mut num: $type_name, base: $type_name, string: &mut [u8]) -> &str { + unsafe { core::str::from_utf8_unchecked($core_function_name(num, base, string)) } + } + + impl NumToA for $type_name { + fn numtoa(self, base: $type_name, string: &mut [u8]) -> &[u8] { + $core_function_name(self, base, string) + } + fn numtoa_str(self, base: $type_name, buf: &mut [u8]) -> &str { + $str_function_name(self, base, buf) } } + } } macro_rules! impl_signed_numtoa_for { - ($t:ty) => { - impl NumToA for $t { - fn numtoa(mut self, base: $t, string: &mut [u8]) -> &[u8] { + ($type_name:ty) => { + impl NumToA for $type_name { + fn numtoa(mut self, base: $type_name, string: &mut [u8]) -> &[u8] { if cfg!(debug_assertions) { if base == 10 { - match size_of::<$t>() { + match size_of::<$type_name>() { 2 => debug_assert!(string.len() >= 6, "i16 base 10 conversions require at least 6 bytes"), 4 => debug_assert!(string.len() >= 11, "i32 base 10 conversions require at least 11 bytes"), 8 => debug_assert!(string.len() >= 19, "i64 base 10 conversions require at least 19 bytes"), @@ -234,10 +246,10 @@ macro_rules! impl_signed_numtoa_for { self = match self.checked_abs() { Some(value) => value, None => { - let value = <$t>::max_value(); + let value = <$type_name>::max_value(); string[index] = LOOKUP[((value % base + 1) % base) as usize]; index -= 1; - value / base + ((value % base == base - 1) as $t) + value / base + ((value % base == base - 1) as $type_name) } }; } else if self == 0 { @@ -266,7 +278,7 @@ macro_rules! impl_signed_numtoa_for { } - fn numtoa_str(self, base: $t, buf: &mut [u8]) -> &str { + fn numtoa_str(self, base: $type_name, buf: &mut [u8]) -> &str { unsafe { str::from_utf8_unchecked(self.numtoa(base, buf)) } } } @@ -278,11 +290,11 @@ impl_signed_numtoa_for!(i32); impl_signed_numtoa_for!(i64); impl_signed_numtoa_for!(i128); impl_signed_numtoa_for!(isize); -impl_unsigned_numtoa_for!(u16); -impl_unsigned_numtoa_for!(u32); -impl_unsigned_numtoa_for!(u64); -impl_unsigned_numtoa_for!(u128); -impl_unsigned_numtoa_for!(usize); +impl_unsigned_numtoa_for!(u16,numtoa_u16,numtoa_str_u16); +impl_unsigned_numtoa_for!(u32,numtoa_u32,numtoa_str_u32); +impl_unsigned_numtoa_for!(u64,numtoa_u64,numtoa_str_u64); +impl_unsigned_numtoa_for!(u128,numtoa_u128,numtoa_str_u128); +impl_unsigned_numtoa_for!(usize,numtoa_usize,numtoa_str_usize); impl NumToA for i8 { fn numtoa(mut self, base: i8, string: &mut [u8]) -> &[u8] { From cfdd49feda6a564d9d7b77240cc5ce1d99353009 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 08:53:23 -0700 Subject: [PATCH 05/10] support const context for signed types --- src/lib.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5c62536..a007495 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,7 +206,7 @@ macro_rules! impl_unsigned_numtoa_for { string.split_at(index.wrapping_add(1)).1 } - pub const fn $str_function_name(mut num: $type_name, base: $type_name, string: &mut [u8]) -> &str { + pub const fn $str_function_name(num: $type_name, base: $type_name, string: &mut [u8]) -> &str { unsafe { core::str::from_utf8_unchecked($core_function_name(num, base, string)) } } @@ -223,7 +223,11 @@ macro_rules! impl_unsigned_numtoa_for { } macro_rules! impl_signed_numtoa_for { - ($type_name:ty) => { + ( + $type_name:ty, + $core_function_name:ident, + $str_function_name:ident + ) => { impl NumToA for $type_name { fn numtoa(mut self, base: $type_name, string: &mut [u8]) -> &[u8] { if cfg!(debug_assertions) { @@ -285,11 +289,11 @@ macro_rules! impl_signed_numtoa_for { } } -impl_signed_numtoa_for!(i16); -impl_signed_numtoa_for!(i32); -impl_signed_numtoa_for!(i64); -impl_signed_numtoa_for!(i128); -impl_signed_numtoa_for!(isize); +impl_signed_numtoa_for!(i16,numtoa_i16,numtoa_str_i16); +impl_signed_numtoa_for!(i32,numtoa_i32,numtoa_str_i32); +impl_signed_numtoa_for!(i64,numtoa_i64,numtoa_str_i64); +impl_signed_numtoa_for!(i128,numtoa_i128,numtoa_str_i128); +impl_signed_numtoa_for!(isize,numtoa_isize,numtoa_str_isize); impl_unsigned_numtoa_for!(u16,numtoa_u16,numtoa_str_u16); impl_unsigned_numtoa_for!(u32,numtoa_u32,numtoa_str_u32); impl_unsigned_numtoa_for!(u64,numtoa_u64,numtoa_str_u64); From 49229f790b7621d06e2c7347f881f2c981c29e21 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 09:02:52 -0700 Subject: [PATCH 06/10] support const context for i8 --- src/lib.rs | 108 ++++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a007495..bd6db86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -300,66 +300,74 @@ impl_unsigned_numtoa_for!(u64,numtoa_u64,numtoa_str_u64); impl_unsigned_numtoa_for!(u128,numtoa_u128,numtoa_str_u128); impl_unsigned_numtoa_for!(usize,numtoa_usize,numtoa_str_usize); -impl NumToA for i8 { - fn numtoa(mut self, base: i8, string: &mut [u8]) -> &[u8] { - if cfg!(debug_assertions) { - if base == 10 { - debug_assert!(string.len() >= 4, "i8 conversions need at least 4 bytes"); - } - } - - let mut index = string.len() - 1; - let mut is_negative = false; - - if self < 0 { - is_negative = true; - self = match self.checked_abs() { - Some(value) => value, - None => { - let value = ::max_value(); - string[index] = LOOKUP[((value % base + 1) % base) as usize]; - index -= 1; - value / base + ((value % base == base - 1) as i8) - } - }; - } else if self == 0 { - string[index] = b'0'; - return &string[index..]; +pub const fn numtoa_i8(mut num: i8, base: i8, string: &mut [u8]) -> &[u8] { + if cfg!(debug_assertions) { + if base == 10 { + debug_assert!(string.len() >= 4, "i8 conversions need at least 4 bytes"); } + } - if base == 10 { - if self > 99 { - let section = (self / 10) * 2; - string[index-2..index].copy_from_slice(&DEC_LOOKUP[section as usize..section as usize+2]); - string[index] = LOOKUP[(self % 10) as usize]; - index = index.wrapping_sub(3); - } else if self > 9 { - let idx = self as usize * 2; - string[index-1..index+1].copy_from_slice(&DEC_LOOKUP[idx..idx+2]); - index = index.wrapping_sub(2); - } else { - string[index] = LOOKUP[self as usize]; - index = index.wrapping_sub(1); + let mut index = string.len() - 1; + let mut is_negative = false; + + if num < 0 { + is_negative = true; + num = match num.checked_abs() { + Some(value) => value, + None => { + let value = ::max_value(); + string[index] = LOOKUP[((value % base + 1) % base) as usize]; + index -= 1; + value / base + ((value % base == base - 1) as i8) } - } else { - while self != 0 { - let rem = self % base; - string[index] = LOOKUP[rem as usize]; - index = index.wrapping_sub(1); - self /= base; - } - } + }; + } else if num == 0 { + string[index] = b'0'; + return string.split_at(index).1; + } - if is_negative { - string[index] = b'-'; + if base == 10 { + if num > 99 { + let section = (num / 10) * 2; + copy_3_dec_lut_bytes!(string, index-2, section); + string[index] = LOOKUP[(num % 10) as usize]; + index = index.wrapping_sub(3); + } else if num > 9 { + let idx = num as usize * 2; + copy_3_dec_lut_bytes!(string, index-1, idx); + index = index.wrapping_sub(2); + } else { + string[index] = LOOKUP[num as usize]; + index = index.wrapping_sub(1); + } + } else { + while num != 0 { + let rem = num % base; + string[index] = LOOKUP[rem as usize]; index = index.wrapping_sub(1); + num /= base; } + } - &string[index.wrapping_add(1)..] + if is_negative { + string[index] = b'-'; + index = index.wrapping_sub(1); + } + + string.split_at(index.wrapping_add(1)).1 +} + +pub const fn numtoa_i8_str(num: i8, base: i8, string: &mut [u8]) -> &str { + unsafe { str::from_utf8_unchecked(numtoa_i8(num, base, string)) } +} + +impl NumToA for i8 { + fn numtoa(self, base: i8, string: &mut [u8]) -> &[u8] { + numtoa_i8(self, base, string) } fn numtoa_str(self, base: Self, buf: &mut [u8]) -> &str { - unsafe { str::from_utf8_unchecked(self.numtoa(base, buf)) } + numtoa_i8_str(self, base, buf) } } From d6a60c3c8dc8aa8da2d900e1ab17e16867b4f765 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 09:08:45 -0700 Subject: [PATCH 07/10] support const context for u8 --- src/lib.rs | 74 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bd6db86..11a4232 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -371,48 +371,56 @@ impl NumToA for i8 { } } -impl NumToA for u8 { - fn numtoa(mut self, base: u8, string: &mut [u8]) -> &[u8] { - if cfg!(debug_assertions) { - if base == 10 { - debug_assert!(string.len() >= 3, "u8 conversions need at least 3 bytes"); - } +pub const fn numtoa_u8(mut num: u8, base: u8, string: &mut [u8]) -> &[u8] { + if cfg!(debug_assertions) { + if base == 10 { + debug_assert!(string.len() >= 3, "u8 conversions need at least 3 bytes"); } + } - let mut index = string.len() - 1; - if self == 0 { - string[index] = b'0'; - return &string[index..]; - } + let mut index = string.len() - 1; + if num == 0 { + string[index] = b'0'; + return string.split_at(index).1; + } - if base == 10 { - if self > 99 { - let section = (self / 10) * 2; - string[index-2..index].copy_from_slice(&DEC_LOOKUP[section as usize..section as usize+2]); - string[index] = LOOKUP[(self % 10) as usize]; - index = index.wrapping_sub(3); - } else if self > 9 { - self *= 2; - string[index-1..index+1].copy_from_slice(&DEC_LOOKUP[self as usize..self as usize+2]); - index = index.wrapping_sub(2); - } else { - string[index] = LOOKUP[self as usize]; - index = index.wrapping_sub(1); - } + if base == 10 { + if num > 99 { + let section = (num / 10) * 2; + copy_3_dec_lut_bytes!(string, index-2, section); + string[index] = LOOKUP[(num % 10) as usize]; + index = index.wrapping_sub(3); + } else if num > 9 { + num *= 2; + copy_3_dec_lut_bytes!(string, index-1, num); + index = index.wrapping_sub(2); } else { - while self != 0 { - let rem = self % base; - string[index] = LOOKUP[rem as usize]; - index = index.wrapping_sub(1); - self /= base; - } + string[index] = LOOKUP[num as usize]; + index = index.wrapping_sub(1); } + } else { + while num != 0 { + let rem = num % base; + string[index] = LOOKUP[rem as usize]; + index = index.wrapping_sub(1); + num /= base; + } + } - &string[index.wrapping_add(1)..] + string.split_at(1).1 +} + +pub const fn numtoa_u8_str(num: u8, base: u8, string: &mut [u8]) -> &str { + unsafe { str::from_utf8_unchecked(numtoa_u8(num, base, string)) } +} + +impl NumToA for u8 { + fn numtoa(self, base: u8, string: &mut [u8]) -> &[u8] { + numtoa_u8(self, base, string) } fn numtoa_str(self, base: Self, buf: &mut [u8]) -> &str { - unsafe { str::from_utf8_unchecked(self.numtoa(base, buf)) } + numtoa_u8_str(self, base, buf) } } From 2ffe3fe506992974cf6e3caa026ed022745744a8 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 09:29:41 -0700 Subject: [PATCH 08/10] naming nit --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 11a4232..82032fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -357,7 +357,7 @@ pub const fn numtoa_i8(mut num: i8, base: i8, string: &mut [u8]) -> &[u8] { string.split_at(index.wrapping_add(1)).1 } -pub const fn numtoa_i8_str(num: i8, base: i8, string: &mut [u8]) -> &str { +pub const fn numtoa_str_i8(num: i8, base: i8, string: &mut [u8]) -> &str { unsafe { str::from_utf8_unchecked(numtoa_i8(num, base, string)) } } @@ -367,7 +367,7 @@ impl NumToA for i8 { } fn numtoa_str(self, base: Self, buf: &mut [u8]) -> &str { - numtoa_i8_str(self, base, buf) + numtoa_str_i8(self, base, buf) } } @@ -410,7 +410,7 @@ pub const fn numtoa_u8(mut num: u8, base: u8, string: &mut [u8]) -> &[u8] { string.split_at(1).1 } -pub const fn numtoa_u8_str(num: u8, base: u8, string: &mut [u8]) -> &str { +pub const fn numtoa_str_u8(num: u8, base: u8, string: &mut [u8]) -> &str { unsafe { str::from_utf8_unchecked(numtoa_u8(num, base, string)) } } @@ -420,7 +420,7 @@ impl NumToA for u8 { } fn numtoa_str(self, base: Self, buf: &mut [u8]) -> &str { - numtoa_u8_str(self, base, buf) + numtoa_str_u8(self, base, buf) } } From 4a8cf45389ff71e6f318e9f2726d7ee31a4ce4fe Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 10:18:39 -0700 Subject: [PATCH 09/10] oops --- src/lib.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 82032fd..1e20544 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,11 +124,10 @@ const DEC_LOOKUP: &[u8; 200] = b"0001020304050607080910111213141516171819\ 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; -macro_rules! copy_3_dec_lut_bytes { +macro_rules! copy_2_dec_lut_bytes { ($to:ident,$to_index:expr,$lut_index:expr) => { - $to[($to_index as usize) % $to.len()] = DEC_LOOKUP[($lut_index as usize) % DEC_LOOKUP.len()]; - $to[($to_index as usize+1) % $to.len()] = DEC_LOOKUP[($lut_index as usize+1) % DEC_LOOKUP.len()]; - $to[($to_index as usize+2) % $to.len()] = DEC_LOOKUP[($lut_index as usize+2) % DEC_LOOKUP.len()]; + $to[$to_index as usize] = DEC_LOOKUP[$lut_index as usize]; + $to[$to_index as usize+1] = DEC_LOOKUP[$lut_index as usize+1]; }; } @@ -138,24 +137,24 @@ macro_rules! base_10 { while $number > 9999 { let rem = ($number % 10000) as u16; let (frst, scnd) = ((rem / 100) * 2, (rem % 100) * 2); - copy_3_dec_lut_bytes!($string, $index-3, frst); - copy_3_dec_lut_bytes!($string, $index-1, scnd); + copy_2_dec_lut_bytes!($string, $index-3, frst); + copy_2_dec_lut_bytes!($string, $index-1, scnd); $index = $index.wrapping_sub(4); $number /= 10000; } if $number > 999 { let (frst, scnd) = (($number / 100) * 2, ($number % 100) * 2); - copy_3_dec_lut_bytes!($string, $index-3, frst); - copy_3_dec_lut_bytes!($string, $index-1, scnd); + copy_2_dec_lut_bytes!($string, $index-3, frst); + copy_2_dec_lut_bytes!($string, $index-1, scnd); $index = $index.wrapping_sub(4); } else if $number > 99 { let section = ($number as u16 / 10) * 2; - copy_3_dec_lut_bytes!($string, $index-2, section); + copy_2_dec_lut_bytes!($string, $index-2, section); $string[$index] = LOOKUP[($number % 10) as usize]; $index = $index.wrapping_sub(3); } else if $number > 9 { $number *= 2; - copy_3_dec_lut_bytes!($string, $index-1, $number); + copy_2_dec_lut_bytes!($string, $index-1, $number); $index = $index.wrapping_sub(2); } else { $string[$index] = LOOKUP[$number as usize]; @@ -329,12 +328,12 @@ pub const fn numtoa_i8(mut num: i8, base: i8, string: &mut [u8]) -> &[u8] { if base == 10 { if num > 99 { let section = (num / 10) * 2; - copy_3_dec_lut_bytes!(string, index-2, section); + copy_2_dec_lut_bytes!(string, index-2, section); string[index] = LOOKUP[(num % 10) as usize]; index = index.wrapping_sub(3); } else if num > 9 { let idx = num as usize * 2; - copy_3_dec_lut_bytes!(string, index-1, idx); + copy_2_dec_lut_bytes!(string, index-1, idx); index = index.wrapping_sub(2); } else { string[index] = LOOKUP[num as usize]; @@ -387,12 +386,12 @@ pub const fn numtoa_u8(mut num: u8, base: u8, string: &mut [u8]) -> &[u8] { if base == 10 { if num > 99 { let section = (num / 10) * 2; - copy_3_dec_lut_bytes!(string, index-2, section); + copy_2_dec_lut_bytes!(string, index-2, section); string[index] = LOOKUP[(num % 10) as usize]; index = index.wrapping_sub(3); } else if num > 9 { num *= 2; - copy_3_dec_lut_bytes!(string, index-1, num); + copy_2_dec_lut_bytes!(string, index-1, num); index = index.wrapping_sub(2); } else { string[index] = LOOKUP[num as usize]; From 743ab9bfc0d5e176ac8a498dabdab0a7c9568706 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Sun, 1 Jun 2025 10:59:56 -0700 Subject: [PATCH 10/10] function naming format --- README.md | 4 ++++ src/lib.rs | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 3a85623..d91e38e 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ In addition to supporting the standard base 10 conversion, this implementation a your choice. Therefore, if you want a binary representation, set the base to 2. If you want hexadecimal, set the base to 16. +## Supports Const Contexts + +This library's API includes `const` functions that can be used to convert numbers into their string representation at compile time, allowing developers to build smaller & faster executables. + ## `&str` Example ```rust diff --git a/src/lib.rs b/src/lib.rs index 1e20544..3214fc6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -288,16 +288,16 @@ macro_rules! impl_signed_numtoa_for { } } -impl_signed_numtoa_for!(i16,numtoa_i16,numtoa_str_i16); -impl_signed_numtoa_for!(i32,numtoa_i32,numtoa_str_i32); -impl_signed_numtoa_for!(i64,numtoa_i64,numtoa_str_i64); -impl_signed_numtoa_for!(i128,numtoa_i128,numtoa_str_i128); -impl_signed_numtoa_for!(isize,numtoa_isize,numtoa_str_isize); -impl_unsigned_numtoa_for!(u16,numtoa_u16,numtoa_str_u16); -impl_unsigned_numtoa_for!(u32,numtoa_u32,numtoa_str_u32); -impl_unsigned_numtoa_for!(u64,numtoa_u64,numtoa_str_u64); -impl_unsigned_numtoa_for!(u128,numtoa_u128,numtoa_str_u128); -impl_unsigned_numtoa_for!(usize,numtoa_usize,numtoa_str_usize); +impl_signed_numtoa_for!(i16,numtoa_i16,numtoa_i16_str); +impl_signed_numtoa_for!(i32,numtoa_i32,numtoa_i32_str); +impl_signed_numtoa_for!(i64,numtoa_i64,numtoa_i64_str); +impl_signed_numtoa_for!(i128,numtoa_i128,numtoa_i128_str); +impl_signed_numtoa_for!(isize,numtoa_isize,numtoa_isize_str); +impl_unsigned_numtoa_for!(u16,numtoa_u16,numtoa_u16_str); +impl_unsigned_numtoa_for!(u32,numtoa_u32,numtoa_u32_str); +impl_unsigned_numtoa_for!(u64,numtoa_u64,numtoa_u64_str); +impl_unsigned_numtoa_for!(u128,numtoa_u128,numtoa_u128_str); +impl_unsigned_numtoa_for!(usize,numtoa_usize,numtoa_usize_str); pub const fn numtoa_i8(mut num: i8, base: i8, string: &mut [u8]) -> &[u8] { if cfg!(debug_assertions) { @@ -356,7 +356,7 @@ pub const fn numtoa_i8(mut num: i8, base: i8, string: &mut [u8]) -> &[u8] { string.split_at(index.wrapping_add(1)).1 } -pub const fn numtoa_str_i8(num: i8, base: i8, string: &mut [u8]) -> &str { +pub const fn numtoa_i8_str(num: i8, base: i8, string: &mut [u8]) -> &str { unsafe { str::from_utf8_unchecked(numtoa_i8(num, base, string)) } } @@ -366,7 +366,7 @@ impl NumToA for i8 { } fn numtoa_str(self, base: Self, buf: &mut [u8]) -> &str { - numtoa_str_i8(self, base, buf) + numtoa_i8_str(self, base, buf) } } @@ -409,7 +409,7 @@ pub const fn numtoa_u8(mut num: u8, base: u8, string: &mut [u8]) -> &[u8] { string.split_at(1).1 } -pub const fn numtoa_str_u8(num: u8, base: u8, string: &mut [u8]) -> &str { +pub const fn numtoa_u8_str(num: u8, base: u8, string: &mut [u8]) -> &str { unsafe { str::from_utf8_unchecked(numtoa_u8(num, base, string)) } } @@ -419,7 +419,7 @@ impl NumToA for u8 { } fn numtoa_str(self, base: Self, buf: &mut [u8]) -> &str { - numtoa_str_u8(self, base, buf) + numtoa_u8_str(self, base, buf) } }