1
1
//! Integer and floating-point number formatting
2
2
3
+ use crate :: fmt:: num_buffer:: NumBuffer ;
3
4
use crate :: mem:: MaybeUninit ;
4
5
use crate :: num:: fmt as numfmt;
5
6
use crate :: ops:: { Div , Rem , Sub } ;
@@ -199,44 +200,60 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"\
199
200
6061626364656667686970717273747576777879\
200
201
8081828384858687888990919293949596979899";
201
202
202
- macro_rules! impl_Display {
203
- ( $( $signed: ident, $unsigned: ident, ) * ; as $u: ident via $conv_fn: ident named $gen_name: ident) => {
203
+ static NEGATIVE_SIGN : & [ u8 ; 1 ] = b"-" ;
204
+
205
+ // SAFETY: safety is ensured by the caller about:
206
+ // 1. The contents of `buf` containing only ASCII characters.
207
+ // 2. `offset` being bound checked.
208
+ // 3. The contents of `buf` being initialized from `offset` onwards till the end.
209
+ unsafe fn extract_str_from_buf ( buf : & NumBuffer , offset : usize ) -> & str {
210
+ // SAFETY: safety is ensured by the caller about:
211
+ // 1. `offset` being bound checked
212
+ // 2. The contents of `buf` being initialized from `offset` onwards till the end.
213
+ let written = unsafe { buf. extract ( offset..) } ;
214
+
215
+ // SAFETY: safety is ensured by the caller about:
216
+ // 1. The contents of `buf` containing only ASCII characters.
217
+ let as_str = unsafe {
218
+ str:: from_utf8_unchecked ( slice:: from_raw_parts (
219
+ MaybeUninit :: slice_as_ptr ( written) ,
220
+ written. len ( ) ,
221
+ ) )
222
+ } ;
204
223
205
- $(
206
- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
207
- impl fmt:: Display for $unsigned {
208
- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
209
- #[ cfg( not( feature = "optimize_for_size" ) ) ]
210
- {
211
- self . _fmt( true , f)
212
- }
213
- #[ cfg( feature = "optimize_for_size" ) ]
214
- {
215
- $gen_name( self . $conv_fn( ) , true , f)
216
- }
217
- }
218
- }
224
+ as_str
225
+ }
219
226
220
- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
221
- impl fmt:: Display for $signed {
222
- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
223
- #[ cfg( not( feature = "optimize_for_size" ) ) ]
224
- {
225
- return self . unsigned_abs( ) . _fmt( * self >= 0 , f) ;
226
- }
227
- #[ cfg( feature = "optimize_for_size" ) ]
228
- {
229
- return $gen_name( self . unsigned_abs( ) . $conv_fn( ) , * self >= 0 , f) ;
230
- }
231
- }
232
- }
227
+ // SAFETY: safety is ensured by the caller about:
228
+ // 1. `start_offset` being bound checked
229
+ unsafe fn add_negative_sign (
230
+ is_nonnegative : bool ,
231
+ buf : & mut NumBuffer ,
232
+ start_offset : usize ,
233
+ ) -> usize {
234
+ if is_nonnegative {
235
+ return start_offset;
236
+ }
237
+
238
+ let offset = start_offset - 1 ;
239
+
240
+ // Setting sign for the negative number
241
+ // SAFETY: `start_offset` being bound checked is ensured by
242
+ // the caller.
243
+ unsafe { buf. write ( offset, NEGATIVE_SIGN [ 0 ] ) } ;
233
244
245
+ offset
246
+ }
247
+
248
+ // Basic functionality that is relied upon by functionality within
249
+ // `impl_Display` and `impl_FormatInto`
250
+ macro_rules! impl_NumBuffer {
251
+ ( $( $unsigned: ident, ) * ; as $u: ident named $gen_name: ident) => {
252
+
253
+ $(
234
254
#[ cfg( not( feature = "optimize_for_size" ) ) ]
235
255
impl $unsigned {
236
- fn _fmt( self , is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
237
- const MAX_DEC_N : usize = $unsigned:: MAX . ilog( 10 ) as usize + 1 ;
238
- // Buffer decimals for $unsigned with right alignment.
239
- let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; MAX_DEC_N ] ;
256
+ fn _write_into_buf( self , buf: & mut NumBuffer ) -> usize {
240
257
// Count the number of bytes in buf that are not initialized.
241
258
let mut offset = buf. len( ) ;
242
259
// Consume the least-significant decimals from a working copy.
@@ -245,10 +262,11 @@ macro_rules! impl_Display {
245
262
// Format per four digits from the lookup table.
246
263
// Four digits need a 16-bit $unsigned or wider.
247
264
while size_of:: <Self >( ) > 1 && remain > 999 . try_into( ) . expect( "branch is not hit for types that cannot fit 999 (u8)" ) {
248
- // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
265
+ // SAFETY: All of the decimals fit in `buf` since `buf` is large enough to
266
+ // accommodate the largest representation of a number possible (that of i128::MIN)
249
267
// and the while condition ensures at least 4 more decimals.
250
268
unsafe { core:: hint:: assert_unchecked( offset >= 4 ) }
251
- // SAFETY: The offset counts down from its initial buf.len()
269
+ // SAFETY: The offset counts down from its initial size
252
270
// without underflow due to the previous precondition.
253
271
unsafe { core:: hint:: assert_unchecked( offset <= buf. len( ) ) }
254
272
offset -= 4 ;
@@ -259,69 +277,82 @@ macro_rules! impl_Display {
259
277
remain /= scale;
260
278
let pair1 = ( quad / 100 ) as usize ;
261
279
let pair2 = ( quad % 100 ) as usize ;
262
- buf[ offset + 0 ] . write( DEC_DIGITS_LUT [ pair1 * 2 + 0 ] ) ;
263
- buf[ offset + 1 ] . write( DEC_DIGITS_LUT [ pair1 * 2 + 1 ] ) ;
264
- buf[ offset + 2 ] . write( DEC_DIGITS_LUT [ pair2 * 2 + 0 ] ) ;
265
- buf[ offset + 3 ] . write( DEC_DIGITS_LUT [ pair2 * 2 + 1 ] ) ;
280
+
281
+ // SAFETY: The offset is bounds-checked in the asserts above.
282
+ unsafe {
283
+ buf. write( offset + 0 , DEC_DIGITS_LUT [ pair1 * 2 + 0 ] ) ;
284
+ buf. write( offset + 1 , DEC_DIGITS_LUT [ pair1 * 2 + 1 ] ) ;
285
+ buf. write( offset + 2 , DEC_DIGITS_LUT [ pair2 * 2 + 0 ] ) ;
286
+ buf. write( offset + 3 , DEC_DIGITS_LUT [ pair2 * 2 + 1 ] ) ;
287
+ }
266
288
}
267
289
268
290
// Format per two digits from the lookup table.
269
291
if remain > 9 {
270
- // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
292
+ // SAFETY: All of the decimals fit in `buf` since `buf` is large enough to
293
+ // accommodate the largest representation of a number possible (that of i128::MIN)
271
294
// and the while condition ensures at least 2 more decimals.
272
295
unsafe { core:: hint:: assert_unchecked( offset >= 2 ) }
273
- // SAFETY: The offset counts down from its initial buf.len()
296
+ // SAFETY: The offset counts down from its initial size
274
297
// without underflow due to the previous precondition.
275
298
unsafe { core:: hint:: assert_unchecked( offset <= buf. len( ) ) }
276
299
offset -= 2 ;
277
300
278
301
let pair = ( remain % 100 ) as usize ;
279
302
remain /= 100 ;
280
- buf[ offset + 0 ] . write( DEC_DIGITS_LUT [ pair * 2 + 0 ] ) ;
281
- buf[ offset + 1 ] . write( DEC_DIGITS_LUT [ pair * 2 + 1 ] ) ;
303
+
304
+ // SAFETY: The offset is bounds-checked in the asserts above.
305
+ unsafe {
306
+ buf. write( offset + 0 , DEC_DIGITS_LUT [ pair * 2 + 0 ] ) ;
307
+ buf. write( offset + 1 , DEC_DIGITS_LUT [ pair * 2 + 1 ] ) ;
308
+ } ;
282
309
}
283
310
284
311
// Format the last remaining digit, if any.
285
312
if remain != 0 || self == 0 {
286
- // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
313
+ // SAFETY: All of the decimals fit in `buf` since `buf` is large enough to
314
+ // accommodate the largest representation of a number possible (that of i128::MIN)
287
315
// and the if condition ensures (at least) 1 more decimals.
288
316
unsafe { core:: hint:: assert_unchecked( offset >= 1 ) }
289
- // SAFETY: The offset counts down from its initial buf.len()
317
+ // SAFETY: The offset counts down from its initial size
290
318
// without underflow due to the previous precondition.
291
319
unsafe { core:: hint:: assert_unchecked( offset <= buf. len( ) ) }
292
320
offset -= 1 ;
293
321
294
322
// Either the compiler sees that remain < 10, or it prevents
295
323
// a boundary check up next.
296
324
let last = ( remain & 15 ) as usize ;
297
- buf[ offset] . write( DEC_DIGITS_LUT [ last * 2 + 1 ] ) ;
325
+
326
+ // SAFETY: The offset is bounds-checked in the asserts above.
327
+ unsafe { buf. write( offset, DEC_DIGITS_LUT [ last * 2 + 1 ] ) } ;
298
328
// not used: remain = 0;
299
329
}
300
330
301
- // SAFETY: All buf content since offset is set.
302
- let written = unsafe { buf. get_unchecked( offset..) } ;
303
- // SAFETY: Writes use ASCII from the lookup table exclusively.
304
- let as_str = unsafe {
305
- str :: from_utf8_unchecked( slice:: from_raw_parts(
306
- MaybeUninit :: slice_as_ptr( written) ,
307
- written. len( ) ,
308
- ) )
309
- } ;
331
+ offset
332
+ }
333
+
334
+ fn _fmt( self , is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
335
+ // Buffer decimals for $unsigned with right alignment.
336
+ let mut buf = NumBuffer :: new( ) ;
337
+ let offset = self . _write_into_buf( & mut buf) ;
338
+
339
+ // SAFETY: All contents of `buf` since offset is set, and
340
+ // writes use ASCII from the lookup table exclusively.
341
+ let as_str = unsafe { extract_str_from_buf( & buf, offset) } ;
342
+
310
343
f. pad_integral( is_nonnegative, "" , as_str)
311
344
}
312
345
} ) *
313
346
314
347
#[ cfg( feature = "optimize_for_size" ) ]
315
- fn $gen_name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
316
- const MAX_DEC_N : usize = $u:: MAX . ilog( 10 ) as usize + 1 ;
317
- let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; MAX_DEC_N ] ;
318
- let mut curr = MAX_DEC_N ;
319
- let buf_ptr = MaybeUninit :: slice_as_mut_ptr( & mut buf) ;
348
+ fn $gen_name( mut n: $u, is_nonnegative: bool , buf: & mut NumBuffer ) -> & str {
349
+ let mut curr = buf. len( ) ;
350
+ let buf_ptr = NumBuffer :: extract_start_mut_ptr( buf) ;
320
351
321
352
// SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
322
- // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
353
+ // `curr == buf.len() == 40 > log(n)` since `n < 2^128 < 10^39 < 10^40 `, and at
323
354
// each step this is kept the same as `n` is divided. Since `n` is always
324
- // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
355
+ // non-negative, this means that `curr >= (40 - 39) == 1 > 0` so `buf_ptr[curr..curr + 1]`
325
356
// is safe to access.
326
357
unsafe {
327
358
loop {
@@ -335,16 +366,187 @@ macro_rules! impl_Display {
335
366
}
336
367
}
337
368
338
- // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid UTF-8
369
+ // SAFETY: `curr >= 1` (unchanged if `is_nonnegative` is true) and
370
+ // `curr >= 0` (incase `is_nonnegative` is false) so `buf_ptr[curr..curr + 1]`
371
+ // is safe to access.
372
+ unsafe { add_negative_sign( is_nonnegative, buf, curr) } ;
373
+
374
+ // SAFETY: `curr >= 0` (since we made `buf` large enough), and all the chars are valid UTF-8
339
375
let buf_slice = unsafe {
340
376
str :: from_utf8_unchecked(
341
377
slice:: from_raw_parts( buf_ptr. add( curr) , buf. len( ) - curr) )
342
378
} ;
343
- f. pad_integral( is_nonnegative, "" , buf_slice)
379
+
380
+ buf_slice
344
381
}
345
382
} ;
346
383
}
347
384
385
+ // Must invoke `impl_NumBuffer` before invoking this macro.
386
+ macro_rules! impl_Display {
387
+ ( $( $signed: ident, $unsigned: ident, ) * ; via $conv_fn: ident named $gen_name: ident) => {
388
+
389
+ $(
390
+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
391
+ impl fmt:: Display for $unsigned {
392
+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
393
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
394
+ {
395
+ self . _fmt( true , f)
396
+ }
397
+ #[ cfg( feature = "optimize_for_size" ) ]
398
+ {
399
+ let mut buf = NumBuffer :: new( ) ;
400
+
401
+ // not setting the sign here, hence sending `is_nonnegative` as `true`
402
+ let as_str = $gen_name( self . $conv_fn( ) , true , & mut buf) ;
403
+ f. pad_integral( true , "" , as_str)
404
+ }
405
+ }
406
+ }
407
+
408
+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
409
+ impl fmt:: Display for $signed {
410
+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
411
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
412
+ {
413
+ return self . unsigned_abs( ) . _fmt( * self >= 0 , f) ;
414
+ }
415
+ #[ cfg( feature = "optimize_for_size" ) ]
416
+ {
417
+ let mut buf = NumBuffer :: new( ) ;
418
+
419
+ // not setting the sign here, hence sending `is_nonnegative` as `true`
420
+ let as_str = $gen_name( self . unsigned_abs( ) . $conv_fn( ) , true , & mut buf) ;
421
+ f. pad_integral( * self >= 0 , "" , as_str)
422
+ }
423
+ }
424
+ }
425
+ ) *
426
+ } ;
427
+ }
428
+
429
+ // Must invoke `impl_NumBuffer` before invoking this macro.
430
+ macro_rules! impl_FormatInto {
431
+ ( $( $signed: ident, $unsigned: ident, ) * ; via $conv_fn: ident named $gen_name: ident) => {
432
+ $(
433
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
434
+ impl $signed {
435
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
436
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
437
+ ///
438
+ /// # Examples
439
+ /// ```
440
+ /// #![feature(int_format_into)]
441
+ /// use core::fmt::NumBuffer;
442
+ ///
443
+ #[ doc = concat!( "let n = 0" , stringify!( $signed) , ";" ) ]
444
+ /// let mut buf = NumBuffer::new();
445
+ /// assert_eq!(n.format_into(&mut buf), "0");
446
+ ///
447
+ #[ doc = concat!( "let n1 = -32" , stringify!( $signed) , ";" ) ]
448
+ /// let mut buf1 = NumBuffer::new();
449
+ /// assert_eq!(n1.format_into(&mut buf1), "-32");
450
+ ///
451
+ #[ doc = concat!( "let n2 = " , stringify!( $signed:: MIN ) , ";" ) ]
452
+ /// let mut buf2 = NumBuffer::new();
453
+ #[ doc = concat!( "assert_eq!(n2.format_into(&mut buf2), " , stringify!( $signed:: MIN ) , ".to_string());" ) ]
454
+ ///
455
+ #[ doc = concat!( "let n3 = " , stringify!( $signed:: MAX ) , ";" ) ]
456
+ /// let mut buf3 = NumBuffer::new();
457
+ #[ doc = concat!( "assert_eq!(n3.format_into(&mut buf3), " , stringify!( $signed:: MAX ) , ".to_string());" ) ]
458
+ /// ```
459
+ ///
460
+ pub fn format_into( self , buf: & mut NumBuffer ) -> & str {
461
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
462
+ {
463
+ let is_nonnegative = self >= 0 ;
464
+ let mut offset = self . unsigned_abs( ) . _write_into_buf( buf) ;
465
+
466
+ // SAFETY: `offset >= 1` since only a maximum of 39 digits
467
+ // would have been written into the buffer (of size 40 bytes).
468
+ // The negative sign is not written yet.
469
+ unsafe { core:: hint:: assert_unchecked( offset >= 1 ) }
470
+
471
+ // SAFETY: The offset counts down from its initial size
472
+ // without underflow due to the previous precondition.
473
+ unsafe { core:: hint:: assert_unchecked( offset <= buf. len( ) ) }
474
+
475
+ // SAFETY: `offset >= 1` (unchanged if `is_nonnegative` is true) and
476
+ // `offset >= 0` (incase `is_nonnegative` is false) so
477
+ // `buf_ptr[offset..offset + 1]` is safe to access.
478
+ offset = unsafe { add_negative_sign( is_nonnegative, buf, offset) } ;
479
+
480
+ // SAFETY: All buf content since offset is set, and
481
+ // writes use ASCII from the lookup table exclusively.
482
+ let as_str = unsafe { extract_str_from_buf( buf, offset) } ;
483
+
484
+ as_str
485
+ }
486
+
487
+ #[ cfg( feature = "optimize_for_size" ) ]
488
+ {
489
+ let is_nonnegative = self >= 0 ;
490
+ $gen_name( self . unsigned_abs( ) . $conv_fn( ) , is_nonnegative, buf)
491
+ }
492
+
493
+ }
494
+ }
495
+
496
+ #[ unstable( feature = "int_format_into" , issue = "138215" ) ]
497
+ impl $unsigned {
498
+ /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
499
+ /// type [`NumBuffer`] that is passed by the caller by mutable reference.
500
+ ///
501
+ /// # Examples
502
+ /// ```
503
+ /// #![feature(int_format_into)]
504
+ /// use core::fmt::NumBuffer;
505
+ ///
506
+ #[ doc = concat!( "let n = 0" , stringify!( $signed) , ";" ) ]
507
+ /// let mut buf = NumBuffer::new();
508
+ /// assert_eq!(n.format_into(&mut buf), "0");
509
+ ///
510
+ #[ doc = concat!( "let n1 = 32" , stringify!( $unsigned) , ";" ) ]
511
+ /// let mut buf1 = NumBuffer::new();
512
+ /// assert_eq!(n1.format_into(&mut buf1), "32");
513
+ ///
514
+ #[ doc = concat!( "let n2 = " , stringify!( $unsigned:: MAX ) , ";" ) ]
515
+ /// let mut buf2 = NumBuffer::new();
516
+ #[ doc = concat!( "assert_eq!(n2.format_into(&mut buf2), " , stringify!( $unsigned:: MAX ) , ".to_string());" ) ]
517
+ /// ```
518
+ ///
519
+ pub fn format_into( self , buf: & mut NumBuffer ) -> & str {
520
+ #[ cfg( not( feature = "optimize_for_size" ) ) ]
521
+ {
522
+ let offset = self . _write_into_buf( buf) ;
523
+
524
+ // SAFETY: `offset >= 1` since only a maximum of 39 digits
525
+ // would have been written into the buffer (of size 40 bytes).
526
+ unsafe { core:: hint:: assert_unchecked( offset >= 1 ) }
527
+
528
+ // SAFETY: The offset counts down from its initial size
529
+ // without underflow due to the previous precondition.
530
+ unsafe { core:: hint:: assert_unchecked( offset <= buf. len( ) ) }
531
+
532
+ // SAFETY: All contents in `buf` since offset is set, and
533
+ // writes use ASCII from the lookup table exclusively.
534
+ let as_str = unsafe { extract_str_from_buf( buf, offset) } ;
535
+
536
+ as_str
537
+ }
538
+
539
+ #[ cfg( feature = "optimize_for_size" ) ]
540
+ {
541
+ $gen_name( self . $conv_fn( ) , true , buf)
542
+ }
543
+
544
+ }
545
+ }
546
+ ) *
547
+ }
548
+ }
549
+
348
550
macro_rules! impl_Exp {
349
551
( $( $t: ident) ,* as $u: ident via $conv_fn: ident named $name: ident) => {
350
552
fn $name(
@@ -523,14 +725,24 @@ impl_Debug! {
523
725
#[ cfg( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ]
524
726
mod imp {
525
727
use super :: * ;
728
+ impl_NumBuffer ! (
729
+ u8 , u16 , u32 , u64 , usize ,
730
+ ; as u64 named stringify_u64) ;
526
731
impl_Display ! (
527
732
i8 , u8 ,
528
733
i16 , u16 ,
529
734
i32 , u32 ,
530
735
i64 , u64 ,
531
736
isize , usize ,
532
- ; as u64 via to_u64 named fmt_u64
533
- ) ;
737
+ ; via to_u64 named stringify_u64) ;
738
+ impl_FormatInto ! (
739
+ i8 , u8 ,
740
+ i16 , u16 ,
741
+ i32 , u32 ,
742
+ i64 , u64 ,
743
+ isize , usize ,
744
+ ; via to_u64 named stringify_u64) ;
745
+
534
746
impl_Exp ! (
535
747
i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , usize , isize
536
748
as u64 via to_u64 named exp_u64
@@ -540,19 +752,42 @@ mod imp {
540
752
#[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
541
753
mod imp {
542
754
use super :: * ;
755
+ impl_NumBuffer ! (
756
+ u8 , u16 , u32 , usize ,
757
+ ; as u32 named stringify_u32) ;
543
758
impl_Display ! (
544
759
i8 , u8 ,
545
760
i16 , u16 ,
546
761
i32 , u32 ,
547
762
isize , usize ,
548
- ; as u32 via to_u32 named fmt_u32) ;
763
+ ; via to_u32 named stringify_u32) ;
764
+ impl_FormatInto ! (
765
+ i8 , u8 ,
766
+ i16 , u16 ,
767
+ i32 , u32 ,
768
+ isize , usize ,
769
+ ; via to_u32 named stringify_u32) ;
770
+
771
+ impl_NumBuffer ! (
772
+ u64 ,
773
+ ; as u64 named stringify_u64) ;
549
774
impl_Display ! (
550
775
i64 , u64 ,
551
- ; as u64 via to_u64 named fmt_u64) ;
776
+ ; via to_u64 named stringify_u64) ;
777
+ impl_FormatInto ! (
778
+ i64 , u64 ,
779
+ ; via to_u64 named stringify_u64) ;
552
780
553
781
impl_Exp ! ( i8 , u8 , i16 , u16 , i32 , u32 , isize , usize as u32 via to_u32 named exp_u32) ;
554
782
impl_Exp ! ( i64 , u64 as u64 via to_u64 named exp_u64) ;
555
783
}
784
+ impl_NumBuffer ! (
785
+ u128 ,
786
+ ; as u128 named stringify_u128) ;
787
+ impl_FormatInto ! (
788
+ i128 , u128 ,
789
+ ; via to_u128 named stringify_u128) ;
790
+
556
791
impl_Exp ! ( i128 , u128 as u128 via to_u128 named exp_u128) ;
557
792
558
793
/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
0 commit comments