Nothing to see here, move along meow
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.1 kB View raw
1pub const MAX_HANDLES_PER_CLIENT: usize = 64; 2 3#[derive(Debug, Clone, Copy, PartialEq, Eq)] 4pub struct VfsHandleMapping { 5 pub mount_id: u8, 6 pub backend_handle: u8, 7} 8 9pub struct VfsHandleTable { 10 entries: [Option<VfsHandleMapping>; MAX_HANDLES_PER_CLIENT], 11} 12 13impl Default for VfsHandleTable { 14 fn default() -> Self { 15 Self::new() 16 } 17} 18 19impl VfsHandleTable { 20 pub const fn new() -> Self { 21 Self { 22 entries: [None; MAX_HANDLES_PER_CLIENT], 23 } 24 } 25 26 pub fn allocate(&mut self, mount_id: u8, backend_handle: u8) -> Option<u8> { 27 let slot = self.entries.iter().position(|e| e.is_none())?; 28 self.entries[slot] = Some(VfsHandleMapping { 29 mount_id, 30 backend_handle, 31 }); 32 Some(slot as u8) 33 } 34 35 pub fn get(&self, handle: u8) -> Option<VfsHandleMapping> { 36 self.entries.get(handle as usize).copied().flatten() 37 } 38 39 pub fn release(&mut self, handle: u8) -> bool { 40 self.entries 41 .get_mut(handle as usize) 42 .and_then(|slot| slot.take()) 43 .is_some() 44 } 45 46 pub fn resolve(&self, handle: u8) -> Option<(u8, u8)> { 47 self.get(handle).map(|m| (m.mount_id, m.backend_handle)) 48 } 49 50 pub fn active_count(&self) -> usize { 51 self.entries.iter().filter(|e| e.is_some()).count() 52 } 53} 54 55#[cfg(test)] 56mod tests { 57 use super::*; 58 59 #[test] 60 fn allocate_returns_sequential_handles() { 61 let mut table = VfsHandleTable::new(); 62 assert_eq!(table.allocate(0, 10), Some(0)); 63 assert_eq!(table.allocate(0, 11), Some(1)); 64 assert_eq!(table.allocate(1, 20), Some(2)); 65 } 66 67 #[test] 68 fn get_returns_mapping() { 69 let mut table = VfsHandleTable::new(); 70 table.allocate(3, 7); 71 let mapping = table.get(0).unwrap(); 72 assert_eq!(mapping.mount_id, 3); 73 assert_eq!(mapping.backend_handle, 7); 74 } 75 76 #[test] 77 fn get_returns_none_for_unoccupied() { 78 let table = VfsHandleTable::new(); 79 assert!(table.get(0).is_none()); 80 } 81 82 #[test] 83 fn get_returns_none_for_out_of_bounds() { 84 let table = VfsHandleTable::new(); 85 assert!(table.get(255).is_none()); 86 } 87 88 #[test] 89 fn release_frees_slot_for_reuse() { 90 let mut table = VfsHandleTable::new(); 91 let h = table.allocate(0, 10).unwrap(); 92 assert!(table.release(h)); 93 assert!(table.get(h).is_none()); 94 let reused = table.allocate(1, 20).unwrap(); 95 assert_eq!(reused, 0); 96 } 97 98 #[test] 99 fn release_unoccupied_returns_false() { 100 let mut table = VfsHandleTable::new(); 101 assert!(!table.release(0)); 102 } 103 104 #[test] 105 fn resolve_returns_mount_and_backend() { 106 let mut table = VfsHandleTable::new(); 107 table.allocate(3, 7); 108 assert_eq!(table.resolve(0), Some((3, 7))); 109 } 110 111 #[test] 112 fn resolve_returns_none_for_empty() { 113 let table = VfsHandleTable::new(); 114 assert_eq!(table.resolve(5), None); 115 } 116 117 #[test] 118 fn exhaustion_returns_none() { 119 let mut table = VfsHandleTable::new(); 120 (0..MAX_HANDLES_PER_CLIENT).for_each(|i| { 121 assert!(table.allocate(0, i as u8).is_some()); 122 }); 123 assert!(table.allocate(0, 99).is_none()); 124 } 125 126 #[test] 127 fn active_count_tracks_occupancy() { 128 let mut table = VfsHandleTable::new(); 129 assert_eq!(table.active_count(), 0); 130 table.allocate(0, 1); 131 table.allocate(0, 2); 132 assert_eq!(table.active_count(), 2); 133 table.release(0); 134 assert_eq!(table.active_count(), 1); 135 } 136 137 #[test] 138 fn handles_across_mounts() { 139 let mut table = VfsHandleTable::new(); 140 let h0 = table.allocate(0, 5).unwrap(); 141 let h1 = table.allocate(1, 10).unwrap(); 142 let h2 = table.allocate(0, 15).unwrap(); 143 144 let (m0, b0) = table.resolve(h0).unwrap(); 145 let (m1, b1) = table.resolve(h1).unwrap(); 146 let (m2, b2) = table.resolve(h2).unwrap(); 147 148 assert_eq!((m0, b0), (0, 5)); 149 assert_eq!((m1, b1), (1, 10)); 150 assert_eq!((m2, b2), (0, 15)); 151 } 152}