@@ -137,6 +137,28 @@ pub enum FormatType {
137137 Percentage ,
138138}
139139
140+ impl From < & FormatType > for char {
141+ fn from ( from : & FormatType ) -> char {
142+ match from {
143+ FormatType :: String => 's' ,
144+ FormatType :: Binary => 'b' ,
145+ FormatType :: Character => 'c' ,
146+ FormatType :: Decimal => 'd' ,
147+ FormatType :: Octal => 'o' ,
148+ FormatType :: HexLower => 'x' ,
149+ FormatType :: HexUpper => 'X' ,
150+ FormatType :: Number => 'n' ,
151+ FormatType :: ExponentLower => 'e' ,
152+ FormatType :: ExponentUpper => 'E' ,
153+ FormatType :: GeneralFormatLower => 'g' ,
154+ FormatType :: GeneralFormatUpper => 'G' ,
155+ FormatType :: FixedPointLower => 'f' ,
156+ FormatType :: FixedPointUpper => 'F' ,
157+ FormatType :: Percentage => '%' ,
158+ }
159+ }
160+ }
161+
140162impl FormatParse for FormatType {
141163 fn parse ( text : & str ) -> ( Option < Self > , & str ) {
142164 let mut chars = text. chars ( ) ;
@@ -337,6 +359,33 @@ impl FormatSpec {
337359 magnitude_str
338360 }
339361
362+ fn validate_format ( & self , default_format_type : FormatType ) -> Result < ( ) , String > {
363+ let format_type = self . format_type . as_ref ( ) . unwrap_or ( & default_format_type) ;
364+ match ( & self . grouping_option , format_type) {
365+ (
366+ Some ( FormatGrouping :: Comma ) ,
367+ FormatType :: String
368+ | FormatType :: Character
369+ | FormatType :: Binary
370+ | FormatType :: Octal
371+ | FormatType :: HexLower
372+ | FormatType :: HexUpper
373+ | FormatType :: Number ,
374+ ) => {
375+ let ch = char:: from ( format_type) ;
376+ Err ( format ! ( "Cannot specify ',' with '{}'." , ch) )
377+ }
378+ (
379+ Some ( FormatGrouping :: Underscore ) ,
380+ FormatType :: String | FormatType :: Character | FormatType :: Number ,
381+ ) => {
382+ let ch = char:: from ( format_type) ;
383+ Err ( format ! ( "Cannot specify '_' with '{}'." , ch) )
384+ }
385+ _ => Ok ( ( ) ) ,
386+ }
387+ }
388+
340389 fn get_separator_interval ( & self ) -> usize {
341390 match self . format_type {
342391 Some ( FormatType :: Binary ) => 4 ,
@@ -467,14 +516,15 @@ impl FormatSpec {
467516 }
468517
469518 #[ inline]
470- fn format_int_radix ( & self , magnitude : BigInt , radix : u32 ) -> Result < String , & ' static str > {
519+ fn format_int_radix ( & self , magnitude : BigInt , radix : u32 ) -> Result < String , String > {
471520 match self . precision {
472- Some ( _) => Err ( "Precision not allowed in integer format specifier" ) ,
521+ Some ( _) => Err ( "Precision not allowed in integer format specifier" . to_owned ( ) ) ,
473522 None => Ok ( magnitude. to_str_radix ( radix) ) ,
474523 }
475524 }
476525
477- pub fn format_int ( & self , num : & BigInt ) -> Result < String , & ' static str > {
526+ pub fn format_int ( & self , num : & BigInt ) -> Result < String , String > {
527+ self . validate_format ( FormatType :: Decimal ) ?;
478528 let magnitude = num. abs ( ) ;
479529 let prefix = if self . alternate_form {
480530 match self . format_type {
@@ -487,30 +537,34 @@ impl FormatSpec {
487537 } else {
488538 ""
489539 } ;
490- let raw_magnitude_str: Result < String , & ' static str > = match self . format_type {
540+ let raw_magnitude_str: Result < String , String > = match self . format_type {
491541 Some ( FormatType :: Binary ) => self . format_int_radix ( magnitude, 2 ) ,
492542 Some ( FormatType :: Decimal ) => self . format_int_radix ( magnitude, 10 ) ,
493543 Some ( FormatType :: Octal ) => self . format_int_radix ( magnitude, 8 ) ,
494544 Some ( FormatType :: HexLower ) => self . format_int_radix ( magnitude, 16 ) ,
495545 Some ( FormatType :: HexUpper ) => match self . precision {
496- Some ( _) => Err ( "Precision not allowed in integer format specifier" ) ,
546+ Some ( _) => Err ( "Precision not allowed in integer format specifier" . to_owned ( ) ) ,
497547 None => {
498548 let mut result = magnitude. to_str_radix ( 16 ) ;
499549 result. make_ascii_uppercase ( ) ;
500550 Ok ( result)
501551 }
502552 } ,
503553 Some ( FormatType :: Number ) => self . format_int_radix ( magnitude, 10 ) ,
504- Some ( FormatType :: String ) => Err ( "Unknown format code 's' for object of type 'int'" ) ,
554+ Some ( FormatType :: String ) => {
555+ Err ( "Unknown format code 's' for object of type 'int'" . to_owned ( ) )
556+ }
505557 Some ( FormatType :: Character ) => match ( self . sign , self . alternate_form ) {
506- ( Some ( _) , _) => Err ( "Sign not allowed with integer format specifier 'c'" ) ,
507- ( _, true ) => {
508- Err ( "Alternate form (#) not allowed with integer format specifier 'c'" )
558+ ( Some ( _) , _) => {
559+ Err ( "Sign not allowed with integer format specifier 'c'" . to_owned ( ) )
509560 }
561+ ( _, true ) => Err (
562+ "Alternate form (#) not allowed with integer format specifier 'c'" . to_owned ( ) ,
563+ ) ,
510564 ( _, _) => match num. to_u32 ( ) {
511565 Some ( n) if n <= 0x10ffff => Ok ( std:: char:: from_u32 ( n) . unwrap ( ) . to_string ( ) ) ,
512566 // TODO: raise OverflowError
513- Some ( _) | None => Err ( "%c arg not in range(0x110000)" ) ,
567+ Some ( _) | None => Err ( "%c arg not in range(0x110000)" . to_owned ( ) ) ,
514568 } ,
515569 } ,
516570 Some ( FormatType :: GeneralFormatUpper )
@@ -520,8 +574,8 @@ impl FormatSpec {
520574 | Some ( FormatType :: ExponentUpper )
521575 | Some ( FormatType :: ExponentLower )
522576 | Some ( FormatType :: Percentage ) => match num. to_f64 ( ) {
523- Some ( float) => return self . format_float ( float) ,
524- _ => Err ( "Unable to convert int to float" ) ,
577+ Some ( float) => return self . format_float ( float) . map_err ( |msg| msg . to_owned ( ) ) ,
578+ _ => Err ( "Unable to convert int to float" . to_owned ( ) ) ,
525579 } ,
526580 None => self . format_int_radix ( magnitude, 10 ) ,
527581 } ;
@@ -537,6 +591,7 @@ impl FormatSpec {
537591 let sign_prefix = format ! ( "{}{}" , sign_str, prefix) ;
538592 let magnitude_str = self . add_magnitude_separators ( raw_magnitude_str?, & sign_prefix) ;
539593 self . format_sign_and_align ( & magnitude_str, & sign_prefix, FormatAlign :: Right )
594+ . map_err ( |msg| msg. to_owned ( ) )
540595 }
541596
542597 pub fn format_string ( & self , s : & str ) -> Result < String , & ' static str > {
0 commit comments