22//!
33//! TODO: This whole scheme is still under development.
44
5+ #[ cfg( test) ]
56use camino:: Utf8PathBuf ;
67use cap_std:: fs_utf8:: Dir ;
8+ #[ cfg( test) ]
9+ use std:: env;
710use std:: ops:: Deref ;
8- use std:: { env, fmt, fs, io, mem} ;
9- #[ cfg( not( target_os = "emscripten" ) ) ]
10- use uuid:: Uuid ;
11+ use std:: { fmt, io, mem} ;
1112
1213#[ doc( hidden) ]
1314pub use cap_std:: ambient_authority_known_at_compile_time;
@@ -28,6 +29,13 @@ pub struct TempDir {
2829}
2930
3031impl TempDir {
32+ // Consume a base/non-UTF8 tempdir instance and return a UTF8 version
33+ fn from_cap_std ( mut td : super :: TempDir ) -> Self {
34+ // Take ownership of the underlying Dir instance
35+ let dir = td. dir . take ( ) . map ( Dir :: from_cap_std) ;
36+ Self { dir }
37+ }
38+
3139 /// Attempts to make a temporary directory inside of `env::temp_dir()`.
3240 ///
3341 /// This corresponds to [`tempfile::TempDir::new`].
@@ -39,27 +47,11 @@ impl TempDir {
3947 /// This function makes use of ambient authority to access temporary
4048 /// directories.
4149 pub fn new ( ambient_authority : AmbientAuthority ) -> io:: Result < Self > {
42- let system_tmp: Utf8PathBuf = env:: temp_dir ( )
43- . try_into ( )
44- . expect ( "temporary directory path should be valid UTF-8" ) ;
45- for _ in 0 ..Self :: num_iterations ( ) {
46- let name = system_tmp. join ( & Self :: new_name ( ) ) ;
47- match fs:: create_dir ( & name) {
48- Ok ( ( ) ) => {
49- let dir = match Dir :: open_ambient_dir ( & name, ambient_authority) {
50- Ok ( dir) => dir,
51- Err ( e) => {
52- fs:: remove_dir ( name) . ok ( ) ;
53- return Err ( e) ;
54- }
55- } ;
56- return Ok ( Self { dir : Some ( dir) } ) ;
57- }
58- Err ( e) if e. kind ( ) == io:: ErrorKind :: AlreadyExists => continue ,
59- Err ( e) => return Err ( e) ,
60- }
61- }
62- Err ( Self :: already_exists ( ) )
50+ // Because a Dir instance doesn't have a name accessible to the calling
51+ // code, we just delegate to the non-UTF8 base version. In some presumably
52+ // very unusual situations the tempdir may have a non-UTF8 name,
53+ // but that's fine.
54+ super :: TempDir :: new ( ambient_authority) . map ( Self :: from_cap_std)
6355 }
6456
6557 /// Create a new temporary directory.
@@ -68,24 +60,7 @@ impl TempDir {
6860 ///
6961 /// [`tempfile::TempDir::new_in`]: https://docs.rs/tempfile/latest/tempfile/fn.tempdir_in.html
7062 pub fn new_in ( dir : & Dir ) -> io:: Result < Self > {
71- for _ in 0 ..Self :: num_iterations ( ) {
72- let name = & Self :: new_name ( ) ;
73- match dir. create_dir ( name) {
74- Ok ( ( ) ) => {
75- let dir = match dir. open_dir ( name) {
76- Ok ( dir) => dir,
77- Err ( e) => {
78- dir. remove_dir ( name) . ok ( ) ;
79- return Err ( e) ;
80- }
81- } ;
82- return Ok ( Self { dir : Some ( dir) } ) ;
83- }
84- Err ( e) if e. kind ( ) == io:: ErrorKind :: AlreadyExists => continue ,
85- Err ( e) => return Err ( e) ,
86- }
87- }
88- Err ( Self :: already_exists ( ) )
63+ super :: TempDir :: new_in ( dir. as_cap_std ( ) ) . map ( Self :: from_cap_std)
8964 }
9065
9166 /// Closes and removes the temporary directory, returning a `Result`.
@@ -96,33 +71,6 @@ impl TempDir {
9671 pub fn close ( mut self ) -> io:: Result < ( ) > {
9772 mem:: take ( & mut self . dir ) . unwrap ( ) . remove_open_dir_all ( )
9873 }
99-
100- fn new_name ( ) -> String {
101- #[ cfg( not( target_os = "emscripten" ) ) ]
102- {
103- Uuid :: new_v4 ( ) . to_string ( )
104- }
105-
106- // Uuid doesn't support Emscripten yet, but Emscripten isn't multi-user
107- // or multi-process yet, so we can do something simple.
108- #[ cfg( target_os = "emscripten" ) ]
109- {
110- use rand:: RngCore ;
111- let mut r = rand:: thread_rng ( ) ;
112- format ! ( "cap-primitives.{}" , r. next_u32( ) )
113- }
114- }
115-
116- const fn num_iterations ( ) -> i32 {
117- i32:: MAX
118- }
119-
120- fn already_exists ( ) -> io:: Error {
121- io:: Error :: new (
122- io:: ErrorKind :: AlreadyExists ,
123- "too many temporary files exist" ,
124- )
125- }
12674}
12775
12876impl Deref for TempDir {
0 commit comments