patina/runtime_services/
variable_services.rs1use core::mem;
2
3use alloc::{vec, vec::Vec};
4use fallible_streaming_iterator::FallibleStreamingIterator;
5use r_efi::efi::{self, Guid};
6
7use super::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 prev_name = vec![0; 1];
96
97 prev_name
98 },
99 namespace: Guid::from_bytes(&[0x0; 16]),
102 },
103 next: VariableIdentifier { name: Vec::<u16>::new(), namespace: Guid::from_bytes(&[0x0; 16]) },
104 finished: false,
105 }
106 }
107
108 pub fn new_from_variable(name: &[u16], namespace: &efi::Guid, runtime_services: &'a R) -> Self {
110 Self {
111 rs: runtime_services,
112 current: VariableIdentifier { name: name.to_vec(), namespace: *namespace },
113 next: VariableIdentifier { name: Vec::<u16>::new(), namespace: Guid::from_bytes(&[0x0; 16]) },
114 finished: false,
115 }
116 }
117}
118
119impl<R: RuntimeServices> FallibleStreamingIterator for VariableNameIterator<'_, R> {
120 type Item = VariableIdentifier;
121 type Error = efi::Status;
122
123 fn advance(&mut self) -> Result<(), Self::Error> {
124 unsafe {
127 if self.finished {
129 return Ok(());
130 }
131
132 let status = self.rs.get_next_variable_name_unchecked(
133 &self.current.name,
134 &self.current.namespace,
135 &mut self.next.name,
136 &mut self.next.namespace,
137 );
138
139 mem::swap(&mut self.current, &mut self.next);
140
141 if status.is_err() && status.unwrap_err() == efi::Status::NOT_FOUND {
142 self.finished = true;
143 Ok(())
144 } else {
145 status
146 }
147 }
148 }
149
150 fn get(&self) -> Option<&Self::Item> {
151 if self.finished { None } else { Some(&self.current) }
152 }
153}
154
155#[cfg(test)]
156#[coverage(off)]
157mod test {
158 use r_efi::efi;
159
160 use super::*;
161 use crate::runtime_services::{
162 StandardRuntimeServices,
163 test::{
164 DUMMY_FIRST_NAME, DUMMY_FIRST_NAMESPACE, DUMMY_SECOND_NAME, DUMMY_SECOND_NAMESPACE,
165 mock_efi_get_next_variable_name, runtime_services,
166 },
167 };
168 use std::mem;
169
170 #[test]
171 fn test_variable_name_iterator_from_first() {
172 let rs = runtime_services!(get_next_variable_name = mock_efi_get_next_variable_name);
173
174 let mut iter = VariableNameIterator::new_from_first(&rs);
175
176 let mut status = iter.next();
178 assert!(status.is_ok());
179 assert!(status.unwrap().is_some());
180 let mut variable_identifier = status.unwrap().unwrap();
181 assert_eq!(variable_identifier.name, DUMMY_FIRST_NAME);
182 assert_eq!(variable_identifier.namespace, DUMMY_FIRST_NAMESPACE);
183
184 status = iter.next();
186 assert!(status.is_ok());
187 assert!(status.unwrap().is_some());
188 variable_identifier = status.unwrap().unwrap();
189 assert_eq!(variable_identifier.name, DUMMY_SECOND_NAME);
190 assert_eq!(variable_identifier.namespace, DUMMY_SECOND_NAMESPACE);
191
192 status = iter.next();
194 assert!(status.is_ok());
195 assert!(status.unwrap().is_none());
196 }
197
198 #[test]
199 fn test_variable_name_iterator_from_second() {
200 let rs = 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}