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/// Wrapper for many std types,
14/// which implements the `const_debug_fmt` and/or `const_display_fmt` methods for them.
15///
16/// The macros from this crate automatically wraps std types in this type,
17/// so you only need to use it if you're manually calling the `const_*_fmt` methods.
18///
19/// ### Constructors
20///
21/// Most std types can be wrapped in this type simply by doing `PWrapper(value)`.
22///
23/// To wrap arrays, there is the [`PWrapper::slice`](#method.slice) constructor
24/// for convenience.
25///
26/// ### Excluded std types
27///
28/// Note that this type does not implement the formatting methods
29/// for std types which wrap non-std types,
30/// only for a selection of wrapped std types.
31///
32/// You can use the [`call_debug_fmt`] macro to format arrays/slices/Options of
33/// any type that can be const debug formatted.
34///
35/// # Example
36///
37/// This example demonstrates how you can implement debug formatting for a type
38/// using PWrapper to write std types.
39///
40#[cfg_attr(feature = "fmt", doc = "```rust")]
41#[cfg_attr(not(feature = "fmt"), doc = "```ignore")]
42///
43/// use const_format::{Error, Formatter, PWrapper};
44/// use const_format::{impl_fmt, formatc, try_};
45///
46/// use core::num::NonZeroU32;
47///
48/// pub struct Divide(pub u32, pub u32);
49///
50/// impl_fmt!{
51///     impl Divide;
52///     
53///     pub const fn const_debug_fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
54///         let Self(left, right) = *self;
55///         let divided = self.0 / self.1;
56///
57///         let mut f = f.debug_struct("Divide");
58///         try_!(PWrapper(self.0).const_debug_fmt(f.field("numerator")));
59///         try_!(PWrapper(self.1).const_debug_fmt(f.field("denominator")));
60///         try_!(PWrapper(divided).const_debug_fmt(f.field("divided")));
61///         f.finish()
62///     }
63/// }
64///
65/// const TEXT: &str = formatc!("{:?}", Divide(34, 11));
66/// const T_HEX: &str = formatc!("{:X?}", Divide(34, 11));
67/// const T_BIN: &str = formatc!("{:b?}", Divide(34, 11));
68///
69/// assert_eq!(TEXT, "Divide { numerator: 34, denominator: 11, divided: 3 }");
70/// assert_eq!(T_HEX, "Divide { numerator: 22, denominator: B, divided: 3 }");
71/// assert_eq!(T_BIN, "Divide { numerator: 100010, denominator: 1011, divided: 11 }");
72/// ```
73///
74/// [`call_debug_fmt`]: ./macro.call_debug_fmt.html
75/// [`writec`]: ./macro.writec.html
76///
77#[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    /// For constructing from a reference to an array.
83    ///
84    /// With slices you can do `PWrapper(slice)` as well.
85    #[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            /// Computes how long much space is necessary to write this integer as a literal.
138            #[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            /// Computes how long much space is necessary to
152            /// write this integer as a hexadecimal literal.
153            pub const fn hexadecimal_len(self, fmt: FormattingFlags)-> usize {
154                compute_hex_count!($bits, self.0, fmt.is_alternate())
155            }
156
157            /// Computes how long much space is necessary to
158            /// write this integer as a binary literal.
159            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            /// Returns the absolute value of this integer, as the equivalent unsigned type.
173            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            /// Returns the absolute value of this integer, as the equivalent unsigned type.
197            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            /// Computes how long much space is necessary to write this integer as a literal.
244            #[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            /// Computes how long much space is necessary to write this integer as a literal.
250            #[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            /// Computes how long much space is necessary to
256            /// write this integer as a hexadecimal literal.
257            #[inline(always)]
258            pub const fn hexadecimal_len(self, fmt: FormattingFlags) -> usize {
259                PWrapper(self.0 as $XWord).hexadecimal_len(fmt)
260            }
261
262            /// Computes how long much space is necessary to
263            /// write this integer as a binary literal.
264            #[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    /// Returns the absolute value of this integer.
277    pub const fn unsigned_abs(self) -> usize {
278        self.0
279    }
280}
281
282impl PWrapper<isize> {
283    /// Returns the absolute value of this integer, as the equivalent unsigned type.
284    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    /// Computes how much space is necessary to write the wrapped `&[u8]` as a utf8 string,
406    /// with debug formatting
407    pub const fn compute_utf8_debug_len(self) -> usize {
408        self.compute_utf8_debug_len_in_range(0..self.0.len())
409    }
410
411    /// Computes how much space is necessary to write `&self.0[range]` as a utf8 string,
412    /// with debug formatting
413    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 // `\x01` only add 3 characters
422                    } else {
423                        1 // Escaped with a backslash
424                    };
425                }
426            }
427            range.start += 1;
428        }
429        sum + 2 // The quote characters
430    }
431}
432
433impl PWrapper<&str> {
434    /// Computes how much space is necessary to write a `&str` with debug formatting
435    #[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    /// Computes how much space is necessary to write a `&str` with display formatting
442    #[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///////////////////////////////////////////////////////////////////////////
460
461#[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                /// This method is only available with the "assert" feature.
474                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}