@@ -223,7 +223,7 @@ fn parse_fill_and_align(text: &str) -> (Option<char>, Option<FormatAlign>, &str)
223
223
}
224
224
}
225
225
226
- fn parse_number ( text : & str ) -> Result < ( Option < usize > , & str ) , & ' static str > {
226
+ fn parse_number ( text : & str ) -> Result < ( Option < usize > , & str ) , FormatSpecError > {
227
227
let num_digits: usize = get_num_digits ( text) ;
228
228
if num_digits == 0 {
229
229
return Ok ( ( None , text) ) ;
@@ -232,7 +232,7 @@ fn parse_number(text: &str) -> Result<(Option<usize>, &str), &'static str> {
232
232
Ok ( ( Some ( num) , & text[ num_digits..] ) )
233
233
} else {
234
234
// NOTE: this condition is different from CPython
235
- Err ( "Too many decimal digits in format string" )
235
+ Err ( FormatSpecError :: DecimalDigitsTooMany )
236
236
}
237
237
}
238
238
@@ -252,14 +252,14 @@ fn parse_zero(text: &str) -> (bool, &str) {
252
252
}
253
253
}
254
254
255
- fn parse_precision ( text : & str ) -> Result < ( Option < usize > , & str ) , & ' static str > {
255
+ fn parse_precision ( text : & str ) -> Result < ( Option < usize > , & str ) , FormatSpecError > {
256
256
let mut chars = text. chars ( ) ;
257
257
Ok ( match chars. next ( ) {
258
258
Some ( '.' ) => {
259
259
let ( size, remaining) = parse_number ( chars. as_str ( ) ) ?;
260
260
if let Some ( size) = size {
261
261
if size > i32:: MAX as usize {
262
- return Err ( "Precision too big" ) ;
262
+ return Err ( FormatSpecError :: PrecisionTooBig ) ;
263
263
}
264
264
( Some ( size) , remaining)
265
265
} else {
@@ -271,7 +271,7 @@ fn parse_precision(text: &str) -> Result<(Option<usize>, &str), &'static str> {
271
271
}
272
272
273
273
impl FormatSpec {
274
- pub fn parse ( text : & str ) -> Result < Self , String > {
274
+ pub fn parse ( text : & str ) -> Result < Self , FormatSpecError > {
275
275
// get_integer in CPython
276
276
let ( preconversor, text) = FormatPreconversor :: parse ( text) ;
277
277
let ( mut fill, mut align, text) = parse_fill_and_align ( text) ;
@@ -283,7 +283,7 @@ impl FormatSpec {
283
283
let ( precision, text) = parse_precision ( text) ?;
284
284
let ( format_type, text) = FormatType :: parse ( text) ;
285
285
if !text. is_empty ( ) {
286
- return Err ( "Invalid format specifier" . to_owned ( ) ) ;
286
+ return Err ( FormatSpecError :: InvalidFormatSpecifier ) ;
287
287
}
288
288
289
289
if zero && fill. is_none ( ) {
@@ -359,7 +359,7 @@ impl FormatSpec {
359
359
magnitude_str
360
360
}
361
361
362
- fn validate_format ( & self , default_format_type : FormatType ) -> Result < ( ) , String > {
362
+ fn validate_format ( & self , default_format_type : FormatType ) -> Result < ( ) , FormatSpecError > {
363
363
let format_type = self . format_type . as_ref ( ) . unwrap_or ( & default_format_type) ;
364
364
match ( & self . grouping_option , format_type) {
365
365
(
@@ -373,14 +373,14 @@ impl FormatSpec {
373
373
| FormatType :: Number ,
374
374
) => {
375
375
let ch = char:: from ( format_type) ;
376
- Err ( format ! ( "Cannot specify ',' with '{ch}'." ) )
376
+ Err ( FormatSpecError :: UnspecifiedFormat ( ',' , ch ) )
377
377
}
378
378
(
379
379
Some ( FormatGrouping :: Underscore ) ,
380
380
FormatType :: String | FormatType :: Character | FormatType :: Number ,
381
381
) => {
382
382
let ch = char:: from ( format_type) ;
383
- Err ( format ! ( "Cannot specify '_' with '{ch}'." ) )
383
+ Err ( FormatSpecError :: UnspecifiedFormat ( '_' , ch ) )
384
384
}
385
385
_ => Ok ( ( ) ) ,
386
386
}
@@ -422,11 +422,11 @@ impl FormatSpec {
422
422
}
423
423
}
424
424
425
- pub fn format_float ( & self , num : f64 ) -> Result < String , String > {
425
+ pub fn format_float ( & self , num : f64 ) -> Result < String , FormatSpecError > {
426
426
self . validate_format ( FormatType :: FixedPointLower ) ?;
427
427
let precision = self . precision . unwrap_or ( 6 ) ;
428
428
let magnitude = num. abs ( ) ;
429
- let raw_magnitude_str: Result < String , String > = match self . format_type {
429
+ let raw_magnitude_str: Result < String , FormatSpecError > = match self . format_type {
430
430
Some ( FormatType :: FixedPointUpper ) => Ok ( float_ops:: format_fixed (
431
431
precision,
432
432
magnitude,
@@ -445,13 +445,9 @@ impl FormatSpec {
445
445
| Some ( FormatType :: String )
446
446
| Some ( FormatType :: Character ) => {
447
447
let ch = char:: from ( self . format_type . as_ref ( ) . unwrap ( ) ) ;
448
- Err ( format ! (
449
- "Unknown format code '{ch}' for object of type 'float'" ,
450
- ) )
451
- }
452
- Some ( FormatType :: Number ) => {
453
- Err ( "Format code 'n' for object of type 'float' not implemented yet" . to_owned ( ) )
448
+ Err ( FormatSpecError :: UnknownFormatCode ( ch, "float" ) )
454
449
}
450
+ Some ( FormatType :: Number ) => Err ( FormatSpecError :: NotImplemented ( 'n' , "float" ) ) ,
455
451
Some ( FormatType :: GeneralFormatUpper ) => {
456
452
let precision = if precision == 0 { 1 } else { precision } ;
457
453
Ok ( float_ops:: format_general (
@@ -524,14 +520,14 @@ impl FormatSpec {
524
520
}
525
521
526
522
#[ inline]
527
- fn format_int_radix ( & self , magnitude : BigInt , radix : u32 ) -> Result < String , String > {
523
+ fn format_int_radix ( & self , magnitude : BigInt , radix : u32 ) -> Result < String , FormatSpecError > {
528
524
match self . precision {
529
- Some ( _) => Err ( "Precision not allowed in integer format specifier" . to_owned ( ) ) ,
525
+ Some ( _) => Err ( FormatSpecError :: PrecisionNotAllowed ) ,
530
526
None => Ok ( magnitude. to_str_radix ( radix) ) ,
531
527
}
532
528
}
533
529
534
- pub fn format_int ( & self , num : & BigInt ) -> Result < String , String > {
530
+ pub fn format_int ( & self , num : & BigInt ) -> Result < String , FormatSpecError > {
535
531
self . validate_format ( FormatType :: Decimal ) ?;
536
532
let magnitude = num. abs ( ) ;
537
533
let prefix = if self . alternate_form {
@@ -545,34 +541,27 @@ impl FormatSpec {
545
541
} else {
546
542
""
547
543
} ;
548
- let raw_magnitude_str: Result < String , String > = match self . format_type {
544
+ let raw_magnitude_str: Result < String , FormatSpecError > = match self . format_type {
549
545
Some ( FormatType :: Binary ) => self . format_int_radix ( magnitude, 2 ) ,
550
546
Some ( FormatType :: Decimal ) => self . format_int_radix ( magnitude, 10 ) ,
551
547
Some ( FormatType :: Octal ) => self . format_int_radix ( magnitude, 8 ) ,
552
548
Some ( FormatType :: HexLower ) => self . format_int_radix ( magnitude, 16 ) ,
553
549
Some ( FormatType :: HexUpper ) => match self . precision {
554
- Some ( _) => Err ( "Precision not allowed in integer format specifier" . to_owned ( ) ) ,
550
+ Some ( _) => Err ( FormatSpecError :: PrecisionNotAllowed ) ,
555
551
None => {
556
552
let mut result = magnitude. to_str_radix ( 16 ) ;
557
553
result. make_ascii_uppercase ( ) ;
558
554
Ok ( result)
559
555
}
560
556
} ,
561
557
Some ( FormatType :: Number ) => self . format_int_radix ( magnitude, 10 ) ,
562
- Some ( FormatType :: String ) => {
563
- Err ( "Unknown format code 's' for object of type 'int'" . to_owned ( ) )
564
- }
558
+ Some ( FormatType :: String ) => Err ( FormatSpecError :: UnknownFormatCode ( 's' , "int" ) ) ,
565
559
Some ( FormatType :: Character ) => match ( self . sign , self . alternate_form ) {
566
- ( Some ( _) , _) => {
567
- Err ( "Sign not allowed with integer format specifier 'c'" . to_owned ( ) )
568
- }
569
- ( _, true ) => Err (
570
- "Alternate form (#) not allowed with integer format specifier 'c'" . to_owned ( ) ,
571
- ) ,
560
+ ( Some ( _) , _) => Err ( FormatSpecError :: NotAllowed ( "Sign" ) ) ,
561
+ ( _, true ) => Err ( FormatSpecError :: NotAllowed ( "Alternate form (#)" ) ) ,
572
562
( _, _) => match num. to_u32 ( ) {
573
563
Some ( n) if n <= 0x10ffff => Ok ( std:: char:: from_u32 ( n) . unwrap ( ) . to_string ( ) ) ,
574
- // TODO: raise OverflowError
575
- Some ( _) | None => Err ( "%c arg not in range(0x110000)" . to_owned ( ) ) ,
564
+ Some ( _) | None => Err ( FormatSpecError :: CodeNotInRange ) ,
576
565
} ,
577
566
} ,
578
567
Some ( FormatType :: GeneralFormatUpper )
@@ -583,7 +572,7 @@ impl FormatSpec {
583
572
| Some ( FormatType :: ExponentLower )
584
573
| Some ( FormatType :: Percentage ) => match num. to_f64 ( ) {
585
574
Some ( float) => return self . format_float ( float) ,
586
- _ => Err ( "Unable to convert int to float" . to_owned ( ) ) ,
575
+ _ => Err ( FormatSpecError :: UnableToConvert ) ,
587
576
} ,
588
577
None => self . format_int_radix ( magnitude, 10 ) ,
589
578
} ;
@@ -605,7 +594,7 @@ impl FormatSpec {
605
594
)
606
595
}
607
596
608
- pub fn format_string ( & self , s : & BorrowedStr ) -> Result < String , String > {
597
+ pub fn format_string ( & self , s : & BorrowedStr ) -> Result < String , FormatSpecError > {
609
598
self . validate_format ( FormatType :: String ) ?;
610
599
match self . format_type {
611
600
Some ( FormatType :: String ) | None => self
@@ -618,9 +607,7 @@ impl FormatSpec {
618
607
} ) ,
619
608
_ => {
620
609
let ch = char:: from ( self . format_type . as_ref ( ) . unwrap ( ) ) ;
621
- Err ( format ! (
622
- "Unknown format code '{ch}' for object of type 'str'" ,
623
- ) )
610
+ Err ( FormatSpecError :: UnknownFormatCode ( ch, "str" ) )
624
611
}
625
612
}
626
613
}
@@ -630,7 +617,7 @@ impl FormatSpec {
630
617
magnitude_str : & BorrowedStr ,
631
618
sign_str : & str ,
632
619
default_align : FormatAlign ,
633
- ) -> Result < String , String > {
620
+ ) -> Result < String , FormatSpecError > {
634
621
let align = self . align . unwrap_or ( default_align) ;
635
622
636
623
let num_chars = magnitude_str. char_len ( ) ;
@@ -670,6 +657,20 @@ impl FormatSpec {
670
657
}
671
658
}
672
659
660
+ #[ derive( Debug , PartialEq ) ]
661
+ pub enum FormatSpecError {
662
+ DecimalDigitsTooMany ,
663
+ PrecisionTooBig ,
664
+ InvalidFormatSpecifier ,
665
+ UnspecifiedFormat ( char , char ) ,
666
+ UnknownFormatCode ( char , & ' static str ) ,
667
+ PrecisionNotAllowed ,
668
+ NotAllowed ( & ' static str ) ,
669
+ UnableToConvert ,
670
+ CodeNotInRange ,
671
+ NotImplemented ( char , & ' static str ) ,
672
+ }
673
+
673
674
#[ derive( Debug , PartialEq ) ]
674
675
pub enum FormatParseError {
675
676
UnmatchedBracket ,
@@ -683,7 +684,7 @@ pub enum FormatParseError {
683
684
}
684
685
685
686
impl FromStr for FormatSpec {
686
- type Err = String ;
687
+ type Err = FormatSpecError ;
687
688
fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
688
689
FormatSpec :: parse ( s)
689
690
}
@@ -1104,31 +1105,31 @@ mod tests {
1104
1105
fn test_format_invalid_specification ( ) {
1105
1106
assert_eq ! (
1106
1107
FormatSpec :: parse( "%3" ) ,
1107
- Err ( "Invalid format specifier" . to_owned ( ) )
1108
+ Err ( FormatSpecError :: InvalidFormatSpecifier )
1108
1109
) ;
1109
1110
assert_eq ! (
1110
1111
FormatSpec :: parse( ".2fa" ) ,
1111
- Err ( "Invalid format specifier" . to_owned ( ) )
1112
+ Err ( FormatSpecError :: InvalidFormatSpecifier )
1112
1113
) ;
1113
1114
assert_eq ! (
1114
1115
FormatSpec :: parse( "ds" ) ,
1115
- Err ( "Invalid format specifier" . to_owned ( ) )
1116
+ Err ( FormatSpecError :: InvalidFormatSpecifier )
1116
1117
) ;
1117
1118
assert_eq ! (
1118
1119
FormatSpec :: parse( "x+" ) ,
1119
- Err ( "Invalid format specifier" . to_owned ( ) )
1120
+ Err ( FormatSpecError :: InvalidFormatSpecifier )
1120
1121
) ;
1121
1122
assert_eq ! (
1122
1123
FormatSpec :: parse( "b4" ) ,
1123
- Err ( "Invalid format specifier" . to_owned ( ) )
1124
+ Err ( FormatSpecError :: InvalidFormatSpecifier )
1124
1125
) ;
1125
1126
assert_eq ! (
1126
1127
FormatSpec :: parse( "o!" ) ,
1127
- Err ( "Invalid format specifier" . to_owned ( ) )
1128
+ Err ( FormatSpecError :: InvalidFormatSpecifier )
1128
1129
) ;
1129
1130
assert_eq ! (
1130
1131
FormatSpec :: parse( "d " ) ,
1131
- Err ( "Invalid format specifier" . to_owned ( ) )
1132
+ Err ( FormatSpecError :: InvalidFormatSpecifier )
1132
1133
) ;
1133
1134
}
1134
1135
0 commit comments