1
1
use num_bigint:: { BigInt , Sign } ;
2
+ use num_traits:: cast:: ToPrimitive ;
2
3
use num_traits:: Signed ;
3
4
use std:: cmp;
4
5
use std:: str:: FromStr ;
@@ -281,14 +282,22 @@ impl FormatSpec {
281
282
separator : char ,
282
283
) -> String {
283
284
let mut result = String :: new ( ) ;
284
- let mut remaining: usize = magnitude_string. len ( ) ;
285
- for c in magnitude_string. chars ( ) {
285
+
286
+ // Don't add separators to the floating decimal point of numbers
287
+ let mut parts = magnitude_string. splitn ( 2 , '.' ) ;
288
+ let magnitude_integer_string = parts. next ( ) . unwrap ( ) ;
289
+ let mut remaining: usize = magnitude_integer_string. len ( ) ;
290
+ for c in magnitude_integer_string. chars ( ) {
286
291
result. push ( c) ;
287
292
remaining -= 1 ;
288
293
if remaining % interval == 0 && remaining > 0 {
289
294
result. push ( separator) ;
290
295
}
291
296
}
297
+ if let Some ( part) = parts. next ( ) {
298
+ result. push ( '.' ) ;
299
+ result. push_str ( part) ;
300
+ }
292
301
result
293
302
}
294
303
@@ -300,6 +309,7 @@ impl FormatSpec {
300
309
Some ( FormatType :: HexLower ) => 4 ,
301
310
Some ( FormatType :: HexUpper ) => 4 ,
302
311
Some ( FormatType :: Number ) => 3 ,
312
+ Some ( FormatType :: FixedPointLower ) | Some ( FormatType :: FixedPointUpper ) => 3 ,
303
313
None => 3 ,
304
314
_ => panic ! ( "Separators only valid for numbers!" ) ,
305
315
}
@@ -321,8 +331,75 @@ impl FormatSpec {
321
331
}
322
332
}
323
333
334
+ pub fn format_float ( & self , num : f64 ) -> Result < String , & ' static str > {
335
+ let precision = self . precision . unwrap_or ( 6 ) ;
336
+ let magnitude = num. abs ( ) ;
337
+ let raw_magnitude_string_result: Result < String , & ' static str > = match self . format_type {
338
+ Some ( FormatType :: FixedPointUpper ) => match magnitude {
339
+ magnitude if magnitude. is_nan ( ) => Ok ( "NAN" . to_string ( ) ) ,
340
+ magnitude if magnitude. is_infinite ( ) => Ok ( "INF" . to_string ( ) ) ,
341
+ _ => Ok ( format ! ( "{:.*}" , precision, magnitude) ) ,
342
+ } ,
343
+ Some ( FormatType :: FixedPointLower ) => match magnitude {
344
+ magnitude if magnitude. is_nan ( ) => Ok ( "nan" . to_string ( ) ) ,
345
+ magnitude if magnitude. is_infinite ( ) => Ok ( "inf" . to_string ( ) ) ,
346
+ _ => Ok ( format ! ( "{:.*}" , precision, magnitude) ) ,
347
+ } ,
348
+ Some ( FormatType :: Decimal ) => Err ( "Unknown format code 'd' for object of type 'float'" ) ,
349
+ Some ( FormatType :: Binary ) => Err ( "Unknown format code 'b' for object of type 'float'" ) ,
350
+ Some ( FormatType :: Octal ) => Err ( "Unknown format code 'o' for object of type 'float'" ) ,
351
+ Some ( FormatType :: HexLower ) => Err ( "Unknown format code 'x' for object of type 'float'" ) ,
352
+ Some ( FormatType :: HexUpper ) => Err ( "Unknown format code 'X' for object of type 'float'" ) ,
353
+ Some ( FormatType :: String ) => Err ( "Unknown format code 's' for object of type 'float'" ) ,
354
+ Some ( FormatType :: Character ) => {
355
+ Err ( "Unknown format code 'c' for object of type 'float'" )
356
+ }
357
+ Some ( FormatType :: Number ) => {
358
+ Err ( "Format code 'n' for object of type 'float' not implemented yet" )
359
+ }
360
+ Some ( FormatType :: GeneralFormatUpper ) => {
361
+ Err ( "Format code 'G' for object of type 'float' not implemented yet" )
362
+ }
363
+ Some ( FormatType :: GeneralFormatLower ) => {
364
+ Err ( "Format code 'g' for object of type 'float' not implemented yet" )
365
+ }
366
+ Some ( FormatType :: ExponentUpper ) => {
367
+ Err ( "Format code 'E' for object of type 'float' not implemented yet" )
368
+ }
369
+ Some ( FormatType :: ExponentLower ) => {
370
+ Err ( "Format code 'e' for object of type 'float' not implemented yet" )
371
+ }
372
+ None => {
373
+ match magnitude {
374
+ magnitude if magnitude. is_nan ( ) => Ok ( "nan" . to_string ( ) ) ,
375
+ magnitude if magnitude. is_infinite ( ) => Ok ( "inf" . to_string ( ) ) ,
376
+ // Using the Debug format here to prevent the automatic conversion of floats
377
+ // ending in .0 to their integer representation (e.g., 1.0 -> 1)
378
+ _ => Ok ( format ! ( "{:?}" , magnitude) ) ,
379
+ }
380
+ }
381
+ } ;
382
+
383
+ if raw_magnitude_string_result. is_err ( ) {
384
+ return raw_magnitude_string_result;
385
+ }
386
+
387
+ let magnitude_string = self . add_magnitude_separators ( raw_magnitude_string_result. unwrap ( ) ) ;
388
+ let format_sign = self . sign . unwrap_or ( FormatSign :: Minus ) ;
389
+ let sign_str = if num. is_sign_negative ( ) && !num. is_nan ( ) {
390
+ "-"
391
+ } else {
392
+ match format_sign {
393
+ FormatSign :: Plus => "+" ,
394
+ FormatSign :: Minus => "" ,
395
+ FormatSign :: MinusOrSpace => " " ,
396
+ }
397
+ } ;
398
+
399
+ self . format_sign_and_align ( magnitude_string, sign_str)
400
+ }
401
+
324
402
pub fn format_int ( & self , num : & BigInt ) -> Result < String , & ' static str > {
325
- let fill_char = self . fill . unwrap_or ( ' ' ) ;
326
403
let magnitude = num. abs ( ) ;
327
404
let prefix = if self . alternate_form {
328
405
match self . format_type {
@@ -360,11 +437,11 @@ impl FormatSpec {
360
437
Some ( FormatType :: ExponentLower ) => {
361
438
Err ( "Unknown format code 'e' for object of type 'int'" )
362
439
}
363
- Some ( FormatType :: FixedPointUpper ) => {
364
- Err ( "Unknown format code 'F' for object of type 'int'" )
365
- }
366
- Some ( FormatType :: FixedPointLower ) => {
367
- Err ( "Unknown format code 'f' for object of type 'int'" )
440
+ Some ( FormatType :: FixedPointUpper ) | Some ( FormatType :: FixedPointLower ) => {
441
+ match num . to_f64 ( ) {
442
+ Some ( float ) => return self . format_float ( float ) ,
443
+ _ => Err ( "Unable to convert int to float" ) ,
444
+ }
368
445
}
369
446
None => Ok ( magnitude. to_str_radix ( 10 ) ) ,
370
447
} ;
@@ -376,10 +453,6 @@ impl FormatSpec {
376
453
prefix,
377
454
self . add_magnitude_separators( raw_magnitude_string_result. unwrap( ) )
378
455
) ;
379
- let align = self . align . unwrap_or ( FormatAlign :: Right ) ;
380
-
381
- // Use the byte length as the string length since we're in ascii
382
- let num_chars = magnitude_string. len ( ) ;
383
456
384
457
let format_sign = self . sign . unwrap_or ( FormatSign :: Minus ) ;
385
458
let sign_str = match num. sign ( ) {
@@ -391,6 +464,19 @@ impl FormatSpec {
391
464
} ,
392
465
} ;
393
466
467
+ self . format_sign_and_align ( magnitude_string, sign_str)
468
+ }
469
+
470
+ fn format_sign_and_align (
471
+ & self ,
472
+ magnitude_string : String ,
473
+ sign_str : & str ,
474
+ ) -> Result < String , & ' static str > {
475
+ let align = self . align . unwrap_or ( FormatAlign :: Right ) ;
476
+
477
+ // Use the byte length as the string length since we're in ascii
478
+ let num_chars = magnitude_string. len ( ) ;
479
+ let fill_char = self . fill . unwrap_or ( ' ' ) ;
394
480
let fill_chars_needed: i32 = self . width . map_or ( 0 , |w| {
395
481
cmp:: max ( 0 , ( w as i32 ) - ( num_chars as i32 ) - ( sign_str. len ( ) as i32 ) )
396
482
} ) ;
0 commit comments