use crate::{
formatting::{FormattingFlags, NumberFormatting, StartAndArray, FOR_ESCAPING},
pargument::Integer,
};
use core::ops::Range;
#[cfg(test)]
mod tests;
#[cfg_attr(feature = "fmt", doc = "```rust")]
#[cfg_attr(not(feature = "fmt"), doc = "```ignore")]
#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "fmt")))]
#[derive(Copy, Clone)]
pub struct PWrapper<T>(pub T);
impl<'a, T> PWrapper<&'a [T]> {
#[inline(always)]
pub const fn slice(x: &'a [T]) -> Self {
Self { 0: x }
}
}
macro_rules! compute_hex_count {
($bits:expr, $int:expr, $with_0x:expr) => {{
let with_0x = ($with_0x as usize) << 1;
let i = ($bits - $int.leading_zeros()) as usize;
(if i == 0 {
1
} else {
(i >> 2) + ((i & 3) != 0) as usize
}) + with_0x
}};
}
macro_rules! compute_binary_count {
($bits:expr, $int:expr, $with_0b:expr) => {{
let with_0b = ($with_0b as usize) << 1;
let i = ($bits - $int.leading_zeros()) as usize;
(if i == 0 { 1 } else { i }) + with_0b
}};
}
macro_rules! impl_number_of_digits {
(num number_of_digits;delegate $n:ident $len:ident)=>{
$n.number_of_digits()
};
(num number_of_digits;128 $n:ident $len:ident)=>{{
if $n >= 1_0000_0000_0000_0000{$n /= 1_0000_0000_0000_0000; $len += 16;}
impl_number_of_digits!(num number_of_digits;64 $n $len)
}};
(num number_of_digits;64 $n:ident $len:ident)=>{{
if $n >= 1_0000_0000_0000{$n /= 1_0000_0000_0000; $len += 12;}
impl_number_of_digits!(num number_of_digits;32 $n $len)
}};
(num number_of_digits;32 $n:ident $len:ident)=>{{
if $n >= 1_0000_0000{$n /= 100_000_000; $len += 8;}
impl_number_of_digits!(num number_of_digits;16 $n $len)
}};
(num number_of_digits;16 $n:ident $len:ident)=>{{
if $n >= 1_0000{$n /= 1_0000; $len += 4;}
impl_number_of_digits!(num number_of_digits;8 $n $len)
}};
(num number_of_digits;8 $n:ident $len:ident)=>{{
if $n >= 100{$n /= 100; $len += 2;}
if $n >= 10{ $len += 1;}
$len
}};
(@shared $This:ty, $bits:tt)=>{
impl PWrapper<$This> {
#[allow(unused_mut,unused_variables)]
#[doc(hidden)]
pub const fn compute_debug_len(self, fmt: FormattingFlags)-> usize {
match fmt.num_fmt() {
NumberFormatting::Decimal=>
self.compute_display_len(fmt),
NumberFormatting::Hexadecimal=>
compute_hex_count!($bits, self.0, fmt.is_alternate()),
NumberFormatting::Binary=>
compute_binary_count!($bits, self.0, fmt.is_alternate()),
}
}
pub const fn hexadecimal_len(self, fmt: FormattingFlags)-> usize {
compute_hex_count!($bits, self.0, fmt.is_alternate())
}
pub const fn binary_len(self, fmt: FormattingFlags)-> usize {
compute_binary_count!($bits, self.0, fmt.is_alternate())
}
}
};
(impl_either;
signed,
($This:ty, $Unsigned:ty),
$bits:tt $(,)?
)=>{
impl_number_of_digits!{@shared $This, $bits}
impl PWrapper<$This> {
pub const fn unsigned_abs(self) -> $Unsigned {
self.0.wrapping_abs() as $Unsigned
}
#[allow(unused_mut,unused_variables)]
#[doc(hidden)]
pub const fn compute_display_len(self, _: FormattingFlags)-> usize {
let mut n = self.0.wrapping_abs() as $Unsigned;
let mut len = 1 + (self.0 < 0) as usize;
impl_number_of_digits!(num number_of_digits;$bits n len)
}
}
};
(impl_either;
unsigned,
($This:ty, $Unsigned:ty),
$bits:tt $(,)?
)=>{
impl_number_of_digits!{@shared $This, $bits}
impl PWrapper<$This> {
pub const fn unsigned_abs(self) -> $Unsigned {
self.0
}
#[doc(hidden)]
pub const fn compute_display_len(self, _: FormattingFlags)-> usize {
let mut n = self.0;
let mut len = 1usize;
impl_number_of_digits!(num number_of_digits;$bits n len)
}
}
};
}
impl_number_of_digits! {impl_either; signed , (i8, u8), 8}
impl_number_of_digits! {impl_either; signed , (i16, u16), 16}
impl_number_of_digits! {impl_either; signed , (i32, u32), 32}
impl_number_of_digits! {impl_either; signed , (i64, u64), 64}
impl_number_of_digits! {impl_either; signed , (i128, u128), 128}
impl_number_of_digits! {impl_either; unsigned, (u8, u8), 8}
impl_number_of_digits! {impl_either; unsigned, (u16, u16), 16}
impl_number_of_digits! {impl_either; unsigned, (u32, u32), 32}
impl_number_of_digits! {impl_either; unsigned, (u64, u64), 64}
impl_number_of_digits! {impl_either; unsigned, (u128, u128), 128}
#[cfg(target_pointer_width = "16")]
type UWord = u16;
#[cfg(target_pointer_width = "32")]
type UWord = u32;
#[cfg(target_pointer_width = "64")]
type UWord = u64;
#[cfg(target_pointer_width = "128")]
type UWord = u128;
#[cfg(target_pointer_width = "16")]
type IWord = i16;
#[cfg(target_pointer_width = "32")]
type IWord = i32;
#[cfg(target_pointer_width = "64")]
type IWord = i64;
#[cfg(target_pointer_width = "128")]
type IWord = i128;
macro_rules! impl_for_xsize {
($XSize:ident, $XWord:ident) => {
impl PWrapper<$XSize> {
#[inline(always)]
pub const fn compute_display_len(self, fmt: FormattingFlags) -> usize {
PWrapper(self.0 as $XWord).compute_display_len(fmt)
}
#[inline(always)]
pub const fn compute_debug_len(self, fmt: FormattingFlags) -> usize {
PWrapper(self.0 as $XWord).compute_debug_len(fmt)
}
#[inline(always)]
pub const fn hexadecimal_len(self, fmt: FormattingFlags) -> usize {
PWrapper(self.0 as $XWord).hexadecimal_len(fmt)
}
#[inline(always)]
pub const fn binary_len(self, fmt: FormattingFlags) -> usize {
PWrapper(self.0 as $XWord).binary_len(fmt)
}
}
};
}
impl_for_xsize! {usize, UWord}
impl_for_xsize! {isize, IWord}
impl PWrapper<usize> {
pub const fn unsigned_abs(self) -> usize {
self.0
}
}
impl PWrapper<isize> {
pub const fn unsigned_abs(self) -> usize {
self.0.wrapping_abs() as usize
}
}
impl Integer {
#[inline]
const fn as_negative(self) -> i128 {
(self.unsigned as i128).wrapping_neg()
}
}
#[doc(hidden)]
impl PWrapper<Integer> {
pub const fn to_start_array_binary(self, flags: FormattingFlags) -> StartAndArray<[u8; 130]> {
let mut n = if self.0.is_negative {
self.0.as_negative() as u128
} else {
self.0.unsigned
};
n &= *self.0.mask;
let mut out = StartAndArray {
start: 130,
array: [0u8; 130],
};
loop {
out.start -= 1;
let digit = (n & 1) as u8;
out.array[out.start] = b'0' + digit;
n >>= 1;
if n == 0 {
break;
}
}
if flags.is_alternate() {
out.start -= 1;
out.array[out.start] = b'b';
out.start -= 1;
out.array[out.start] = b'0';
}
out
}
pub const fn to_start_array_hexadecimal(
self,
flags: FormattingFlags,
) -> StartAndArray<[u8; 34]> {
let mut n = if self.0.is_negative {
self.0.as_negative() as u128
} else {
self.0.unsigned
};
n &= *self.0.mask;
let mut out = StartAndArray {
start: 34,
array: [0u8; 34],
};
loop {
out.start -= 1;
let digit = (n & 0xF) as u8;
out.array[out.start] = match digit {
0..=9 => b'0' + digit,
_ => digit + flags.hex_fmt() as u8,
};
n >>= 4;
if n == 0 {
break;
}
}
if flags.is_alternate() {
out.start -= 1;
out.array[out.start] = b'x';
out.start -= 1;
out.array[out.start] = b'0';
}
out
}
pub const fn to_start_array_display(self) -> StartAndArray<[u8; 40]> {
let mut out = StartAndArray {
start: 40,
array: [0u8; 40],
};
let mut n = self.0.unsigned;
loop {
out.start -= 1;
let digit = (n % 10) as u8;
out.array[out.start] = b'0' + digit;
n /= 10;
if n == 0 {
break;
}
}
if self.0.is_negative {
out.start -= 1;
out.array[out.start] = b'-';
}
out
}
#[inline(always)]
pub const fn to_start_array_debug(self) -> StartAndArray<[u8; 40]> {
self.to_start_array_display()
}
}
impl PWrapper<&[u8]> {
pub const fn compute_utf8_debug_len(self) -> usize {
self.compute_utf8_debug_len_in_range(0..self.0.len())
}
pub const fn compute_utf8_debug_len_in_range(self, mut range: Range<usize>) -> usize {
let mut sum = range.end - range.start;
while range.start < range.end {
let c = self.0[range.start];
if c < 128 {
let shifted = 1 << c;
if (FOR_ESCAPING.is_escaped & shifted) != 0 {
sum += if (FOR_ESCAPING.is_backslash_escaped & shifted) == 0 {
3 } else {
1 };
}
}
range.start += 1;
}
sum + 2 }
}
impl PWrapper<&str> {
#[inline(always)]
#[doc(hidden)]
pub const fn compute_debug_len(self, _: FormattingFlags) -> usize {
PWrapper(self.0.as_bytes()).compute_utf8_debug_len()
}
#[inline(always)]
#[doc(hidden)]
pub const fn compute_display_len(self, _: FormattingFlags) -> usize {
self.0.len()
}
}
#[cfg(feature = "fmt")]
const _: () = {
use crate::marker_traits::{FormatMarker, IsNotStdKind};
impl<P> FormatMarker for PWrapper<P> {
type Kind = IsNotStdKind;
type This = Self;
}
};
#[cfg(feature = "assertcp")]
macro_rules! impl_eq_for_primitives {
(
(l=$l:ident, r=$r:ident)
$(
impl[$($impl_:tt)*] $type:ty = $comparison:expr;
)*
) => (
$(
impl<$($impl_)*> PWrapper<$type> {
pub const fn const_eq(&self, $r:&$type) -> bool {
let $l = self.0;
$comparison
}
}
)*
)
}
#[cfg(feature = "assertcp")]
impl_eq_for_primitives! {
(l = l, r = r)
impl[] u8 = l == *r;
impl[] i8 = l == *r;
impl[] u16 = l == *r;
impl[] i16 = l == *r;
impl[] u32 = l == *r;
impl[] i32 = l == *r;
impl[] u64 = l == *r;
impl[] i64 = l == *r;
impl[] u128 = l == *r;
impl[] i128 = l == *r;
impl[] usize = l == *r;
impl[] isize = l == *r;
impl[] bool = l == *r;
impl[] char = l == *r;
impl[] &str = crate::slice_cmp::str_eq(l, r);
}