11use num_bigint:: { BigInt , Sign } ;
2+ use num_traits:: cast:: ToPrimitive ;
23use num_traits:: Signed ;
34use std:: cmp;
45use std:: str:: FromStr ;
@@ -281,14 +282,22 @@ impl FormatSpec {
281282 separator : char ,
282283 ) -> String {
283284 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 parts: Vec < & str > = magnitude_string. split ( '.' ) . collect ( ) ;
288+ let magnitude_integer_string = parts[ 0 ] ;
289+ let mut remaining: usize = magnitude_integer_string. len ( ) ;
290+ for c in magnitude_integer_string. chars ( ) {
286291 result. push ( c) ;
287292 remaining -= 1 ;
288293 if remaining % interval == 0 && remaining > 0 {
289294 result. push ( separator) ;
290295 }
291296 }
297+ if parts. len ( ) == 2 {
298+ result. push ( '.' ) ;
299+ result. push_str ( parts[ 1 ] ) ;
300+ }
292301 result
293302 }
294303
@@ -300,6 +309,7 @@ impl FormatSpec {
300309 Some ( FormatType :: HexLower ) => 4 ,
301310 Some ( FormatType :: HexUpper ) => 4 ,
302311 Some ( FormatType :: Number ) => 3 ,
312+ Some ( FormatType :: FixedPointLower ) | Some ( FormatType :: FixedPointUpper ) => 3 ,
303313 None => 3 ,
304314 _ => panic ! ( "Separators only valid for numbers!" ) ,
305315 }
@@ -321,8 +331,75 @@ impl FormatSpec {
321331 }
322332 }
323333
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+
324402 pub fn format_int ( & self , num : & BigInt ) -> Result < String , & ' static str > {
325- let fill_char = self . fill . unwrap_or ( ' ' ) ;
326403 let magnitude = num. abs ( ) ;
327404 let prefix = if self . alternate_form {
328405 match self . format_type {
@@ -360,11 +437,11 @@ impl FormatSpec {
360437 Some ( FormatType :: ExponentLower ) => {
361438 Err ( "Unknown format code 'e' for object of type 'int'" )
362439 }
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+ }
368445 }
369446 None => Ok ( magnitude. to_str_radix ( 10 ) ) ,
370447 } ;
@@ -376,10 +453,6 @@ impl FormatSpec {
376453 prefix,
377454 self . add_magnitude_separators( raw_magnitude_string_result. unwrap( ) )
378455 ) ;
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 ( ) ;
383456
384457 let format_sign = self . sign . unwrap_or ( FormatSign :: Minus ) ;
385458 let sign_str = match num. sign ( ) {
@@ -391,6 +464,19 @@ impl FormatSpec {
391464 } ,
392465 } ;
393466
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 ( ' ' ) ;
394480 let fill_chars_needed: i32 = self . width . map_or ( 0 , |w| {
395481 cmp:: max ( 0 , ( w as i32 ) - ( num_chars as i32 ) - ( sign_str. len ( ) as i32 ) )
396482 } ) ;
0 commit comments