@@ -17,30 +17,45 @@ use crate::{CStr16, Char16, Result, StatusExt};
17
17
#[ unsafe_protocol( ShellProtocol :: GUID ) ]
18
18
pub struct Shell ( ShellProtocol ) ;
19
19
20
+ /// Trait for implementing the var function
21
+ pub trait ShellVar {
22
+ /// Gets the value of the specified environment variable
23
+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > ;
24
+ }
25
+
20
26
/// Iterator over the names of environmental variables obtained from the Shell protocol.
21
27
#[ derive( Debug ) ]
22
- pub struct Vars < ' a > {
28
+ pub struct Vars < ' a , T : ShellVar > {
23
29
/// Char16 containing names of environment variables
24
- inner : * const Char16 ,
30
+ names : * const Char16 ,
31
+ /// Reference to Shell Protocol
32
+ protocol : * const T ,
25
33
/// Placeholder to attach a lifetime to `Vars`
26
34
placeholder : PhantomData < & ' a CStr16 > ,
27
35
}
28
36
29
- impl < ' a > Iterator for Vars < ' a > {
30
- type Item = & ' a CStr16 ;
37
+ impl < ' a , T : ShellVar + ' a > Iterator for Vars < ' a , T > {
38
+ type Item = ( & ' a CStr16 , Option < & ' a CStr16 > ) ;
31
39
// We iterate a list of NUL terminated CStr16s.
32
40
// The list is terminated with a double NUL.
33
41
fn next ( & mut self ) -> Option < Self :: Item > {
34
- let s = unsafe { CStr16 :: from_ptr ( self . inner ) } ;
42
+ let s = unsafe { CStr16 :: from_ptr ( self . names ) } ;
35
43
if s. is_empty ( ) {
36
44
None
37
45
} else {
38
- self . inner = unsafe { self . inner . add ( s. num_chars ( ) + 1 ) } ;
39
- Some ( s )
46
+ self . names = unsafe { self . names . add ( s. num_chars ( ) + 1 ) } ;
47
+ Some ( ( s , unsafe { self . protocol . as_ref ( ) . unwrap ( ) . var ( s ) } ) )
40
48
}
41
49
}
42
50
}
43
51
52
+ impl ShellVar for Shell {
53
+ /// Gets the value of the specified environment variable
54
+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > {
55
+ self . var ( name)
56
+ }
57
+ }
58
+
44
59
impl Shell {
45
60
/// Gets the value of the specified environment variable
46
61
///
@@ -67,10 +82,11 @@ impl Shell {
67
82
68
83
/// Gets an iterator over the names of all environment variables
69
84
#[ must_use]
70
- pub fn vars ( & self ) -> Vars < ' _ > {
85
+ pub fn vars ( & self ) -> Vars < ' _ , Self > {
71
86
let env_ptr = unsafe { ( self . 0 . get_env ) ( ptr:: null ( ) ) } ;
72
87
Vars {
73
- inner : env_ptr. cast :: < Char16 > ( ) ,
88
+ names : env_ptr. cast :: < Char16 > ( ) ,
89
+ protocol : self ,
74
90
placeholder : PhantomData ,
75
91
}
76
92
}
@@ -92,61 +108,38 @@ impl Shell {
92
108
let value_ptr: * const Char16 = value. as_ptr ( ) ;
93
109
unsafe { ( self . 0 . set_env ) ( name_ptr. cast ( ) , value_ptr. cast ( ) , volatile) } . to_result ( )
94
110
}
95
-
96
- /// Returns the current directory on the specified device
97
- ///
98
- /// # Arguments
99
- ///
100
- /// * `file_system_mapping` - The file system mapping for which to get
101
- /// the current directory
102
- ///
103
- /// # Returns
104
- ///
105
- /// * `Some(cwd)` - CStr16 containing the current working directory
106
- /// * `None` - Could not retrieve current directory
107
- #[ must_use]
108
- pub fn current_dir ( & self , file_system_mapping : Option < & CStr16 > ) -> Option < & CStr16 > {
109
- let mapping_ptr: * const Char16 = file_system_mapping. map_or ( ptr:: null ( ) , CStr16 :: as_ptr) ;
110
- let cur_dir = unsafe { ( self . 0 . get_cur_dir ) ( mapping_ptr. cast ( ) ) } ;
111
- if cur_dir. is_null ( ) {
112
- None
113
- } else {
114
- unsafe { Some ( CStr16 :: from_ptr ( cur_dir. cast ( ) ) ) }
115
- }
116
- }
117
-
118
- /// Changes the current directory on the specified device
119
- ///
120
- /// # Arguments
121
- ///
122
- /// * `file_system` - Pointer to the file system's mapped name.
123
- /// * `directory` - Points to the directory on the device specified by
124
- /// `file_system`.
125
- ///
126
- /// # Returns
127
- ///
128
- /// * `Status::SUCCESS` - The directory was successfully set
129
- ///
130
- /// # Errors
131
- ///
132
- /// * `Status::EFI_NOT_FOUND` - The directory does not exist
133
- pub fn set_current_dir (
134
- & self ,
135
- file_system : Option < & CStr16 > ,
136
- directory : Option < & CStr16 > ,
137
- ) -> Result {
138
- let fs_ptr: * const Char16 = file_system. map_or ( ptr:: null ( ) , |x| ( x. as_ptr ( ) ) ) ;
139
- let dir_ptr: * const Char16 = directory. map_or ( ptr:: null ( ) , |x| ( x. as_ptr ( ) ) ) ;
140
- unsafe { ( self . 0 . set_cur_dir ) ( fs_ptr. cast ( ) , dir_ptr. cast ( ) ) } . to_result ( )
141
- }
142
111
}
143
112
144
113
#[ cfg( test) ]
145
114
mod tests {
146
115
use super :: * ;
116
+ use alloc:: collections:: BTreeMap ;
147
117
use alloc:: vec:: Vec ;
148
118
use uefi:: cstr16;
149
119
120
+ struct ShellMock < ' a > {
121
+ inner : BTreeMap < & ' a CStr16 , & ' a CStr16 > ,
122
+ }
123
+
124
+ impl < ' a > ShellMock < ' a > {
125
+ fn new ( names : Vec < & ' a CStr16 > , values : Vec < & ' a CStr16 > ) -> ShellMock < ' a > {
126
+ let mut inner_map = BTreeMap :: new ( ) ;
127
+ for ( name, val) in names. iter ( ) . zip ( values. iter ( ) ) {
128
+ inner_map. insert ( * name, * val) ;
129
+ }
130
+ ShellMock { inner : inner_map }
131
+ }
132
+ }
133
+ impl < ' a > ShellVar for ShellMock < ' a > {
134
+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > {
135
+ if let Some ( val) = self . inner . get ( name) {
136
+ Some ( * val)
137
+ } else {
138
+ None
139
+ }
140
+ }
141
+ }
142
+
150
143
/// Testing Vars struct
151
144
#[ test]
152
145
fn test_vars ( ) {
@@ -155,9 +148,11 @@ mod tests {
155
148
vars_mock. push ( 0 ) ;
156
149
vars_mock. push ( 0 ) ;
157
150
let mut vars = Vars {
158
- inner : vars_mock. as_ptr ( ) . cast ( ) ,
151
+ names : vars_mock. as_ptr ( ) . cast ( ) ,
152
+ protocol : & ShellMock :: new ( Vec :: new ( ) , Vec :: new ( ) ) ,
159
153
placeholder : PhantomData ,
160
154
} ;
155
+
161
156
assert ! ( vars. next( ) . is_none( ) ) ;
162
157
163
158
// One environment variable in Vars
@@ -168,10 +163,14 @@ mod tests {
168
163
vars_mock. push ( 0 ) ;
169
164
vars_mock. push ( 0 ) ;
170
165
let vars = Vars {
171
- inner : vars_mock. as_ptr ( ) . cast ( ) ,
166
+ names : vars_mock. as_ptr ( ) . cast ( ) ,
167
+ protocol : & ShellMock :: new ( Vec :: from ( [ cstr16 ! ( "foo" ) ] ) , Vec :: from ( [ cstr16 ! ( "value" ) ] ) ) ,
172
168
placeholder : PhantomData ,
173
169
} ;
174
- assert_eq ! ( vars. collect:: <Vec <_>>( ) , Vec :: from( [ cstr16!( "foo" ) ] ) ) ;
170
+ assert_eq ! (
171
+ vars. collect:: <Vec <_>>( ) ,
172
+ Vec :: from( [ ( cstr16!( "foo" ) , Some ( cstr16!( "value" ) ) ) ] )
173
+ ) ;
175
174
176
175
// Multiple environment variables in Vars
177
176
let mut vars_mock = Vec :: < u16 > :: new ( ) ;
@@ -192,12 +191,20 @@ mod tests {
192
191
vars_mock. push ( 0 ) ;
193
192
194
193
let vars = Vars {
195
- inner : vars_mock. as_ptr ( ) . cast ( ) ,
194
+ names : vars_mock. as_ptr ( ) . cast ( ) ,
195
+ protocol : & ShellMock :: new (
196
+ Vec :: from ( [ cstr16 ! ( "foo1" ) , cstr16 ! ( "bar" ) , cstr16 ! ( "baz2" ) ] ) ,
197
+ Vec :: from ( [ cstr16 ! ( "value" ) , cstr16 ! ( "one" ) , cstr16 ! ( "two" ) ] ) ,
198
+ ) ,
196
199
placeholder : PhantomData ,
197
200
} ;
198
201
assert_eq ! (
199
202
vars. collect:: <Vec <_>>( ) ,
200
- Vec :: from( [ cstr16!( "foo1" ) , cstr16!( "bar" ) , cstr16!( "baz2" ) ] )
203
+ Vec :: from( [
204
+ ( cstr16!( "foo1" ) , Some ( cstr16!( "value" ) ) ) ,
205
+ ( cstr16!( "bar" ) , Some ( cstr16!( "one" ) ) ) ,
206
+ ( cstr16!( "baz2" ) , Some ( cstr16!( "two" ) ) )
207
+ ] )
201
208
) ;
202
209
}
203
210
}
0 commit comments