@@ -6,7 +6,7 @@ mod traits;
66pub use traits:: { impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord} ;
77
88use crate :: borrow:: { Borrow , BorrowMut } ;
9- use crate :: fmt;
9+ use crate :: fmt:: { self , Alignment } ;
1010use crate :: ops:: { Deref , DerefMut , DerefPure } ;
1111
1212/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not
@@ -174,43 +174,85 @@ impl fmt::Debug for ByteStr {
174174#[ unstable( feature = "bstr" , issue = "134915" ) ]
175175impl fmt:: Display for ByteStr {
176176 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
177- let nchars: usize = self
178- . utf8_chunks ( )
179- . map ( |chunk| {
180- chunk. valid ( ) . chars ( ) . count ( ) + if chunk. invalid ( ) . is_empty ( ) { 0 } else { 1 }
181- } )
182- . sum ( ) ;
183-
184- let padding = f. width ( ) . unwrap_or ( 0 ) . saturating_sub ( nchars) ;
185- let fill = f. fill ( ) ;
186-
187- let ( lpad, rpad) = match f. align ( ) {
188- Some ( fmt:: Alignment :: Right ) => ( padding, 0 ) ,
189- Some ( fmt:: Alignment :: Center ) => {
190- let half = padding / 2 ;
191- ( half, half + padding % 2 )
177+ fn emit ( byte_str : & ByteStr , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
178+ for chunk in byte_str. utf8_chunks ( ) {
179+ f. write_str ( chunk. valid ( ) ) ?;
180+ if !chunk. invalid ( ) . is_empty ( ) {
181+ f. write_str ( "\u{FFFD} " ) ?;
182+ }
192183 }
193- // Either alignment is not specified or it's left aligned
194- // which behaves the same with padding
195- _ => ( 0 , padding) ,
196- } ;
197184
198- for _ in 0 ..lpad {
199- write ! ( f, "{fill}" ) ?;
185+ Ok ( ( ) )
200186 }
201187
202- for chunk in self . utf8_chunks ( ) {
203- f . write_str ( chunk . valid ( ) ) ? ;
204- if !chunk . invalid ( ) . is_empty ( ) {
205- f . write_str ( " \u{FFFD} " ) ? ;
206- }
188+ let requested_width = f . width ( ) . unwrap_or ( 0 ) ;
189+ if requested_width == 0 && f . precision ( ) . is_none ( ) {
190+ // Avoid counting the characters if no truncation or padding was
191+ // requested.
192+ return emit ( self , f ) ;
207193 }
208194
209- for _ in 0 ..rpad {
210- write ! ( f, "{fill}" ) ?;
211- }
195+ let ( truncated, actual_width) = match f. precision ( ) {
196+ // The entire string is truncated away. Weird, but ok.
197+ Some ( 0 ) => ( ByteStr :: new ( & [ ] ) , 0 ) ,
198+ // Advance through string until we run out of space.
199+ Some ( precision) => {
200+ let mut remaining_width = precision;
201+ let mut chunks = self . utf8_chunks ( ) ;
202+ let mut current_width = 0 ;
203+ let mut offset = 0 ;
204+ loop {
205+ let Some ( chunk) = chunks. next ( ) else {
206+ // We reached the end of the string without running out
207+ // of space, so print the entire string.
208+ break ( self , current_width) ;
209+ } ;
210+
211+ let mut chars = chunk. valid ( ) . char_indices ( ) ;
212+ let Err ( remaining) = chars. advance_by ( remaining_width) else {
213+ // We've counted off `precision` characters, so truncate
214+ // the string at the current offset.
215+ break ( & self [ ..offset + chars. offset ( ) ] , precision) ;
216+ } ;
217+
218+ offset += chunk. valid ( ) . len ( ) ;
219+ current_width += remaining_width - remaining. get ( ) ;
220+ remaining_width = remaining. get ( ) ;
221+
222+ // `remaining_width` cannot be zero, there is still space
223+ // remaining. So next, count the � character emitted for
224+ // the invalid chunk (if it exists).
225+ if !chunk. invalid ( ) . is_empty ( ) {
226+ offset += chunk. invalid ( ) . len ( ) ;
227+ current_width += 1 ;
228+ remaining_width -= 1 ;
229+
230+ if remaining_width == 0 {
231+ break ( & self [ ..offset] , precision) ;
232+ }
233+ }
234+ }
235+ }
236+ // The string shouldn't be truncated at all, so just count the number
237+ // of characters to calculate the padding.
238+ None => {
239+ let actual_width = self
240+ . utf8_chunks ( )
241+ . map ( |chunk| {
242+ chunk. valid ( ) . chars ( ) . count ( )
243+ + if chunk. invalid ( ) . is_empty ( ) { 0 } else { 1 }
244+ } )
245+ . sum ( ) ;
246+ ( self , actual_width)
247+ }
248+ } ;
212249
213- Ok ( ( ) )
250+ // The width is originally stored as a 16-bit number, so this cannot fail.
251+ let padding = u16:: try_from ( requested_width. saturating_sub ( actual_width) ) . unwrap ( ) ;
252+
253+ let post_padding = f. padding ( padding, Alignment :: Left ) ?;
254+ emit ( truncated, f) ?;
255+ post_padding. write ( f)
214256 }
215257}
216258
0 commit comments