runtime_services/
variable_services.rs1use core::mem;
2
3use alloc::vec::Vec;
4use fallible_streaming_iterator::FallibleStreamingIterator;
5use r_efi::efi::{self, Guid};
6
7use crate::RuntimeServices;
8
9#[derive(Debug)]
11pub enum GetVariableStatus {
12 Error(efi::Status),
14 BufferTooSmall {
16 data_size: usize,
18 attributes: u32,
20 },
21 Success {
23 data_size: usize,
25 attributes: u32,
27 },
28}
29
30#[derive(Debug)]
32pub struct VariableInfo {
33 pub maximum_variable_storage_size: u64,
35 pub remaining_variable_storage_size: u64,
37 pub maximum_variable_size: u64,
39}
40
41#[derive(Debug)]
43pub struct VariableIdentifier {
44 name: Vec<u16>,
46 namespace: efi::Guid,
48}
49
50#[derive(Debug)]
79pub struct VariableNameIterator<'a, R: RuntimeServices> {
80 rs: &'a R,
81
82 current: VariableIdentifier,
83 next: VariableIdentifier,
84 finished: bool,
85}
86
87impl<'a, R: RuntimeServices> VariableNameIterator<'a, R> {
88 pub fn new_from_first(runtime_services: &'a R) -> Self {
90 Self {
91 rs: &runtime_services,
92 current: VariableIdentifier {
93 name: {
94 let mut prev_name = Vec::<u16>::with_capacity(1);
96 prev_name.resize(1, 0);
97
98 prev_name
99 },
100 namespace: Guid::from_bytes(&[0x0; 16]),
103 },
104 next: VariableIdentifier { name: Vec::<u16>::new(), namespace: Guid::from_bytes(&[0x0; 16]) },
105 finished: false,
106 }
107 }
108
109 pub fn new_from_variable(name: &[u16], namespace: &efi::Guid, runtime_services: &'a R) -> Self {
111 Self {
112 rs: &runtime_services,
113 current: VariableIdentifier { name: name.to_vec(), namespace: namespace.clone() },
114 next: VariableIdentifier { name: Vec::<u16>::new(), namespace: Guid::from_bytes(&[0x0; 16]) },
115 finished: false,
116 }
117 }
118}
119
120impl<'a, R: RuntimeServices> FallibleStreamingIterator for VariableNameIterator<'a, R> {
121 type Item = VariableIdentifier;
122 type Error = efi::Status;
123
124 fn advance(&mut self) -> Result<(), Self::Error> {
125 unsafe {
126 if self.finished {
128 return Ok(());
129 }
130
131 let status = self.rs.get_next_variable_name_unchecked(
132 &self.current.name,
133 &self.current.namespace,
134 &mut self.next.name,
135 &mut self.next.namespace,
136 );
137
138 mem::swap(&mut self.current, &mut self.next);
139
140 if status.is_err() && status.unwrap_err() == efi::Status::NOT_FOUND {
141 self.finished = true;
142 return Ok(());
143 } else {
144 return status;
145 }
146 }
147 }
148
149 fn get(&self) -> Option<&Self::Item> {
150 if self.finished {
151 None
152 } else {
153 Some(&self.current)
154 }
155 }
156}
157
158#[cfg(test)]
159mod test {
160 use efi;
161
162 use super::*;
163 use crate::StandardRuntimeServices;
164 use core::mem;
165
166 use crate::test::*;
167
168 #[test]
169 fn test_variable_name_iterator_from_first() {
170 let rs: &StandardRuntimeServices<'_> =
171 runtime_services!(get_next_variable_name = mock_efi_get_next_variable_name);
172
173 let mut iter = VariableNameIterator::new_from_first(rs);
174
175 let mut status = iter.next();
177 assert!(status.is_ok());
178 assert!(status.unwrap().is_some());
179 let mut variable_identifier = status.unwrap().unwrap();
180 assert_eq!(variable_identifier.name, DUMMY_FIRST_NAME);
181 assert_eq!(variable_identifier.namespace, DUMMY_FIRST_NAMESPACE);
182
183 status = iter.next();
185 assert!(status.is_ok());
186 assert!(status.unwrap().is_some());
187 variable_identifier = status.unwrap().unwrap();
188 assert_eq!(variable_identifier.name, DUMMY_SECOND_NAME);
189 assert_eq!(variable_identifier.namespace, DUMMY_SECOND_NAMESPACE);
190
191 status = iter.next();
193 assert!(status.is_ok());
194 assert!(status.unwrap().is_none());
195 }
196
197 #[test]
198 fn test_variable_name_iterator_from_second() {
199 let rs: &StandardRuntimeServices<'_> =
200 runtime_services!(get_next_variable_name = mock_efi_get_next_variable_name);
201
202 let mut iter = VariableNameIterator::new_from_variable(&DUMMY_FIRST_NAME, &DUMMY_FIRST_NAMESPACE, rs);
203
204 let mut status = iter.next();
206 assert!(status.is_ok());
207 assert!(status.unwrap().is_some());
208 let variable_identifier = status.unwrap().unwrap();
209 assert_eq!(variable_identifier.name, DUMMY_SECOND_NAME);
210 assert_eq!(variable_identifier.namespace, DUMMY_SECOND_NAMESPACE);
211
212 status = iter.next();
214 assert!(status.is_ok());
215 assert!(status.unwrap().is_none());
216 }
217}