@@ -6,12 +6,13 @@ use std::{io, sync::Mutex};
6
6
#[ cfg( windows) ]
7
7
use winreg:: {
8
8
enums:: { HKEY_CURRENT_USER , KEY_READ , KEY_WRITE } ,
9
+ types:: { FromRegValue , ToRegValue } ,
9
10
RegKey , RegValue ,
10
11
} ;
11
12
12
13
#[ cfg( windows) ]
13
14
pub fn with_saved_path ( f : & mut dyn FnMut ( ) ) {
14
- with_saved_reg_value ( & RegKey :: predef ( HKEY_CURRENT_USER ) , "Environment" , "PATH" , f)
15
+ with_saved_reg_value ( & USER_PATH , f)
15
16
}
16
17
17
18
#[ cfg( unix) ]
@@ -21,41 +22,62 @@ pub fn with_saved_path(f: &mut dyn FnMut()) {
21
22
22
23
#[ cfg( windows) ]
23
24
pub fn get_path ( ) -> io:: Result < Option < RegValue > > {
24
- get_reg_value ( & RegKey :: predef ( HKEY_CURRENT_USER ) , "Environment" , "PATH" )
25
+ USER_PATH . get ( )
25
26
}
26
27
27
28
#[ cfg( windows) ]
28
- pub fn with_saved_reg_value ( root : & RegKey , subkey : & str , name : & str , f : & mut dyn FnMut ( ) ) {
29
+ pub fn with_saved_reg_value ( id : & RegistryValueId , f : & mut dyn FnMut ( ) ) {
29
30
// Lock protects concurrent mutation of registry
30
31
static LOCK : Mutex < ( ) > = Mutex :: new ( ( ) ) ;
31
32
let _g = LOCK . lock ( ) ;
32
33
33
34
// Save and restore the global state here to keep from trashing things.
34
- let saved_state = get_reg_value ( root, subkey, name)
35
+ let saved_state = id
36
+ . get ( )
35
37
. expect ( "Error getting global state: Better abort to avoid trashing it" ) ;
36
- let _g = scopeguard:: guard ( saved_state, |p| restore_reg_value ( root , subkey , name , p ) ) ;
38
+ let _g = scopeguard:: guard ( saved_state, |p| id . set ( p . as_ref ( ) ) . unwrap ( ) ) ;
37
39
38
40
f ( ) ;
39
41
}
40
42
41
43
#[ cfg( windows) ]
42
- fn get_reg_value ( root : & RegKey , subkey : & str , name : & str ) -> io:: Result < Option < RegValue > > {
43
- let subkey = root. open_subkey_with_flags ( subkey, KEY_READ | KEY_WRITE ) ?;
44
- match subkey. get_raw_value ( name) {
45
- Ok ( val) => Ok ( Some ( val) ) ,
46
- Err ( ref e) if e. kind ( ) == io:: ErrorKind :: NotFound => Ok ( None ) ,
47
- Err ( e) => Err ( e) ,
48
- }
44
+ const USER_PATH : RegistryValueId = RegistryValueId {
45
+ sub_key : "Environment" ,
46
+ value_name : "PATH" ,
47
+ } ;
48
+
49
+ #[ cfg( windows) ]
50
+ pub struct RegistryValueId {
51
+ pub sub_key : & ' static str ,
52
+ pub value_name : & ' static str ,
49
53
}
50
54
51
55
#[ cfg( windows) ]
52
- fn restore_reg_value ( root : & RegKey , subkey : & str , name : & str , p : Option < RegValue > ) {
53
- let subkey = root
54
- . open_subkey_with_flags ( subkey, KEY_READ | KEY_WRITE )
55
- . unwrap ( ) ;
56
- if let Some ( p) = p. as_ref ( ) {
57
- subkey. set_raw_value ( name, p) . unwrap ( ) ;
58
- } else {
59
- let _ = subkey. delete_value ( name) ;
56
+ impl RegistryValueId {
57
+ pub fn get_value < T : FromRegValue > ( & self ) -> io:: Result < Option < T > > {
58
+ self . get ( ) ?. map ( |v| T :: from_reg_value ( & v) ) . transpose ( )
59
+ }
60
+
61
+ pub fn get ( & self ) -> io:: Result < Option < RegValue > > {
62
+ let sub_key = RegKey :: predef ( HKEY_CURRENT_USER )
63
+ . open_subkey_with_flags ( self . sub_key , KEY_READ | KEY_WRITE ) ?;
64
+ match sub_key. get_raw_value ( self . value_name ) {
65
+ Ok ( val) => Ok ( Some ( val) ) ,
66
+ Err ( ref e) if e. kind ( ) == io:: ErrorKind :: NotFound => Ok ( None ) ,
67
+ Err ( e) => Err ( e) ,
68
+ }
69
+ }
70
+
71
+ pub fn set_value ( & self , new : Option < impl ToRegValue > ) -> io:: Result < ( ) > {
72
+ self . set ( new. map ( |s| s. to_reg_value ( ) ) . as_ref ( ) )
73
+ }
74
+
75
+ pub fn set ( & self , new : Option < & RegValue > ) -> io:: Result < ( ) > {
76
+ let sub_key = RegKey :: predef ( HKEY_CURRENT_USER )
77
+ . open_subkey_with_flags ( self . sub_key , KEY_READ | KEY_WRITE ) ?;
78
+ match new {
79
+ Some ( new) => sub_key. set_raw_value ( self . value_name , new) ,
80
+ None => sub_key. delete_value ( self . value_name ) ,
81
+ }
60
82
}
61
83
}
0 commit comments