155 lines
4.6 KiB
Rust
155 lines
4.6 KiB
Rust
//! Implements the algorithm in terms of the lexical API.
|
|
|
|
#![doc(hidden)]
|
|
|
|
use lexical_util::format::{NumberFormat, STANDARD};
|
|
use lexical_util::num::SignedInteger;
|
|
use lexical_util::{to_lexical, to_lexical_with_options};
|
|
|
|
use crate::options::Options;
|
|
use crate::write::WriteInteger;
|
|
|
|
// UNSIGNED
|
|
|
|
/// Callback for unsigned integer formatter.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Safe as long as the buffer can hold `FORMATTED_SIZE` elements
|
|
/// (or `FORMATTED_SIZE_DECIMAL` for decimal).
|
|
#[cfg_attr(not(feature = "compact"), inline(always))]
|
|
fn unsigned<T, const FORMAT: u128>(value: T, buffer: &mut [u8]) -> usize
|
|
where
|
|
T: WriteInteger,
|
|
{
|
|
let format = NumberFormat::<FORMAT> {};
|
|
if cfg!(feature = "format") && format.required_mantissa_sign() {
|
|
buffer[0] = b'+';
|
|
let buffer = &mut buffer[1..];
|
|
value.write_mantissa::<FORMAT>(buffer) + 1
|
|
} else {
|
|
value.write_mantissa::<FORMAT>(buffer)
|
|
}
|
|
}
|
|
|
|
// SIGNED
|
|
|
|
/// Callback for signed integer formatter.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Safe as long as the buffer can hold `FORMATTED_SIZE` elements
|
|
/// (or `FORMATTED_SIZE_DECIMAL` for decimal).
|
|
#[cfg_attr(not(feature = "compact"), inline(always))]
|
|
fn signed<Signed, Unsigned, const FORMAT: u128>(value: Signed, buffer: &mut [u8]) -> usize
|
|
where
|
|
Signed: SignedInteger,
|
|
Unsigned: WriteInteger,
|
|
{
|
|
let format = NumberFormat::<FORMAT> {};
|
|
if value < Signed::ZERO {
|
|
// Need to cast the value to the same size as unsigned type, since if
|
|
// the value is **exactly** `Narrow::MIN`, and it it is then cast
|
|
// as the wrapping negative as the unsigned value, a wider type
|
|
// will have a very different value.
|
|
let unsigned = Unsigned::as_cast(value.wrapping_neg());
|
|
buffer[0] = b'-';
|
|
let buffer = &mut buffer[1..];
|
|
unsigned.write_mantissa_signed::<FORMAT>(buffer) + 1
|
|
} else if cfg!(feature = "format") && format.required_mantissa_sign() {
|
|
let unsigned = Unsigned::as_cast(value);
|
|
buffer[0] = b'+';
|
|
let buffer = &mut buffer[1..];
|
|
unsigned.write_mantissa_signed::<FORMAT>(buffer) + 1
|
|
} else {
|
|
let unsigned = Unsigned::as_cast(value);
|
|
unsigned.write_mantissa_signed::<FORMAT>(buffer)
|
|
}
|
|
}
|
|
|
|
// API
|
|
|
|
// Implement `ToLexical` for numeric type.
|
|
macro_rules! unsigned_to_lexical {
|
|
($($t:tt)*) => ($(
|
|
impl ToLexical for $t {
|
|
#[cfg_attr(not(feature = "compact"), inline)]
|
|
fn to_lexical(self, bytes: &mut [u8])
|
|
-> &mut [u8]
|
|
{
|
|
let len = unsigned::<$t, { STANDARD }>(self, bytes);
|
|
&mut bytes[..len]
|
|
}
|
|
}
|
|
|
|
impl ToLexicalWithOptions for $t {
|
|
type Options = Options;
|
|
|
|
#[cfg_attr(not(feature = "compact"), inline)]
|
|
fn to_lexical_with_options<'a, const FORMAT: u128>(
|
|
self,
|
|
bytes: &'a mut [u8],
|
|
options: &Self::Options,
|
|
) -> &'a mut [u8]
|
|
{
|
|
_ = options;
|
|
assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
|
|
let len = unsigned::<$t, FORMAT>(self, bytes);
|
|
&mut bytes[..len]
|
|
}
|
|
}
|
|
)*)
|
|
}
|
|
|
|
to_lexical!("lexical_write_integer", 1234, u64);
|
|
to_lexical_with_options!("lexical_write_integer", 1234, u64, Options);
|
|
unsigned_to_lexical! { u8 u16 u32 u64 u128 usize }
|
|
|
|
// Implement `ToLexical` for numeric type.
|
|
macro_rules! signed_to_lexical {
|
|
($($signed:tt $unsigned:tt ; )*) => ($(
|
|
impl ToLexical for $signed {
|
|
#[cfg_attr(not(feature = "compact"), inline)]
|
|
fn to_lexical(self, bytes: &mut [u8])
|
|
-> &mut [u8]
|
|
{
|
|
let len = signed::<$signed, $unsigned, { STANDARD }>(self, bytes);
|
|
&mut bytes[..len]
|
|
}
|
|
}
|
|
|
|
impl ToLexicalWithOptions for $signed {
|
|
type Options = Options;
|
|
#[cfg_attr(not(feature = "compact"), inline)]
|
|
fn to_lexical_with_options<'a, const FORMAT: u128>(
|
|
self,
|
|
bytes: &'a mut [u8],
|
|
options: &Self::Options,
|
|
) -> &'a mut [u8]
|
|
{
|
|
_ = options;
|
|
assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
|
|
let len = signed::<$signed, $unsigned, FORMAT>(self, bytes);
|
|
&mut bytes[..len]
|
|
}
|
|
}
|
|
)*)
|
|
}
|
|
|
|
signed_to_lexical! {
|
|
i8 u8 ;
|
|
i16 u16 ;
|
|
i32 u32 ;
|
|
i64 u64 ;
|
|
i128 u128 ;
|
|
}
|
|
|
|
#[cfg(target_pointer_width = "16")]
|
|
signed_to_lexical! { isize u16 ; }
|
|
|
|
#[cfg(target_pointer_width = "32")]
|
|
signed_to_lexical! { isize u32 ; }
|
|
|
|
#[cfg(target_pointer_width = "64")]
|
|
signed_to_lexical! { isize u64 ; }
|