macro_toolset/string/
number.rs

1//! Number to string, fast and efficient utilities.
2
3use std::ops;
4
5use super::{StringExtT, StringT};
6use crate::impl_for_shared_ref;
7
8/// Hexadecimal characters in lower case.
9static HEX_CHARS_LOWER: [u8; 16] = [
10    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f',
11];
12
13/// Hexadecimal characters in upper case.
14static HEX_CHARS_UPPER: [u8; 16] = [
15    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F',
16];
17
18// === impls ===
19
20#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
21#[repr(transparent)]
22/// Number to string
23///
24/// # Generic
25///
26/// - `B`: the base of the number, should be within the range `2..=16`. Default
27///   is 10.
28/// - `U`: whether to use uppercase for hex. Default is lowercase (false).
29///
30///   For float number, `U` means whether only to reserve the integer part.
31/// - `R`: the resize length of the string. The overflow part will be truncated,
32///   and the insufficient part will be filled with '0'. Default is 0, or no
33///   resize.
34/// - `M`: the minimum length of the string, if the length of the string is less
35///   than `M`, fill with '0'.  Default is 0, or no minimum.  For signed number
36///   `M` will be ignored.
37///
38/// - `T`: the underlying type of the number. Default is `usize`.
39///
40/// # Panic
41///
42/// - Invalid base (== 0 or > 16)
43pub struct NumStr<
44    const B: u8 = 10,
45    const U: bool = false,
46    const R: usize = 0,
47    const M: usize = 0,
48    T = usize,
49>(T);
50
51impl<const B: u8, const U: bool, const R: usize, const M: usize, T> AsRef<T>
52    for NumStr<B, U, R, M, T>
53{
54    #[inline]
55    fn as_ref(&self) -> &T {
56        &self.0
57    }
58}
59
60impl<const B: u8, const U: bool, const R: usize, const M: usize, T> ops::Deref
61    for NumStr<B, U, R, M, T>
62{
63    type Target = T;
64
65    fn deref(&self) -> &Self::Target {
66        &self.0
67    }
68}
69
70impl<const B: u8, const U: bool, const R: usize, const M: usize, T> ops::DerefMut
71    for NumStr<B, U, R, M, T>
72{
73    fn deref_mut(&mut self) -> &mut Self::Target {
74        &mut self.0
75    }
76}
77
78impl<T> NumStr<10, false, 0, 0, T> {
79    #[inline]
80    /// # Create a new [`NumStr`] with the given number.
81    ///
82    /// With default settings of `B`, `U`, `R`, `M`:
83    ///
84    /// - `B`: `10`
85    /// - `U`: `false`
86    /// - `R`: `0`
87    /// - `M`: `0`
88    ///
89    /// See [`NumStr`] for details.
90    ///
91    /// If you want a hexadecimal number, chains with [`NumStr::hexadecimal()`].
92    ///
93    /// ## Notice
94    ///
95    /// For negative number, `R`, `M` will not make sense
96    ///
97    /// ## Examples
98    ///
99    /// ```rust
100    /// # use macro_toolset::string::NumStr;
101    /// # let num =
102    /// NumStr::new_default(123_i16)
103    /// # ;
104    /// ```
105    pub fn new_default(inner: T) -> Self {
106        NumStr(inner)
107    }
108
109    #[inline]
110    /// # Create a new [`NumStr`] with the given number.
111    ///
112    /// With default settings of `B`, `U`, `R`, `M`:
113    ///
114    /// - `B`: `16`
115    /// - `U`: `false`
116    /// - `R`: `0`
117    /// - `M`: `0`
118    ///
119    /// See [`NumStr`] for details.
120    ///
121    /// ## Notice
122    ///
123    /// For negative number, `R`, `M` will not make sense
124    ///
125    /// ## Examples
126    ///
127    /// ```rust
128    /// # use macro_toolset::string::NumStr;
129    /// # let num =
130    /// NumStr::hex_default(123_i16)
131    /// # ;
132    /// ```
133    pub fn hex_default(inner: T) -> NumStr<16, false, 0, 0, T> {
134        NumStr(inner)
135    }
136}
137
138impl NumStr<10, false, 0, 0, u8> {
139    #[inline]
140    /// # Create a new [`NumStr`] with the given number, mostly for encoding bytes to hex.
141    ///
142    /// With default settings of `B`, `U`, `R`, `M`:
143    ///
144    /// - `B`: `16`
145    /// - `U`: `false`
146    /// - `R`: `2`
147    /// - `M`: `0`
148    ///
149    /// See [`NumStr`] for details.
150    ///
151    /// ## Notice
152    ///
153    /// For negative number, `R`, `M` will not make sense
154    ///
155    /// ## Examples
156    ///
157    /// ```rust
158    /// # use macro_toolset::string::{NumStr, StringExtT};
159    /// let nums = vec![0x11, 0x45, 0x14, 0x19, 0x19, 0x81, 0x00]
160    ///     .into_iter()
161    ///     .map(NumStr::hex_byte_default);
162    ///
163    /// assert_eq!(nums.to_string_ext(), "11451419198100");
164    /// ```
165    pub fn hex_byte_default(inner: u8) -> NumStr<16, false, 2, 0, u8> {
166        NumStr(inner)
167    }
168}
169
170impl<const B: u8, const U: bool, const R: usize, const M: usize, T> NumStr<B, U, R, M, T> {
171    #[inline]
172    /// Create a new [`NumStr`] with the given number.
173    pub fn new(inner: T) -> Self {
174        NumStr(inner)
175    }
176
177    #[inline]
178    /// Convert to decimal representation.
179    pub fn decimal(self) -> NumStr<10, U, R, M, T> {
180        NumStr(self.0)
181    }
182
183    #[inline]
184    /// Convert to hexadecimal representation.
185    pub fn hexadecimal(self) -> NumStr<16, U, R, M, T> {
186        NumStr(self.0)
187    }
188
189    #[inline]
190    /// Set custom base.
191    ///
192    /// The valid range is `2..=16`
193    pub fn set_custom_base<const NB: u8>(self) -> NumStr<NB, U, R, M, T> {
194        debug_assert!(NB >= 2 && NB <= 16);
195
196        NumStr(self.0)
197    }
198
199    #[inline]
200    /// Set uppercase / lowercase of the number.
201    ///
202    /// Default is lowercase
203    ///
204    /// Note: only works for base > 10
205    pub fn set_uppercase<const NU: bool>(self) -> NumStr<B, NU, R, M, T> {
206        NumStr(self.0)
207    }
208
209    #[inline]
210    /// Set whether to resize the string to `len` length.
211    ///
212    /// The overflow part will be truncated, and the insufficient part will be
213    /// filled with '0'
214    ///
215    /// Default is not resize
216    ///
217    /// Note: see [`Vec::resize`] for details
218    pub fn set_resize_len<const NR: usize>(self) -> NumStr<B, U, NR, M, T> {
219        NumStr(self.0)
220    }
221
222    #[inline]
223    /// Set the minimum length of the string.
224    ///
225    /// The insufficient part will be filled with '0'.
226    ///
227    /// Default is not minimum
228    ///
229    /// Note: if set `Self::should_resize`, the minimum length will be ignored
230    pub fn set_minimum_len<const NM: usize>(self) -> NumStr<B, U, R, NM, T> {
231        NumStr(self.0)
232    }
233
234    #[inline]
235    fn charset() -> &'static [u8] {
236        debug_assert!(B >= 2 && B <= 16, "unsupported base: {}", B);
237
238        if U {
239            &HEX_CHARS_UPPER
240        } else {
241            &HEX_CHARS_LOWER
242        }
243    }
244}
245
246impl<const B: u8, const U: bool, const R: usize, const M: usize> NumStr<B, U, R, M, f32> {
247    #[inline]
248    /// Set integer only mode.
249    ///
250    /// Default disable.
251    pub fn set_integer_only<const NU: bool>(self) -> NumStr<B, NU, R, M, f32> {
252        NumStr(self.0)
253    }
254}
255
256impl<const B: u8, const U: bool, const R: usize, const M: usize> NumStr<B, U, R, M, f64> {
257    #[inline]
258    /// Set integer only mode.
259    ///
260    /// Default disable.
261    pub fn set_integer_only<const NU: bool>(self) -> NumStr<B, NU, R, M, f64> {
262        NumStr(self.0)
263    }
264}
265
266macro_rules! impl_num_str {
267    (UNSIGNED: $($ty:ty) +) => {
268        $(
269            impl<const B: u8, const U: bool, const R: usize, const M: usize> NumStr<B, U, R, M, $ty> {
270                #[inline]
271                /// Encode the number to the str
272                pub fn encode(self, string: &mut Vec<u8>) {
273                    let current_ptr = string.len();
274
275                    if R > 0 {
276                        string.resize(current_ptr + R, b'0');
277
278                        let (mut num, charset) = if self.0 == 0 {
279                            return
280                        } else {
281                            (self.0, Self::charset())
282                        };
283
284                        let string = &mut string[current_ptr..current_ptr + R];
285
286                        let mut count = 0;
287
288                        while let Some(s) = string.get_mut(count) {
289                            *s = charset[(num % B as $ty) as usize];
290                            num /= B as $ty;
291                            count += 1;
292
293                            if num <= 0 {
294                                break
295                            }
296                        }
297
298                        string
299                    } else {
300                        let (mut num, charset) = if self.0 == 0 {
301                            string.push(b'0');
302                            return
303                        } else {
304                            (self.0, Self::charset())
305                        };
306
307                        let mut count = 0;
308
309                        while num > 0 {
310                            count += 1;
311                            string.push(charset[(num % B as $ty) as usize]);
312                            num /= B as $ty;
313                        }
314
315                        // Minimal length
316                        while count < M {
317                            count += 1;
318                            string.push(b'0');
319                        }
320
321                        let final_ptr = string.len();
322                        &mut string[current_ptr..final_ptr]
323                    }.reverse();
324                }
325
326                #[inline]
327                /// Encode the number to the str
328                pub fn encode_bytes(self, string: &mut bytes::BytesMut) {
329                    let current_ptr = string.len();
330
331                    if R > 0 {
332                        string.resize(current_ptr + R, b'0');
333
334                        let (mut num, charset) = if self.0 == 0 {
335                            return
336                        } else {
337                            (self.0, Self::charset())
338                        };
339
340                        let string = &mut string[current_ptr..current_ptr + R];
341
342                        let mut count = 0;
343
344                        while let Some(s) = string.get_mut(count) {
345                            *s = charset[(num % B as $ty) as usize];
346                            num /= B as $ty;
347                            count += 1;
348
349                            if num <= 0 {
350                                break
351                            }
352                        }
353
354                        string
355                    } else {
356                        let (mut num, charset) = if self.0 == 0 {
357                            string.extend(b"0");
358                            return
359                        } else {
360                            (self.0, Self::charset())
361                        };
362
363                        let mut count = 0;
364
365                        while num > 0 {
366                            count += 1;
367                            string.extend([charset[(num % B as $ty) as usize]]);
368                            num /= B as $ty;
369                        }
370
371                        // Minimal length
372                        while count < M {
373                            count += 1;
374                            string.extend([b'0']);
375                        }
376
377                        let final_ptr = string.len();
378                        &mut string[current_ptr..final_ptr]
379                    }.reverse();
380                }
381            }
382
383            impl_num_str!(@INTERNAL $ty);
384        )+
385    };
386    (SIGNED: $($ty:ty as $uty:ty);+) => {
387        $(
388            impl<const B: u8, const U: bool, const R: usize, const M: usize> NumStr<B, U, R, M, $ty> {
389                #[inline]
390                /// Encode the number to the str
391                pub fn encode(self, string: &mut Vec<u8>) {
392                    if self.is_negative() {
393                        string.push(b'-');
394                        // No resize or minimum length for signed numbers!
395                    }
396
397                    NumStr::<B, U, 0, 0, _>::new(self.0.unsigned_abs()).encode(string);
398                }
399
400                #[inline]
401                /// Encode the number to the str
402                pub fn encode_bytes(self, string: &mut bytes::BytesMut) {
403                    if self.is_negative() {
404                        string.extend(b"-");
405                        // No resize or minimum length for signed numbers!
406                    }
407
408                    NumStr::<B, U, 0, 0, _>::new(self.0.unsigned_abs()).encode_bytes(string);
409                }
410            }
411
412            impl_num_str!(@INTERNAL $ty);
413        )+
414    };
415    (FLOAT: $($ty:ty) +) => {
416        $(
417            impl<const B: u8, const U: bool, const R: usize, const M: usize> NumStr<B, U, R, M, $ty> {
418                #[inline]
419                /// Encode the number to the str
420                pub fn encode(mut self, string: &mut Vec<u8>) {
421                    if U {
422                        self.0 = self.0.trunc();
423                    }
424
425                    let original_len = string.len();
426
427                    #[cfg(not(feature = "feat-string-ext-ryu"))]
428                    string.extend(format!("{}", self.0).as_bytes());
429
430                    #[cfg(feature = "feat-string-ext-ryu")]
431                    string.extend(ryu::Buffer::new().format(self.0).as_bytes());
432
433                    #[allow(unsafe_code)]
434                    match unsafe { std::str::from_utf8_unchecked(string) }.rfind('.') {
435                        Some(dot_pos) if self.0.is_finite() => {
436                            if U {
437                                string.truncate(dot_pos);
438                            } else if R > 0 {
439                                string.resize(dot_pos + R + 1, b'0');
440                            } else if dot_pos - original_len < M {
441                                string.resize(dot_pos + M + 1, b'0');
442                            } else {
443                                // do nothing
444                            }
445                        },
446                        Some(_) => {
447                            // is NOT finite, do nothing
448                        },
449                        None if (U || !self.0.is_finite()) => {
450                            // is not finite, or integer only, do nothing
451                        },
452                        None => {
453                            string.push(b'.');
454                            if R > 0 {
455                                string.resize(original_len + R + 1, b'0');
456                            } else if M > 0 {
457                                string.resize(original_len + M + 1, b'0');
458                            } else {
459                                string.push(b'0');
460                            }
461                        }
462                    }
463                }
464
465                #[inline]
466                /// Encode the number to the str
467                pub fn encode_bytes(mut self, string: &mut bytes::BytesMut) {
468                    if U {
469                        self.0 = self.0.trunc();
470                    }
471
472                    let original_len = string.len();
473
474                    #[cfg(not(feature = "feat-string-ext-ryu"))]
475                    string.extend(format!("{}", self.0).as_bytes());
476
477                    #[cfg(feature = "feat-string-ext-ryu")]
478                    string.extend(ryu::Buffer::new().format(self.0).as_bytes());
479
480                    #[allow(unsafe_code)]
481                    match unsafe { std::str::from_utf8_unchecked(string) }.rfind('.') {
482                        Some(dot_pos) if self.0.is_finite() => {
483                            if U {
484                                string.truncate(dot_pos);
485                            } else if R > 0 {
486                                string.resize(dot_pos + R + 1, b'0');
487                            } else if dot_pos - original_len < M {
488                                string.resize(dot_pos + M + 1, b'0');
489                            } else {
490                                // do nothing
491                            }
492                        },
493                        Some(_) => {
494                            // is NOT finite, do nothing
495                        },
496                        None if (U || !self.0.is_finite()) => {
497                            // is not finite, or integer only, do nothing
498                        },
499                        None => {
500                            string.extend(b".");
501                            if R > 0 {
502                                string.resize(original_len + R + 1, b'0');
503                            } else if M > 0 {
504                                string.resize(original_len + M + 1, b'0');
505                            } else {
506                                string.extend(b"0");
507                            }
508                        }
509                    }
510                }
511            }
512
513            impl_num_str!(@INTERNAL $ty);
514        )*
515    };
516
517    (@INTERNAL $ty:ty) => {
518        impl<const B: u8, const U: bool, const R: usize, const M: usize> StringT for NumStr<B, U, R, M, $ty> {
519            #[inline]
520            fn encode_to_buf(self, string: &mut Vec<u8>) {
521                self.encode(string)
522            }
523
524            #[inline]
525            fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
526                self.encode(string);
527                string.extend(separator.as_bytes());
528            }
529
530            #[inline]
531            fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
532                self.encode_bytes(string)
533            }
534
535            #[inline]
536            fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
537                self.encode_bytes(string);
538                string.extend(separator.as_bytes());
539            }
540        }
541
542        impl<const B: u8, const U: bool, const R: usize, const M: usize> StringExtT for NumStr<B, U, R, M, $ty> {}
543
544        impl StringT for $ty {
545            #[inline]
546            fn encode_to_buf(self, string: &mut Vec<u8>) {
547                NumStr::new_default(self).encode_to_buf(string)
548            }
549
550            #[inline]
551            fn encode_to_buf_with_separator(self, string: &mut Vec<u8>, separator: &str) {
552                NumStr::new_default(self).encode_to_buf_with_separator(string, separator)
553            }
554
555            #[inline]
556            fn encode_to_bytes_buf(self, string: &mut bytes::BytesMut) {
557                NumStr::new_default(self).encode_to_bytes_buf(string)
558            }
559
560            #[inline]
561            fn encode_to_bytes_buf_with_separator(self, string: &mut bytes::BytesMut, separator: &str) {
562                NumStr::new_default(self).encode_to_bytes_buf_with_separator(string, separator)
563            }
564        }
565
566        impl StringExtT for $ty {}
567    };
568}
569
570impl_num_str!(UNSIGNED: u8 u16 u32 u64 u128 usize);
571impl_num_str!(SIGNED: i8 as u8; i16 as u16; i32 as u32; i64 as u64; i128 as u128; isize as usize);
572impl_num_str!(FLOAT: f32 f64);
573impl_for_shared_ref!(COPIED: u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64);
574
575#[cfg(test)]
576#[allow(clippy::cognitive_complexity)]
577mod test {
578    use crate::string::{NumStr, StringExtT};
579
580    #[test]
581    fn test_num_basic() {
582        // unsigned number
583        assert_eq!("0", (0_u8).to_string_ext());
584        assert_eq!("1", (1_u8).to_string_ext());
585        assert_eq!("123", (123_u8).to_string_ext());
586        assert_eq!(u8::MAX.to_string(), (u8::MAX).to_string_ext());
587
588        assert_eq!("0", (0_u16).to_string_ext());
589        assert_eq!("1", (1_u16).to_string_ext());
590        assert_eq!("123", (123_u16).to_string_ext());
591        assert_eq!(u16::MAX.to_string(), (u16::MAX).to_string_ext());
592
593        assert_eq!("0", (0_u32).to_string_ext());
594        assert_eq!("1", (1_u32).to_string_ext());
595        assert_eq!("123", (123_u32).to_string_ext());
596        assert_eq!(u32::MAX.to_string(), (u32::MAX).to_string_ext());
597
598        assert_eq!("0", (0_u64).to_string_ext());
599        assert_eq!("1", (1_u64).to_string_ext());
600        assert_eq!("123", (123_u64).to_string_ext());
601        assert_eq!(u64::MAX.to_string(), (u64::MAX).to_string_ext());
602
603        assert_eq!("0", (0_u128).to_string_ext());
604        assert_eq!("1", (1_u128).to_string_ext());
605        assert_eq!("123", (123_u128).to_string_ext());
606        assert_eq!(u128::MAX.to_string(), (u128::MAX).to_string_ext());
607
608        assert_eq!("0", (0_usize).to_string_ext());
609        assert_eq!("1", (1_usize).to_string_ext());
610        assert_eq!("123", (123_usize).to_string_ext());
611        assert_eq!(usize::MAX.to_string(), (usize::MAX).to_string_ext());
612
613        // signed number
614        assert_eq!("-123", (-123_i8).to_string_ext());
615        assert_eq!("-1", (-1_i8).to_string_ext());
616        assert_eq!("0", (0_i8).to_string_ext());
617        assert_eq!("1", (1_i8).to_string_ext());
618        assert_eq!("123", (123_i8).to_string_ext());
619        assert_eq!(i8::MAX.to_string(), (i8::MAX).to_string_ext());
620        assert_eq!(i8::MIN.to_string(), (i8::MIN).to_string_ext());
621
622        assert_eq!("-123", (-123_i16).to_string_ext());
623        assert_eq!("-1", (-1_i16).to_string_ext());
624        assert_eq!("0", (0_i16).to_string_ext());
625        assert_eq!("1", (1_i16).to_string_ext());
626        assert_eq!("123", (123_i16).to_string_ext());
627        assert_eq!(i16::MAX.to_string(), (i16::MAX).to_string_ext());
628        assert_eq!(i16::MIN.to_string(), (i16::MIN).to_string_ext());
629
630        assert_eq!("-123", (-123_i32).to_string_ext());
631        assert_eq!("-1", (-1_i32).to_string_ext());
632        assert_eq!("0", (0_i32).to_string_ext());
633        assert_eq!("1", (1_i32).to_string_ext());
634        assert_eq!("123", (123_i32).to_string_ext());
635        assert_eq!(i32::MAX.to_string(), (i32::MAX).to_string_ext());
636        assert_eq!(i32::MIN.to_string(), (i32::MIN).to_string_ext());
637
638        assert_eq!("-123", (-123_i64).to_string_ext());
639        assert_eq!("-1", (-1_i64).to_string_ext());
640        assert_eq!("0", (0_i64).to_string_ext());
641        assert_eq!("1", (1_i64).to_string_ext());
642        assert_eq!("123", (123_i64).to_string_ext());
643        assert_eq!(i64::MAX.to_string(), (i64::MAX).to_string_ext());
644        assert_eq!(i64::MIN.to_string(), (i64::MIN).to_string_ext());
645
646        assert_eq!("-123", (-123_i128).to_string_ext());
647        assert_eq!("-1", (-1_i128).to_string_ext());
648        assert_eq!("0", (0_i128).to_string_ext());
649        assert_eq!("1", (1_i128).to_string_ext());
650        assert_eq!("123", (123_i128).to_string_ext());
651        assert_eq!(i128::MAX.to_string(), (i128::MAX).to_string_ext());
652        assert_eq!(i128::MIN.to_string(), (i128::MIN).to_string_ext());
653
654        assert_eq!("-123", (-123_isize).to_string_ext());
655        assert_eq!("-1", (-1_isize).to_string_ext());
656        assert_eq!("0", (0_isize).to_string_ext());
657        assert_eq!("1", (1_isize).to_string_ext());
658        assert_eq!("123", (123_isize).to_string_ext());
659        assert_eq!(isize::MAX.to_string(), (isize::MAX).to_string_ext());
660        assert_eq!(isize::MIN.to_string(), (isize::MIN).to_string_ext());
661
662        assert_eq!("-inf", f32::NEG_INFINITY.to_string_ext());
663        assert_eq!("-inf", f64::NEG_INFINITY.to_string_ext());
664        assert_eq!("-1.0", (-1.0_f32).to_string_ext());
665        assert_eq!("-1.0", (-1.0_f64).to_string_ext());
666        #[cfg(feature = "feat-string-ext-ryu")]
667        assert_eq!(
668            "-1.23e-40",
669            (-0.000000000000000000000000000000000000000123_f32).to_string_ext()
670        );
671        #[cfg(not(feature = "feat-string-ext-ryu"))]
672        assert_eq!(
673            "-0.000000000000000000000000000000000000000123",
674            (-0.000000000000000000000000000000000000000123_f32).to_string_ext()
675        );
676        #[cfg(feature = "feat-string-ext-ryu")]
677        assert_eq!(
678            "-1.23e-40",
679            (-0.000000000000000000000000000000000000000123_f64).to_string_ext()
680        );
681        #[cfg(not(feature = "feat-string-ext-ryu"))]
682        assert_eq!(
683            "-0.000000000000000000000000000000000000000123",
684            (-0.000000000000000000000000000000000000000123_f64).to_string_ext()
685        );
686        assert_eq!("-4.242", (-4.242_f32).to_string_ext());
687        assert_eq!("-4.242", (-4.242_f64).to_string_ext());
688        assert_eq!("0.0", (0.0_f32).to_string_ext());
689        assert_eq!("0.0", (0.0_f64).to_string_ext());
690        assert_eq!("1.0", (1.0_f32).to_string_ext());
691        assert_eq!("1.0", (1.0_f64).to_string_ext());
692        assert_eq!("4.242", (4.242_f32).to_string_ext());
693        assert_eq!("4.242", (4.242_f64).to_string_ext());
694        assert_eq!("inf", f32::INFINITY.to_string_ext());
695        assert_eq!("inf", f64::INFINITY.to_string_ext());
696    }
697
698    #[test]
699    fn test_num_hex() {
700        // unsigned number
701        assert_eq!(
702            "0",
703            NumStr::new_default(0x0_u8).hexadecimal().to_string_ext()
704        );
705        assert_eq!(
706            "1",
707            NumStr::new_default(0x1_u8).hexadecimal().to_string_ext()
708        );
709        assert_eq!(
710            "42",
711            NumStr::new_default(0x42_u8).hexadecimal().to_string_ext()
712        );
713        assert_eq!(
714            "ff",
715            NumStr::new_default(u8::MAX).hexadecimal().to_string_ext()
716        );
717
718        assert_eq!(
719            "0",
720            NumStr::new_default(0x0_u16).hexadecimal().to_string_ext()
721        );
722        assert_eq!(
723            "1",
724            NumStr::new_default(0x1_u16).hexadecimal().to_string_ext()
725        );
726        assert_eq!(
727            "123",
728            NumStr::new_default(0x123_u16).hexadecimal().to_string_ext()
729        );
730        assert_eq!(
731            "ffff",
732            NumStr::new_default(u16::MAX).hexadecimal().to_string_ext()
733        );
734
735        assert_eq!(
736            "0",
737            NumStr::new_default(0x0_u32).hexadecimal().to_string_ext()
738        );
739        assert_eq!(
740            "1",
741            NumStr::new_default(0x1_u32).hexadecimal().to_string_ext()
742        );
743        assert_eq!(
744            "123",
745            NumStr::new_default(0x123_u32).hexadecimal().to_string_ext()
746        );
747        assert_eq!(
748            "ffffffff",
749            NumStr::new_default(u32::MAX).hexadecimal().to_string_ext()
750        );
751
752        assert_eq!(
753            "0",
754            NumStr::new_default(0x0_u64).hexadecimal().to_string_ext()
755        );
756        assert_eq!(
757            "1",
758            NumStr::new_default(0x1_u64).hexadecimal().to_string_ext()
759        );
760        assert_eq!(
761            "123",
762            NumStr::new_default(0x123_u64).hexadecimal().to_string_ext()
763        );
764        assert_eq!(
765            "ffffffffffffffff",
766            NumStr::new_default(u64::MAX).hexadecimal().to_string_ext()
767        );
768
769        assert_eq!(
770            "0",
771            NumStr::new_default(0x0_u128).hexadecimal().to_string_ext()
772        );
773        assert_eq!(
774            "1",
775            NumStr::new_default(0x1_u128).hexadecimal().to_string_ext()
776        );
777        assert_eq!(
778            "123",
779            NumStr::new_default(0x123_u128)
780                .hexadecimal()
781                .to_string_ext()
782        );
783        assert_eq!(
784            "ffffffffffffffffffffffffffffffff",
785            NumStr::new_default(u128::MAX).hexadecimal().to_string_ext()
786        );
787
788        assert_eq!(
789            "0",
790            NumStr::new_default(0x0_usize).hexadecimal().to_string_ext()
791        );
792        assert_eq!(
793            "1",
794            NumStr::new_default(0x1_usize).hexadecimal().to_string_ext()
795        );
796        assert_eq!(
797            "123",
798            NumStr::new_default(0x123_usize)
799                .hexadecimal()
800                .to_string_ext()
801        );
802        assert_eq!(
803            format!("{:x}", usize::MAX),
804            NumStr::new_default(usize::MAX)
805                .hexadecimal()
806                .to_string_ext()
807        );
808
809        // signed number
810        assert_eq!(
811            "-42",
812            NumStr::new_default(-0x42_i8).hexadecimal().to_string_ext()
813        );
814        assert_eq!(
815            "-1",
816            NumStr::new_default(-0x1_i8).hexadecimal().to_string_ext()
817        );
818        assert_eq!(
819            "0",
820            NumStr::new_default(0x0_i8).hexadecimal().to_string_ext()
821        );
822        assert_eq!(
823            "1",
824            NumStr::new_default(0x1_i8).hexadecimal().to_string_ext()
825        );
826        assert_eq!(
827            "42",
828            NumStr::new_default(0x42_i8).hexadecimal().to_string_ext()
829        );
830        assert_eq!(
831            "7f",
832            NumStr::new_default(i8::MAX).hexadecimal().to_string_ext()
833        );
834        assert_eq!(
835            "-80",
836            NumStr::new_default(i8::MIN).hexadecimal().to_string_ext()
837        );
838
839        assert_eq!(
840            "-123",
841            NumStr::new_default(-0x123_i16)
842                .hexadecimal()
843                .to_string_ext()
844        );
845        assert_eq!(
846            "-1",
847            NumStr::new_default(-0x1_i16).hexadecimal().to_string_ext()
848        );
849        assert_eq!(
850            "0",
851            NumStr::new_default(0x0_i16).hexadecimal().to_string_ext()
852        );
853        assert_eq!(
854            "1",
855            NumStr::new_default(0x1_i16).hexadecimal().to_string_ext()
856        );
857        assert_eq!(
858            "123",
859            NumStr::new_default(0x123_i16).hexadecimal().to_string_ext()
860        );
861        assert_eq!(
862            "7fff",
863            NumStr::new_default(i16::MAX).hexadecimal().to_string_ext()
864        );
865        assert_eq!(
866            "-8000",
867            NumStr::new_default(i16::MIN).hexadecimal().to_string_ext()
868        );
869
870        assert_eq!(
871            "-123",
872            NumStr::new_default(-0x123_i32)
873                .hexadecimal()
874                .to_string_ext()
875        );
876        assert_eq!(
877            "-1",
878            NumStr::new_default(-0x1_i32).hexadecimal().to_string_ext()
879        );
880        assert_eq!(
881            "0",
882            NumStr::new_default(0x0_i32).hexadecimal().to_string_ext()
883        );
884        assert_eq!(
885            "1",
886            NumStr::new_default(0x1_i32).hexadecimal().to_string_ext()
887        );
888        assert_eq!(
889            "123",
890            NumStr::new_default(0x123_i32).hexadecimal().to_string_ext()
891        );
892        assert_eq!(
893            "7fffffff",
894            NumStr::new_default(i32::MAX).hexadecimal().to_string_ext()
895        );
896        assert_eq!(
897            "-80000000",
898            NumStr::new_default(i32::MIN).hexadecimal().to_string_ext()
899        );
900
901        assert_eq!(
902            "-123",
903            NumStr::new_default(-0x123_i64)
904                .hexadecimal()
905                .to_string_ext()
906        );
907        assert_eq!(
908            "-1",
909            NumStr::new_default(-0x1_i64).hexadecimal().to_string_ext()
910        );
911        assert_eq!(
912            "0",
913            NumStr::new_default(0x0_i64).hexadecimal().to_string_ext()
914        );
915        assert_eq!(
916            "1",
917            NumStr::new_default(0x1_i64).hexadecimal().to_string_ext()
918        );
919        assert_eq!(
920            "123",
921            NumStr::new_default(0x123_i64).hexadecimal().to_string_ext()
922        );
923        assert_eq!(
924            "7fffffffffffffff",
925            NumStr::new_default(i64::MAX).hexadecimal().to_string_ext()
926        );
927        assert_eq!(
928            "-8000000000000000",
929            NumStr::new_default(i64::MIN).hexadecimal().to_string_ext()
930        );
931
932        assert_eq!(
933            "-123",
934            NumStr::new_default(-0x123_i128)
935                .hexadecimal()
936                .to_string_ext()
937        );
938        assert_eq!(
939            "-1",
940            NumStr::new_default(-0x1_i128).hexadecimal().to_string_ext()
941        );
942        assert_eq!(
943            "0",
944            NumStr::new_default(0x0_i128).hexadecimal().to_string_ext()
945        );
946        assert_eq!(
947            "1",
948            NumStr::new_default(0x1_i128).hexadecimal().to_string_ext()
949        );
950        assert_eq!(
951            "123",
952            NumStr::new_default(0x123_i128)
953                .hexadecimal()
954                .to_string_ext()
955        );
956        assert_eq!(
957            "7fffffffffffffffffffffffffffffff",
958            NumStr::new_default(i128::MAX).hexadecimal().to_string_ext()
959        );
960        assert_eq!(
961            "-80000000000000000000000000000000",
962            NumStr::new_default(i128::MIN).hexadecimal().to_string_ext()
963        );
964
965        assert_eq!(
966            "-123",
967            NumStr::new_default(-0x123_isize)
968                .hexadecimal()
969                .to_string_ext()
970        );
971        assert_eq!(
972            "-1",
973            NumStr::new_default(-0x1_isize)
974                .hexadecimal()
975                .to_string_ext()
976        );
977        assert_eq!(
978            "0",
979            NumStr::new_default(0x0_isize).hexadecimal().to_string_ext()
980        );
981        assert_eq!(
982            "1",
983            NumStr::new_default(0x1_isize).hexadecimal().to_string_ext()
984        );
985        assert_eq!(
986            "123",
987            NumStr::new_default(0x123_isize)
988                .hexadecimal()
989                .to_string_ext()
990        );
991        assert_eq!(
992            format!("{:x}", isize::MAX),
993            NumStr::new_default(isize::MAX)
994                .hexadecimal()
995                .to_string_ext()
996        );
997        assert_eq!(
998            format!("-{:x}", isize::MIN),
999            NumStr::new_default(isize::MIN)
1000                .hexadecimal()
1001                .to_string_ext()
1002        );
1003    }
1004
1005    #[test]
1006    fn test_r_m() {
1007        let data = NumStr::new_default(123_456_789_usize);
1008
1009        assert_eq!(data.set_resize_len::<12>().to_string_ext(), "000123456789");
1010        assert_eq!(data.set_minimum_len::<12>().to_string_ext(), "000123456789");
1011        assert_eq!(data.set_resize_len::<9>().to_string_ext(), "123456789");
1012        assert_eq!(data.set_minimum_len::<9>().to_string_ext(), "123456789");
1013        assert_eq!(data.set_resize_len::<6>().to_string_ext(), "456789");
1014        assert_eq!(data.set_minimum_len::<6>().to_string_ext(), "123456789");
1015
1016        let data = NumStr::new_default(0x123_456_789_usize).hexadecimal();
1017        assert_eq!(data.set_resize_len::<12>().to_string_ext(), "000123456789");
1018        assert_eq!(data.set_minimum_len::<12>().to_string_ext(), "000123456789");
1019        assert_eq!(data.set_resize_len::<9>().to_string_ext(), "123456789");
1020        assert_eq!(data.set_minimum_len::<9>().to_string_ext(), "123456789");
1021        assert_eq!(data.set_resize_len::<6>().to_string_ext(), "456789");
1022        assert_eq!(data.set_minimum_len::<6>().to_string_ext(), "123456789");
1023
1024        let data = NumStr::new_default(123456789.87654321_f64);
1025        assert_eq!(
1026            data.set_resize_len::<12>().to_string_ext(),
1027            "123456789.876543210000"
1028        );
1029        assert_eq!(
1030            data.set_minimum_len::<12>().to_string_ext(),
1031            "123456789.876543210000"
1032        );
1033        assert_eq!(
1034            data.set_resize_len::<8>().to_string_ext(),
1035            "123456789.87654321"
1036        );
1037        assert_eq!(
1038            data.set_minimum_len::<8>().to_string_ext(),
1039            "123456789.87654321"
1040        );
1041        assert_eq!(
1042            data.set_resize_len::<7>().to_string_ext(),
1043            "123456789.8765432"
1044        );
1045        assert_eq!(
1046            data.set_minimum_len::<7>().to_string_ext(),
1047            "123456789.87654321"
1048        );
1049        assert_eq!(data.set_resize_len::<1>().to_string_ext(), "123456789.8");
1050        assert_eq!(
1051            data.set_minimum_len::<1>().to_string_ext(),
1052            "123456789.87654321"
1053        );
1054        assert_eq!(data.set_integer_only::<true>().to_string_ext(), "123456789");
1055    }
1056
1057    #[test]
1058    fn test_hex_uppercase() {
1059        let data = NumStr::new_default(0x1_234_567_890_abc_usize).hexadecimal();
1060        assert_eq!(
1061            data.set_uppercase::<true>().to_string_ext(),
1062            "1234567890ABC"
1063        );
1064        assert_eq!(
1065            data.set_uppercase::<false>().to_string_ext(),
1066            "1234567890abc"
1067        );
1068    }
1069}