@@ -44,14 +44,14 @@ use std::path::PathBuf;
4444use std:: pin:: Pin ;
4545use std:: sync:: Arc ;
4646use std:: task:: { Context , Poll } ;
47+ use std:: time:: SystemTime ;
4748use tokio:: fs:: { File , OpenOptions } ;
4849use tokio:: io:: { AsyncRead , AsyncSeek , AsyncWrite , ReadBuf } ;
4950
5051#[ cfg( feature = "uuid" ) ]
5152use uuid:: Uuid ;
5253
53- #[ cfg( feature = "uuid" ) ]
54- const FILE_PREFIX : & ' static str = "atmp_" ;
54+ const FILE_PREFIX : & str = "atmp_" ;
5555
5656/// A named temporary file that will be cleaned automatically
5757/// after the last reference to it is dropped.
@@ -115,8 +115,6 @@ impl TempFile {
115115 /// # Ok::<(), Error>(())
116116 /// # });
117117 /// ```
118- #[ cfg_attr( docsrs, doc( cfg( feature = "uuid" ) ) ) ]
119- #[ cfg( feature = "uuid" ) ]
120118 pub async fn new ( ) -> Result < Self , Error > {
121119 Self :: new_in ( Self :: default_dir ( ) ) . await
122120 }
@@ -189,6 +187,11 @@ impl TempFile {
189187 /// Creates a new temporary file in the specified location.
190188 /// When the instance goes out of scope, the file will be deleted.
191189 ///
190+ /// ## Crate Features
191+ ///
192+ /// * `uuid` - When the `uuid` crate feature is enabled, a random UUIDv4 is used to
193+ /// generate the temporary file name.
194+ ///
192195 /// ## Arguments
193196 ///
194197 /// * `dir` - The directory to create the file in.
@@ -213,12 +216,18 @@ impl TempFile {
213216 /// assert!(fs::metadata(file_path).await.is_err());
214217 /// # Ok::<(), Error>(())
215218 /// # });
216- /// ```
217- #[ cfg_attr( docsrs, doc( cfg( feature = "uuid" ) ) ) ]
218- #[ cfg( feature = "uuid" ) ]
219219 pub async fn new_in < P : Borrow < PathBuf > > ( dir : P ) -> Result < Self , Error > {
220- let id = Uuid :: new_v4 ( ) ;
221- return Self :: new_with_uuid_in ( id, dir) . await ;
220+ #[ cfg( feature = "uuid" ) ]
221+ {
222+ let id = Uuid :: new_v4 ( ) ;
223+ Self :: new_with_uuid_in ( id, dir) . await
224+ }
225+
226+ #[ cfg( not( feature = "uuid" ) ) ]
227+ {
228+ let name = RandomName :: new ( ) ;
229+ Self :: new_with_name_in ( name, dir) . await
230+ }
222231 }
223232
224233 /// Creates a new temporary file in the specified location.
@@ -405,6 +414,40 @@ impl TempFile {
405414 }
406415}
407416
417+ /// Represents a randomly generated file name.
418+ struct RandomName {
419+ name : String ,
420+ }
421+
422+ impl RandomName {
423+ #[ allow( dead_code) ]
424+ fn new ( ) -> Self {
425+ let pid = std:: process:: id ( ) ;
426+
427+ // Using the address of a local variable for extra variation.
428+ let marker = & pid as * const _ as usize ;
429+
430+ // Current timestamp for added variation.
431+ let now = SystemTime :: now ( )
432+ . duration_since ( SystemTime :: UNIX_EPOCH )
433+ . unwrap_or ( std:: time:: Duration :: from_secs ( 0 ) ) ;
434+ let ( secs, subsec_nanos) = ( now. as_secs ( ) , now. subsec_nanos ( ) ) ;
435+
436+ Self {
437+ name : format ! (
438+ "{}{}{:x}{:x}{:x}" ,
439+ FILE_PREFIX , pid, marker, secs, subsec_nanos
440+ ) ,
441+ }
442+ }
443+ }
444+
445+ impl AsRef < str > for RandomName {
446+ fn as_ref ( & self ) -> & str {
447+ & self . name
448+ }
449+ }
450+
408451/// Ensures the file handles are closed before the core reference is freed.
409452/// If the core reference would be freed while handles are still open, it is
410453/// possible that the underlying file cannot be deleted.
@@ -535,3 +578,14 @@ impl AsyncSeek for TempFile {
535578 Pin :: new ( self . file . deref_mut ( ) ) . poll_complete ( cx)
536579 }
537580}
581+
582+ #[ cfg( test) ]
583+ mod tests {
584+ use super :: * ;
585+
586+ #[ test]
587+ fn test_random_name ( ) {
588+ let name = RandomName :: new ( ) ;
589+ assert ! ( name. as_ref( ) . starts_with( FILE_PREFIX ) )
590+ }
591+ }
0 commit comments