88
99use crate :: backend:: fd:: { AsFd , AsRawFd } ;
1010use crate :: ffi:: CStr ;
11- use core:: fmt :: Write ;
11+ use core:: mem :: { self , MaybeUninit } ;
1212use itoa:: { Buffer , Integer } ;
1313#[ cfg( all( feature = "std" , unix) ) ]
1414use std:: os:: unix:: ffi:: OsStrExt ;
@@ -36,23 +36,36 @@ use {core::fmt, std::ffi::OsStr, std::path::Path};
3636/// ```
3737#[ derive( Clone ) ]
3838pub struct DecInt {
39- // 20 `u8`s is enough to hold the decimal ASCII representation of any
40- // `u64`, and we add one for a NUL terminator for `as_c_str`.
41- buf : [ u8 ; 20 + 1 ] ,
39+ // Enough to hold an {u,i}64 and NUL terminator.
40+ buf : [ MaybeUninit < u8 > ; u64:: MAX_STR_LEN + 1 ] ,
4241 len : usize ,
4342}
43+ const _: ( ) = assert ! ( u64 :: MAX_STR_LEN == i64 :: MAX_STR_LEN ) ;
4444
4545impl DecInt {
4646 /// Construct a new path component from an integer.
4747 #[ inline]
48- pub fn new < Int : Integer > ( i : Int ) -> Self {
49- let mut me = DecIntWriter ( Self {
50- buf : [ 0 ; 20 + 1 ] ,
51- len : 0 ,
48+ pub fn new < Int : Integer + ' static > ( i : Int ) -> Self {
49+ let mut buf = [ MaybeUninit :: uninit ( ) ; 21 ] ;
50+
51+ let mut str_buf = Buffer :: new ( ) ;
52+ let str_buf = str_buf. format ( i) ;
53+ assert ! (
54+ str_buf. len( ) < buf. len( ) ,
55+ "{str_buf}{} unsupported." ,
56+ core:: any:: type_name:: <Int >( )
57+ ) ;
58+
59+ buf[ ..str_buf. len ( ) ] . copy_from_slice ( unsafe {
60+ // SAFETY: you can always go from init to uninit
61+ mem:: transmute :: < & [ u8 ] , & [ MaybeUninit < u8 > ] > ( str_buf. as_bytes ( ) )
5262 } ) ;
53- let mut buf = Buffer :: new ( ) ;
54- me. write_str ( buf. format ( i) ) . unwrap ( ) ;
55- me. 0
63+ buf[ str_buf. len ( ) ] = MaybeUninit :: new ( 0 ) ;
64+
65+ Self {
66+ buf,
67+ len : str_buf. len ( ) ,
68+ }
5669 }
5770
5871 /// Construct a new path component from a file descriptor.
@@ -72,44 +85,35 @@ impl DecInt {
7285 /// Return the raw byte buffer as a `&CStr`.
7386 #[ inline]
7487 pub fn as_c_str ( & self ) -> & CStr {
75- let bytes_with_nul = & self . buf [ ..= self . len ] ;
88+ let bytes_with_nul = self . as_bytes_with_nul ( ) ;
7689 debug_assert ! ( CStr :: from_bytes_with_nul( bytes_with_nul) . is_ok( ) ) ;
7790
7891 // SAFETY: `self.buf` holds a single decimal ASCII representation and
7992 // at least one extra NUL byte.
8093 unsafe { CStr :: from_bytes_with_nul_unchecked ( bytes_with_nul) }
8194 }
8295
83- /// Return the raw byte buffer.
96+ /// Return the raw byte buffer including the NUL byte .
8497 #[ inline]
85- pub fn as_bytes ( & self ) -> & [ u8 ] {
86- & self . buf [ ..self . len ]
98+ pub fn as_bytes_with_nul ( & self ) -> & [ u8 ] {
99+ let init = & self . buf [ ..=self . len ] ;
100+ // SAFETY: we're guaranteed to have initialized len+1 bytes.
101+ unsafe { mem:: transmute :: < & [ MaybeUninit < u8 > ] , & [ u8 ] > ( init) }
87102 }
88- }
89-
90- /// A wrapper around `DecInt` that implements `Write` without exposing this
91- /// implementation to `DecInt`'s public API.
92- struct DecIntWriter ( DecInt ) ;
93103
94- impl core :: fmt :: Write for DecIntWriter {
104+ /// Return the raw byte buffer.
95105 #[ inline]
96- fn write_str ( & mut self , s : & str ) -> core:: fmt:: Result {
97- match self . 0 . buf . get_mut ( self . 0 . len ..self . 0 . len + s. len ( ) ) {
98- Some ( slice) => {
99- slice. copy_from_slice ( s. as_bytes ( ) ) ;
100- self . 0 . len += s. len ( ) ;
101- Ok ( ( ) )
102- }
103- None => Err ( core:: fmt:: Error ) ,
104- }
106+ pub fn as_bytes ( & self ) -> & [ u8 ] {
107+ let bytes = self . as_bytes_with_nul ( ) ;
108+ & bytes[ ..bytes. len ( ) - 1 ]
105109 }
106110}
107111
108112#[ cfg( feature = "std" ) ]
109113impl AsRef < Path > for DecInt {
110114 #[ inline]
111115 fn as_ref ( & self ) -> & Path {
112- let as_os_str: & OsStr = OsStrExt :: from_bytes ( & self . buf [ .. self . len ] ) ;
116+ let as_os_str: & OsStr = OsStrExt :: from_bytes ( self . as_bytes ( ) ) ;
113117 Path :: new ( as_os_str)
114118 }
115119}
0 commit comments