const_format/wrapper_types/
pwrapper.rs
1#![allow(unexpected_cfgs)]
2
3use crate::{
4 formatting::{FormattingFlags, NumberFormatting, StartAndArray, FOR_ESCAPING},
5 pargument::Integer,
6};
7
8use core::ops::Range;
9
10#[cfg(test)]
11mod tests;
12
13#[cfg_attr(feature = "fmt", doc = "```rust")]
41#[cfg_attr(not(feature = "fmt"), doc = "```ignore")]
42#[cfg_attr(feature = "__docsrs", doc(cfg(feature = "fmt")))]
78#[derive(Copy, Clone)]
79pub struct PWrapper<T>(pub T);
80
81impl<'a, T> PWrapper<&'a [T]> {
82 #[inline(always)]
86 pub const fn slice(x: &'a [T]) -> Self {
87 Self { 0: x }
88 }
89}
90
91macro_rules! compute_hex_count {
92 ($bits:expr, $int:expr, $with_0x:expr) => {{
93 let with_0x = ($with_0x as usize) << 1;
94 let i = ($bits - $int.leading_zeros()) as usize;
95 (if i == 0 {
96 1
97 } else {
98 (i >> 2) + ((i & 3) != 0) as usize
99 }) + with_0x
100 }};
101}
102macro_rules! compute_binary_count {
103 ($bits:expr, $int:expr, $with_0b:expr) => {{
104 let with_0b = ($with_0b as usize) << 1;
105 let i = ($bits - $int.leading_zeros()) as usize;
106 (if i == 0 { 1 } else { i }) + with_0b
107 }};
108}
109
110macro_rules! impl_number_of_digits {
111 (num number_of_digits;delegate $n:ident $len:ident)=>{
112 $n.number_of_digits()
113 };
114 (num number_of_digits;128 $n:ident $len:ident)=>{{
115 if $n >= 1_0000_0000_0000_0000{$n /= 1_0000_0000_0000_0000; $len += 16;}
116 impl_number_of_digits!(num number_of_digits;64 $n $len)
117 }};
118 (num number_of_digits;64 $n:ident $len:ident)=>{{
119 if $n >= 1_0000_0000_0000{$n /= 1_0000_0000_0000; $len += 12;}
120 impl_number_of_digits!(num number_of_digits;32 $n $len)
121 }};
122 (num number_of_digits;32 $n:ident $len:ident)=>{{
123 if $n >= 1_0000_0000{$n /= 100_000_000; $len += 8;}
124 impl_number_of_digits!(num number_of_digits;16 $n $len)
125 }};
126 (num number_of_digits;16 $n:ident $len:ident)=>{{
127 if $n >= 1_0000{$n /= 1_0000; $len += 4;}
128 impl_number_of_digits!(num number_of_digits;8 $n $len)
129 }};
130 (num number_of_digits;8 $n:ident $len:ident)=>{{
131 if $n >= 100{$n /= 100; $len += 2;}
132 if $n >= 10{ $len += 1;}
133 $len
134 }};
135 (@shared $This:ty, $bits:tt)=>{
136 impl PWrapper<$This> {
137 #[allow(unused_mut,unused_variables)]
139 #[doc(hidden)]
140 pub const fn compute_debug_len(self, fmt: FormattingFlags)-> usize {
141 match fmt.num_fmt() {
142 NumberFormatting::Decimal=>
143 self.compute_display_len(fmt),
144 NumberFormatting::Hexadecimal=>
145 compute_hex_count!($bits, self.0, fmt.is_alternate()),
146 NumberFormatting::Binary=>
147 compute_binary_count!($bits, self.0, fmt.is_alternate()),
148 }
149 }
150
151 pub const fn hexadecimal_len(self, fmt: FormattingFlags)-> usize {
154 compute_hex_count!($bits, self.0, fmt.is_alternate())
155 }
156
157 pub const fn binary_len(self, fmt: FormattingFlags)-> usize {
160 compute_binary_count!($bits, self.0, fmt.is_alternate())
161 }
162 }
163 };
164 (impl_either;
165 signed,
166 ($This:ty, $Unsigned:ty),
167 $bits:tt $(,)?
168 )=>{
169 impl_number_of_digits!{@shared $This, $bits}
170
171 impl PWrapper<$This> {
172 pub const fn unsigned_abs(self) -> $Unsigned {
174 self.0.wrapping_abs() as $Unsigned
175 }
176
177 #[allow(unused_mut,unused_variables)]
178 #[doc(hidden)]
179 pub const fn compute_display_len(self, _: FormattingFlags)-> usize {
180 let mut n = self.0.wrapping_abs() as $Unsigned;
181 let mut len = 1 + (self.0 < 0) as usize;
182 impl_number_of_digits!(num number_of_digits;$bits n len)
183 }
184
185
186 }
187 };
188 (impl_either;
189 unsigned,
190 ($This:ty, $Unsigned:ty),
191 $bits:tt $(,)?
192 )=>{
193 impl_number_of_digits!{@shared $This, $bits}
194
195 impl PWrapper<$This> {
196 pub const fn unsigned_abs(self) -> $Unsigned {
198 self.0
199 }
200
201 #[doc(hidden)]
202 pub const fn compute_display_len(self, _: FormattingFlags)-> usize {
203 let mut n = self.0;
204 let mut len = 1usize;
205 impl_number_of_digits!(num number_of_digits;$bits n len)
206 }
207 }
208 };
209}
210
211impl_number_of_digits! {impl_either; signed , (i8, u8), 8}
212impl_number_of_digits! {impl_either; signed , (i16, u16), 16}
213impl_number_of_digits! {impl_either; signed , (i32, u32), 32}
214impl_number_of_digits! {impl_either; signed , (i64, u64), 64}
215impl_number_of_digits! {impl_either; signed , (i128, u128), 128}
216impl_number_of_digits! {impl_either; unsigned, (u8, u8), 8}
217impl_number_of_digits! {impl_either; unsigned, (u16, u16), 16}
218impl_number_of_digits! {impl_either; unsigned, (u32, u32), 32}
219impl_number_of_digits! {impl_either; unsigned, (u64, u64), 64}
220impl_number_of_digits! {impl_either; unsigned, (u128, u128), 128}
221
222#[cfg(target_pointer_width = "16")]
223type UWord = u16;
224#[cfg(target_pointer_width = "32")]
225type UWord = u32;
226#[cfg(target_pointer_width = "64")]
227type UWord = u64;
228#[cfg(target_pointer_width = "128")]
229type UWord = u128;
230
231#[cfg(target_pointer_width = "16")]
232type IWord = i16;
233#[cfg(target_pointer_width = "32")]
234type IWord = i32;
235#[cfg(target_pointer_width = "64")]
236type IWord = i64;
237#[cfg(target_pointer_width = "128")]
238type IWord = i128;
239
240macro_rules! impl_for_xsize {
241 ($XSize:ident, $XWord:ident) => {
242 impl PWrapper<$XSize> {
243 #[inline(always)]
245 pub const fn compute_display_len(self, fmt: FormattingFlags) -> usize {
246 PWrapper(self.0 as $XWord).compute_display_len(fmt)
247 }
248
249 #[inline(always)]
251 pub const fn compute_debug_len(self, fmt: FormattingFlags) -> usize {
252 PWrapper(self.0 as $XWord).compute_debug_len(fmt)
253 }
254
255 #[inline(always)]
258 pub const fn hexadecimal_len(self, fmt: FormattingFlags) -> usize {
259 PWrapper(self.0 as $XWord).hexadecimal_len(fmt)
260 }
261
262 #[inline(always)]
265 pub const fn binary_len(self, fmt: FormattingFlags) -> usize {
266 PWrapper(self.0 as $XWord).binary_len(fmt)
267 }
268 }
269 };
270}
271
272impl_for_xsize! {usize, UWord}
273impl_for_xsize! {isize, IWord}
274
275impl PWrapper<usize> {
276 pub const fn unsigned_abs(self) -> usize {
278 self.0
279 }
280}
281
282impl PWrapper<isize> {
283 pub const fn unsigned_abs(self) -> usize {
285 self.0.wrapping_abs() as usize
286 }
287}
288
289impl Integer {
290 #[inline]
291 const fn as_negative(self) -> i128 {
292 (self.unsigned as i128).wrapping_neg()
293 }
294}
295
296#[doc(hidden)]
297impl PWrapper<Integer> {
298 pub const fn to_start_array_binary(self, flags: FormattingFlags) -> StartAndArray<[u8; 130]> {
299 let mut n = if self.0.is_negative {
300 self.0.as_negative() as u128
301 } else {
302 self.0.unsigned
303 };
304
305 n &= *self.0.mask;
306
307 let mut out = StartAndArray {
308 start: 130,
309 array: [0u8; 130],
310 };
311
312 loop {
313 out.start -= 1;
314 let digit = (n & 1) as u8;
315 out.array[out.start] = b'0' + digit;
316 n >>= 1;
317 if n == 0 {
318 break;
319 }
320 }
321
322 if flags.is_alternate() {
323 out.start -= 1;
324 out.array[out.start] = b'b';
325 out.start -= 1;
326 out.array[out.start] = b'0';
327 }
328
329 out
330 }
331
332 pub const fn to_start_array_hexadecimal(
333 self,
334 flags: FormattingFlags,
335 ) -> StartAndArray<[u8; 34]> {
336 let mut n = if self.0.is_negative {
337 self.0.as_negative() as u128
338 } else {
339 self.0.unsigned
340 };
341
342 n &= *self.0.mask;
343
344 let mut out = StartAndArray {
345 start: 34,
346 array: [0u8; 34],
347 };
348
349 loop {
350 out.start -= 1;
351 let digit = (n & 0xF) as u8;
352 out.array[out.start] = match digit {
353 0..=9 => b'0' + digit,
354 _ => digit + flags.hex_fmt() as u8,
355 };
356 n >>= 4;
357 if n == 0 {
358 break;
359 }
360 }
361
362 if flags.is_alternate() {
363 out.start -= 1;
364 out.array[out.start] = b'x';
365 out.start -= 1;
366 out.array[out.start] = b'0';
367 }
368
369 out
370 }
371
372 pub const fn to_start_array_display(self) -> StartAndArray<[u8; 40]> {
373 let mut out = StartAndArray {
374 start: 40,
375 array: [0u8; 40],
376 };
377
378 let mut n = self.0.unsigned;
379
380 loop {
381 out.start -= 1;
382 let digit = (n % 10) as u8;
383 out.array[out.start] = b'0' + digit;
384 n /= 10;
385 if n == 0 {
386 break;
387 }
388 }
389
390 if self.0.is_negative {
391 out.start -= 1;
392 out.array[out.start] = b'-';
393 }
394
395 out
396 }
397
398 #[inline(always)]
399 pub const fn to_start_array_debug(self) -> StartAndArray<[u8; 40]> {
400 self.to_start_array_display()
401 }
402}
403
404impl PWrapper<&[u8]> {
405 pub const fn compute_utf8_debug_len(self) -> usize {
408 self.compute_utf8_debug_len_in_range(0..self.0.len())
409 }
410
411 pub const fn compute_utf8_debug_len_in_range(self, mut range: Range<usize>) -> usize {
414 let mut sum = range.end - range.start;
415 while range.start < range.end {
416 let c = self.0[range.start];
417 if c < 128 {
418 let shifted = 1 << c;
419 if (FOR_ESCAPING.is_escaped & shifted) != 0 {
420 sum += if (FOR_ESCAPING.is_backslash_escaped & shifted) == 0 {
421 3 } else {
423 1 };
425 }
426 }
427 range.start += 1;
428 }
429 sum + 2 }
431}
432
433impl PWrapper<&str> {
434 #[inline(always)]
436 #[doc(hidden)]
437 pub const fn compute_debug_len(self, _: FormattingFlags) -> usize {
438 PWrapper(self.0.as_bytes()).compute_utf8_debug_len()
439 }
440
441 #[inline(always)]
443 #[doc(hidden)]
444 pub const fn compute_display_len(self, _: FormattingFlags) -> usize {
445 self.0.len()
446 }
447}
448
449#[cfg(feature = "fmt")]
450const _: () = {
451 use crate::marker_traits::{FormatMarker, IsNotStdKind};
452
453 impl<P> FormatMarker for PWrapper<P> {
454 type Kind = IsNotStdKind;
455 type This = Self;
456 }
457};
458
459#[cfg(feature = "assertcp")]
462macro_rules! impl_eq_for_primitives {
463 (
464 (l=$l:ident, r=$r:ident)
465
466 $(
467 impl[$($impl_:tt)*] $type:ty = $comparison:expr;
468 )*
469
470 ) => (
471 $(
472 impl<$($impl_)*> PWrapper<$type> {
473 pub const fn const_eq(&self, $r:&$type) -> bool {
475 let $l = self.0;
476 $comparison
477 }
478 }
479 )*
480 )
481}
482
483#[cfg(feature = "assertcp")]
484impl_eq_for_primitives! {
485 (l = l, r = r)
486
487 impl[] u8 = l == *r;
488 impl[] i8 = l == *r;
489 impl[] u16 = l == *r;
490 impl[] i16 = l == *r;
491 impl[] u32 = l == *r;
492 impl[] i32 = l == *r;
493 impl[] u64 = l == *r;
494 impl[] i64 = l == *r;
495 impl[] u128 = l == *r;
496 impl[] i128 = l == *r;
497 impl[] usize = l == *r;
498 impl[] isize = l == *r;
499 impl[] bool = l == *r;
500 impl[] char = l == *r;
501 impl[] &str = crate::slice_cmp::str_eq(l, r);
502}