33// For the full copyright and license information, please view the LICENSE
44// file that was distributed with this source code.
55
6+ use super :: FormatError ;
67use crate :: {
7- error:: { set_exit_code, UResult , USimpleError } ,
8+ error:: { set_exit_code, UError } ,
89 features:: format:: num_parser:: { ParseError , ParsedNumber } ,
910 quoting_style:: { escape_name, Quotes , QuotingStyle } ,
10- show , show_error, show_warning,
11+ show_error, show_warning,
1112} ;
1213use os_display:: Quotable ;
13- use std:: ffi:: { OsStr , OsString } ;
14+ use std:: {
15+ error:: Error ,
16+ ffi:: { OsStr , OsString } ,
17+ fmt:: Display ,
18+ } ;
1419
1520/// An argument for formatting
1621///
@@ -31,70 +36,70 @@ pub enum FormatArgument {
3136}
3237
3338pub trait ArgumentIter < ' a > : Iterator < Item = & ' a FormatArgument > {
34- fn get_char ( & mut self ) -> u8 ;
35- fn get_i64 ( & mut self ) -> i64 ;
36- fn get_u64 ( & mut self ) -> u64 ;
37- fn get_f64 ( & mut self ) -> f64 ;
39+ fn get_char ( & mut self ) -> Result < u8 , FormatError > ;
40+ fn get_i64 ( & mut self ) -> Result < i64 , FormatError > ;
41+ fn get_u64 ( & mut self ) -> Result < u64 , FormatError > ;
42+ fn get_f64 ( & mut self ) -> Result < f64 , FormatError > ;
3843 fn get_str ( & mut self ) -> & ' a OsStr ;
3944}
4045
4146impl < ' a , T : Iterator < Item = & ' a FormatArgument > > ArgumentIter < ' a > for T {
42- fn get_char ( & mut self ) -> u8 {
47+ fn get_char ( & mut self ) -> Result < u8 , FormatError > {
4348 let Some ( next) = self . next ( ) else {
44- return b'\0' ;
49+ return Ok ( b'\0' ) ;
4550 } ;
4651 match next {
47- FormatArgument :: Char ( c) => * c as u8 ,
48- FormatArgument :: Unparsed ( os) => match bytes_from_os_str ( os) . unwrap ( ) . first ( ) {
49- Some ( & byte) => byte,
50- None => b'\0' ,
52+ FormatArgument :: Char ( c) => Ok ( * c as u8 ) ,
53+ FormatArgument :: Unparsed ( os) => match try_get_bytes_from_os_str ( os) ? . first ( ) {
54+ Some ( & byte) => Ok ( byte) ,
55+ None => Ok ( b'\0' ) ,
5156 } ,
52- _ => b'\0' ,
57+ _ => Ok ( b'\0' ) ,
5358 }
5459 }
5560
56- fn get_u64 ( & mut self ) -> u64 {
61+ fn get_u64 ( & mut self ) -> Result < u64 , FormatError > {
5762 let Some ( next) = self . next ( ) else {
58- return 0 ;
63+ return Ok ( 0 ) ;
5964 } ;
6065 match next {
61- FormatArgument :: UnsignedInt ( n) => * n ,
66+ FormatArgument :: UnsignedInt ( n) => Ok ( * n ) ,
6267 FormatArgument :: Unparsed ( os) => {
63- let str = get_str_or_exit_with_error ( os) ;
68+ let str = try_get_str_from_os_str ( os) ? ;
6469
65- extract_value ( ParsedNumber :: parse_u64 ( str) , str)
70+ Ok ( extract_value ( ParsedNumber :: parse_u64 ( str) , str) )
6671 }
67- _ => 0 ,
72+ _ => Ok ( 0 ) ,
6873 }
6974 }
7075
71- fn get_i64 ( & mut self ) -> i64 {
76+ fn get_i64 ( & mut self ) -> Result < i64 , FormatError > {
7277 let Some ( next) = self . next ( ) else {
73- return 0 ;
78+ return Ok ( 0 ) ;
7479 } ;
7580 match next {
76- FormatArgument :: SignedInt ( n) => * n ,
81+ FormatArgument :: SignedInt ( n) => Ok ( * n ) ,
7782 FormatArgument :: Unparsed ( os) => {
78- let str = get_str_or_exit_with_error ( os) ;
83+ let str = try_get_str_from_os_str ( os) ? ;
7984
80- extract_value ( ParsedNumber :: parse_i64 ( str) , str)
85+ Ok ( extract_value ( ParsedNumber :: parse_i64 ( str) , str) )
8186 }
82- _ => 0 ,
87+ _ => Ok ( 0 ) ,
8388 }
8489 }
8590
86- fn get_f64 ( & mut self ) -> f64 {
91+ fn get_f64 ( & mut self ) -> Result < f64 , FormatError > {
8792 let Some ( next) = self . next ( ) else {
88- return 0.0 ;
93+ return Ok ( 0.0 ) ;
8994 } ;
9095 match next {
91- FormatArgument :: Float ( n) => * n ,
96+ FormatArgument :: Float ( n) => Ok ( * n ) ,
9297 FormatArgument :: Unparsed ( os) => {
93- let str = get_str_or_exit_with_error ( os) ;
98+ let str = try_get_str_from_os_str ( os) ? ;
9499
95- extract_value ( ParsedNumber :: parse_f64 ( str) , str)
100+ Ok ( extract_value ( ParsedNumber :: parse_f64 ( str) , str) )
96101 }
97- _ => 0.0 ,
102+ _ => Ok ( 0.0 ) ,
98103 }
99104 }
100105
@@ -135,14 +140,41 @@ fn extract_value<T: Default>(p: Result<T, ParseError<'_, T>>, input: &str) -> T
135140 } else {
136141 show_error ! ( "{}: value not completely converted" , input. quote( ) ) ;
137142 }
143+
138144 v
139145 }
140146 }
141147 }
142148 }
143149}
144150
145- pub fn bytes_from_os_str ( input : & OsStr ) -> UResult < & [ u8 ] > {
151+ #[ derive( Debug ) ]
152+ pub struct NonUtf8OsStr ( pub String ) ;
153+
154+ impl Display for NonUtf8OsStr {
155+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
156+ f. write_fmt ( format_args ! (
157+ "invalid (non-UTF-8) string like {} encountered" ,
158+ self . 0 . quote( ) ,
159+ ) )
160+ }
161+ }
162+
163+ impl Error for NonUtf8OsStr { }
164+ impl UError for NonUtf8OsStr { }
165+
166+ pub fn try_get_str_from_os_str ( os_str : & OsStr ) -> Result < & str , NonUtf8OsStr > {
167+ match os_str. to_str ( ) {
168+ Some ( st) => Ok ( st) ,
169+ None => {
170+ let cow = os_str. to_string_lossy ( ) ;
171+
172+ Err ( NonUtf8OsStr ( cow. to_string ( ) ) )
173+ }
174+ }
175+ }
176+
177+ pub fn try_get_bytes_from_os_str ( input : & OsStr ) -> Result < & [ u8 ] , NonUtf8OsStr > {
146178 let result = {
147179 #[ cfg( target_family = "unix" ) ]
148180 {
@@ -153,38 +185,18 @@ pub fn bytes_from_os_str(input: &OsStr) -> UResult<&[u8]> {
153185
154186 #[ cfg( not( target_family = "unix" ) ) ]
155187 {
156- use crate :: error:: USimpleError ;
157-
158188 // TODO
159189 // Verify that this works correctly on these platforms
160190 match input. to_str ( ) . map ( |st| st. as_bytes ( ) ) {
161191 Some ( sl) => Ok ( sl) ,
162- None => Err ( USimpleError :: new (
163- 1 ,
164- "non-UTF-8 string encountered when not allowed" ,
165- ) ) ,
192+ None => {
193+ let cow = input. to_string_lossy ( ) ;
194+
195+ Err ( NonUtf8OsStr ( cow. to_string ( ) ) )
196+ }
166197 }
167198 }
168199 } ;
169200
170201 result
171202}
172-
173- fn get_str_or_exit_with_error ( os_str : & OsStr ) -> & str {
174- match os_str. to_str ( ) {
175- Some ( st) => st,
176- None => {
177- let cow = os_str. to_string_lossy ( ) ;
178-
179- let quoted = cow. quote ( ) ;
180-
181- let error = format ! (
182- "argument like {quoted} is not a valid UTF-8 string, and could not be parsed as an integer" ,
183- ) ;
184-
185- show ! ( USimpleError :: new( 1 , error. clone( ) ) ) ;
186-
187- panic ! ( "{error}" ) ;
188- }
189- }
190- }
0 commit comments