microsoft/openvmm
Publicmirrored fromhttps://github.com/microsoft/openvmmAvailable
vm/hv1/vtl_array/src/lib.rs
229lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | //! Container data structures indexable by [`Vtl`]. |
| 5 | |
| 6 | #![no_std] |
| 7 | #![forbid(unsafe_code)] |
| 8 | #![warn(missing_docs)] |
| 9 | |
| 10 | use bitvec::array::BitArray; |
| 11 | use core::ops::Deref; |
| 12 | use core::ops::DerefMut; |
| 13 | use core::ops::Index; |
| 14 | use core::ops::IndexMut; |
| 15 | use hvdef::Vtl; |
| 16 | use inspect::Inspect; |
| 17 | |
| 18 | // TODO: Enforce N <= 3 on the type when stable |
| 19 | /// An array indexable by [`Vtl`]. |
| 20 | #[derive(Debug, Clone)] |
| 21 | pub struct VtlArray<T, const N: usize> { |
| 22 | data: [T; N], |
| 23 | } |
| 24 | |
| 25 | impl<T, const N: usize> VtlArray<T, N> { |
| 26 | /// Creates an array of type T, where each element is `value`. |
| 27 | pub const fn new(value: T) -> Self |
| 28 | where |
| 29 | T: Copy, |
| 30 | { |
| 31 | assert!(N > 0 && N <= 3); |
| 32 | Self { data: [value; N] } |
| 33 | } |
| 34 | |
| 35 | /// Creates an array of type T, where each element is |
| 36 | /// the returned value from `f` using that element’s index. |
| 37 | pub fn from_fn<F>(mut f: F) -> Self |
| 38 | where |
| 39 | F: FnMut(Vtl) -> T, |
| 40 | { |
| 41 | assert!(N > 0 && N <= 3); |
| 42 | Self { |
| 43 | data: core::array::from_fn(|i| f(Vtl::try_from(i as u8).unwrap())), |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | /// Maps over the vtl array using the raw underlying array. |
| 48 | pub fn map<U, F>(self, f: F) -> VtlArray<U, N> |
| 49 | where |
| 50 | F: FnMut(T) -> U, |
| 51 | { |
| 52 | VtlArray { |
| 53 | data: self.data.map(f), |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | /// Borrows each element and returns an array of references with the same |
| 58 | /// size as self. |
| 59 | pub fn each_ref(&self) -> VtlArray<&T, N> { |
| 60 | VtlArray { |
| 61 | data: self.data.each_ref(), |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | /// Borrows each element mutably and returns an array of mutable references |
| 66 | /// with the same size as self. |
| 67 | pub fn each_mut(&mut self) -> VtlArray<&mut T, N> { |
| 68 | VtlArray { |
| 69 | data: self.data.each_mut(), |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | /// Returns the raw underlying array. |
| 74 | pub fn into_inner(self) -> [T; N] { |
| 75 | self.data |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | impl<T> From<[T; 1]> for VtlArray<T, 1> { |
| 80 | fn from(a: [T; 1]) -> Self { |
| 81 | Self { data: a } |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | impl<T> From<[T; 2]> for VtlArray<T, 2> { |
| 86 | fn from(a: [T; 2]) -> Self { |
| 87 | Self { data: a } |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | impl<T> From<[T; 3]> for VtlArray<T, 3> { |
| 92 | fn from(a: [T; 3]) -> Self { |
| 93 | Self { data: a } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | impl<T, const N: usize> Inspect for VtlArray<T, N> |
| 98 | where |
| 99 | T: Inspect, |
| 100 | { |
| 101 | fn inspect(&self, req: inspect::Request<'_>) { |
| 102 | inspect::iter_by_index(&self.data).inspect(req) |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | impl<T, V: Into<Vtl>, const N: usize> Index<V> for VtlArray<T, N> { |
| 107 | type Output = T; |
| 108 | |
| 109 | fn index(&self, index: V) -> &Self::Output { |
| 110 | &self.data[index.into() as usize] |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | impl<T, V: Into<Vtl>, const N: usize> IndexMut<V> for VtlArray<T, N> { |
| 115 | fn index_mut(&mut self, index: V) -> &mut Self::Output { |
| 116 | &mut self.data[index.into() as usize] |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | impl<T, const N: usize> Deref for VtlArray<T, N> { |
| 121 | type Target = [T; N]; |
| 122 | |
| 123 | fn deref(&self) -> &Self::Target { |
| 124 | &self.data |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | impl<T, const N: usize> DerefMut for VtlArray<T, N> { |
| 129 | fn deref_mut(&mut self) -> &mut Self::Target { |
| 130 | &mut self.data |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | /// A set of [`Vtl`]s. |
| 135 | #[derive(Copy, Clone)] |
| 136 | pub struct VtlSet { |
| 137 | bits: BitArray<u16>, |
| 138 | } |
| 139 | |
| 140 | impl VtlSet { |
| 141 | /// Creates a new empty set. |
| 142 | pub fn new() -> Self { |
| 143 | Self { |
| 144 | bits: BitArray::new(0), |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | /// Adds a [`Vtl`] to the set. |
| 149 | pub fn set(&mut self, vtl: Vtl) { |
| 150 | self.bits.set(vtl as usize, true); |
| 151 | } |
| 152 | |
| 153 | /// Removes a [`Vtl`] from the set. |
| 154 | pub fn clear(&mut self, vtl: Vtl) { |
| 155 | self.bits.set(vtl as usize, false); |
| 156 | } |
| 157 | |
| 158 | /// Returns true if any [`Vtl`] in the set is higher than `vtl`. |
| 159 | pub fn is_higher_vtl_set_than(&self, vtl: Vtl) -> bool { |
| 160 | self.highest_set() > Some(vtl) |
| 161 | } |
| 162 | |
| 163 | /// Returns the highest set [`Vtl`] in the set, if any. |
| 164 | pub fn highest_set(&self) -> Option<Vtl> { |
| 165 | Some(Vtl::try_from(self.bits.last_one()? as u8).unwrap()) |
| 166 | } |
| 167 | |
| 168 | /// Returns true if the given [`Vtl`] is set. |
| 169 | pub fn is_set<V: Into<Vtl>>(&self, vtl: V) -> bool { |
| 170 | self.bits[vtl.into() as usize] |
| 171 | } |
| 172 | |
| 173 | /// Returns true if the given [`Vtl`] is not set. |
| 174 | pub fn is_clear<V: Into<Vtl>>(&self, vtl: V) -> bool { |
| 175 | !self.is_set(vtl) |
| 176 | } |
| 177 | |
| 178 | /// Returns an iterator over the set [`Vtl`]s, in order from highest to lowest. |
| 179 | pub fn iter_highest_first(&self) -> impl Iterator<Item = Vtl> + '_ { |
| 180 | self.bits |
| 181 | .iter_ones() |
| 182 | .rev() |
| 183 | .map(|i| Vtl::try_from(i as u8).unwrap()) |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | impl Inspect for VtlSet { |
| 188 | fn inspect(&self, req: inspect::Request<'_>) { |
| 189 | inspect::iter_by_index(self.bits.iter().map(|v| *v)).inspect(req) |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | impl From<u16> for VtlSet { |
| 194 | fn from(bits: u16) -> Self { |
| 195 | VtlSet { |
| 196 | bits: BitArray::new(bits), |
| 197 | } |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | #[cfg(test)] |
| 202 | mod tests { |
| 203 | use super::VtlSet; |
| 204 | use hvdef::Vtl; |
| 205 | |
| 206 | #[test] |
| 207 | fn test_vtlset() { |
| 208 | let mut set = VtlSet::new(); |
| 209 | assert_eq!(set.highest_set(), None); |
| 210 | set.set(Vtl::Vtl0); |
| 211 | assert_eq!(set.highest_set(), Some(Vtl::Vtl0)); |
| 212 | set.set(Vtl::Vtl2); |
| 213 | assert_eq!(set.highest_set(), Some(Vtl::Vtl2)); |
| 214 | |
| 215 | { |
| 216 | let mut iter = set.iter_highest_first(); |
| 217 | assert_eq!(iter.next(), Some(Vtl::Vtl2)); |
| 218 | assert_eq!(iter.next(), Some(Vtl::Vtl0)); |
| 219 | assert_eq!(iter.next(), None); |
| 220 | } |
| 221 | |
| 222 | assert!(!set.is_higher_vtl_set_than(Vtl::Vtl2)); |
| 223 | assert!(set.is_higher_vtl_set_than(Vtl::Vtl1)); |
| 224 | assert!(set.is_higher_vtl_set_than(Vtl::Vtl0)); |
| 225 | |
| 226 | set.clear(Vtl::Vtl2); |
| 227 | assert!(!set.is_higher_vtl_set_than(Vtl::Vtl0)); |
| 228 | } |
| 229 | } |
| 230 | |