@@ -30,6 +30,8 @@ use alloc::string::String;
3030use core:: borrow:: Borrow ;
3131use core:: fmt;
3232
33+ use fmt:: Write ;
34+
3335use super :: Case ;
3436#[ cfg( feature = "std" ) ]
3537use super :: Table ;
@@ -106,6 +108,48 @@ pub trait DisplayHex {
106108 fn hex_reserve_suggestion ( & self ) -> usize ;
107109}
108110
111+ /// Formats and writes a truncated hex slice directly into the stack buffer
112+ /// based on the requested precision limit and character case.
113+ struct TruncatedHexBuf {
114+ buf : [ u8 ; 1024 ] ,
115+ len : usize ,
116+ }
117+
118+ impl TruncatedHexBuf {
119+ fn new ( ) -> Self { Self { buf : [ 0 ; 1024 ] , len : 0 } }
120+
121+ fn as_str ( & self ) -> & str { core:: str:: from_utf8 ( & self . buf [ ..self . len ] ) . unwrap ( ) }
122+
123+ fn write_truncated_hex ( & mut self , bytes : & [ u8 ] , case : Case , max : usize ) -> fmt:: Result {
124+ let prefix_len = max / 2 ;
125+
126+ for & b in & bytes[ ..prefix_len] {
127+ let chars = case. table ( ) . byte_to_chars ( b) ;
128+ self . write_char ( chars[ 0 ] ) ?;
129+ self . write_char ( chars[ 1 ] ) ?;
130+ }
131+
132+ if max % 2 == 1 {
133+ let chars = case. table ( ) . byte_to_chars ( bytes[ prefix_len] ) ;
134+ self . write_char ( chars[ 0 ] ) ?;
135+ }
136+
137+ Ok ( ( ) )
138+ }
139+ }
140+
141+ impl fmt:: Write for TruncatedHexBuf {
142+ fn write_str ( & mut self , s : & str ) -> fmt:: Result {
143+ let bytes = s. as_bytes ( ) ;
144+ if self . len + bytes. len ( ) > self . buf . len ( ) {
145+ return Err ( fmt:: Error ) ;
146+ }
147+ self . buf [ self . len ..self . len + bytes. len ( ) ] . copy_from_slice ( bytes) ;
148+ self . len += bytes. len ( ) ;
149+ Ok ( ( ) )
150+ }
151+ }
152+
109153fn internal_display ( bytes : & [ u8 ] , f : & mut fmt:: Formatter , case : Case ) -> fmt:: Result {
110154 use fmt:: Write ;
111155 // There are at least two optimizations left:
@@ -123,10 +167,9 @@ fn internal_display(bytes: &[u8], f: &mut fmt::Formatter, case: Case) -> fmt::Re
123167 }
124168 match f. precision ( ) {
125169 Some ( max) if bytes. len ( ) > max / 2 => {
126- write ! ( f, "{}" , bytes[ ..( max / 2 ) ] . as_hex( ) ) ?;
127- if max % 2 == 1 {
128- f. write_char ( case. table ( ) . byte_to_chars ( bytes[ max / 2 ] ) [ 0 ] ) ?;
129- }
170+ let mut stack_str = TruncatedHexBuf :: new ( ) ;
171+ stack_str. write_truncated_hex ( bytes, case, max) ?;
172+ return f. pad ( stack_str. as_str ( ) ) ;
130173 }
131174 Some ( _) | None => {
132175 let mut chunks = bytes. chunks_exact ( 512 ) ;
@@ -918,6 +961,45 @@ mod tests {
918961 assert_eq ! ( bytes. to_upper_hex_string( ) , upper) ;
919962 assert_eq ! ( bytes. to_lower_hex_string( ) , lower) ;
920963 }
964+
965+ #[ test]
966+ fn upper_hex_precision_preserves_case ( ) {
967+ let bytes: [ u8 ; 4 ] = [ 0xab , 0xcd , 0xef , 0x12 ] ;
968+ let slice: & [ u8 ] = & bytes;
969+ assert_eq ! ( format!( "{:.4X}" , slice. as_hex( ) ) , "ABCD" ) ;
970+ assert_eq ! ( format!( "{:.5X}" , slice. as_hex( ) ) , "ABCDE" ) ;
971+ }
972+
973+ #[ test]
974+ fn lower_hex_precision_works_correctly_with_lowecase ( ) {
975+ let bytes: [ u8 ; 4 ] = [ 0xab , 0xcd , 0xef , 0x12 ] ;
976+ let slice: & [ u8 ] = & bytes;
977+ assert_eq ! ( format!( "{:.4x}" , slice. as_hex( ) ) , "abcd" ) ;
978+ assert_eq ! ( format!( "{:.5x}" , slice. as_hex( ) ) , "abcde" ) ;
979+ }
980+
981+ #[ test]
982+ fn hex_precision_extreme_boundaries ( ) {
983+ let bytes: [ u8 ; 2 ] = [ 0xaa , 0xbb ] ;
984+ let slice: & [ u8 ] = & bytes;
985+
986+ // zero precision
987+ assert_eq ! ( format!( "{:.0X}" , slice. as_hex( ) ) , "" ) ;
988+ assert_eq ! ( format!( "{:.0x}" , slice. as_hex( ) ) , "" ) ;
989+
990+ // 1-nibble precision (odd, edge case)
991+ assert_eq ! ( format!( "{:.1X}" , slice. as_hex( ) ) , "A" ) ;
992+ assert_eq ! ( format!( "{:.1x}" , slice. as_hex( ) ) , "a" ) ;
993+ }
994+
995+ #[ test]
996+ fn hex_precision_greater_than_length ( ) {
997+ let bytes: [ u8 ; 2 ] = [ 0xab , 0xcd ] ;
998+ let slice: & [ u8 ] = & bytes;
999+
1000+ assert_eq ! ( format!( "{:.10X}" , slice. as_hex( ) ) , "ABCD" ) ;
1001+ assert_eq ! ( format!( "{:.10x}" , slice. as_hex( ) ) , "abcd" ) ;
1002+ }
9211003 }
9221004
9231005 #[ cfg( feature = "std" ) ]
0 commit comments