1use std::{collections::BTreeMap, num::NonZeroUsize};
2
3use stable_vec::StableVec;
4use twizzler_rt_abi::object::ObjID;
5
6pub trait Handle {
8 type OpenError;
10
11 type OpenInfo;
13
14 fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
16 where
17 Self: Sized;
18
19 fn release(&mut self);
21}
22
23pub type Descriptor = u32;
25
26#[derive(Default, Clone)]
28pub struct HandleMgr<ServerData> {
29 handles: BTreeMap<ObjID, StableVec<ServerData>>,
30 max: Option<NonZeroUsize>,
31}
32
33impl<ServerData> HandleMgr<ServerData> {
34 pub const fn new(max: Option<usize>) -> Self {
36 Self {
37 handles: BTreeMap::new(),
38 max: match max {
39 Some(m) => NonZeroUsize::new(m),
40 None => None,
41 },
42 }
43 }
44
45 pub fn max(&self) -> Option<usize> {
47 self.max.map(|x| x.get())
48 }
49
50 pub fn total_count(&self) -> usize {
52 self.handles
53 .values()
54 .fold(0, |acc, val| acc + val.num_elements())
55 }
56
57 pub fn open_count(&self, comp: ObjID) -> usize {
59 self.handles
60 .get(&comp)
61 .map(|sv| sv.num_elements())
62 .unwrap_or(0)
63 }
64
65 pub fn lookup(&self, comp: ObjID, ds: Descriptor) -> Option<&ServerData> {
67 let idx: usize = ds.try_into().ok()?;
68 self.handles.get(&comp).and_then(|sv| sv.get(idx))
69 }
70
71 pub fn lookup_mut(&mut self, comp: ObjID, ds: Descriptor) -> Option<&mut ServerData> {
73 let idx: usize = ds.try_into().ok()?;
74 self.handles.get_mut(&comp).and_then(|sv| sv.get_mut(idx))
75 }
76
77 pub fn insert(&mut self, comp: ObjID, sd: ServerData) -> Option<Descriptor> {
79 let entry = self.handles.entry(comp).or_insert_with(|| StableVec::new());
80 let idx = entry.next_push_index();
81 if let Some(max) = self.max {
82 if idx >= max.get() {
83 return None;
84 }
85 }
86 let ds: Descriptor = idx.try_into().ok()?;
87 let pushed_idx = entry.push(sd);
88 debug_assert_eq!(pushed_idx, idx);
89
90 Some(ds)
91 }
92
93 pub fn remove(&mut self, comp: ObjID, ds: Descriptor) -> Option<ServerData> {
95 let idx: usize = ds.try_into().ok()?;
96 self.handles.get_mut(&comp)?.remove(idx)
97 }
98}
99
100#[cfg(test)]
101mod test {
102 use std::cell::RefCell;
103
104 use super::*;
105
106 struct FooHandle {
107 desc: Descriptor,
108 x: u32,
109 mgr: RefCell<HandleMgr<u32>>,
110 removed_data: Option<u32>,
111 }
112
113 impl Handle for FooHandle {
114 type OpenError = ();
115
116 type OpenInfo = (u32, RefCell<HandleMgr<u32>>);
117
118 fn open(info: Self::OpenInfo) -> Result<Self, Self::OpenError>
119 where
120 Self: Sized,
121 {
122 let desc = info.1.borrow_mut().insert(0.into(), info.0).unwrap();
123 Ok(Self {
124 desc,
125 x: info.0,
126 mgr: info.1,
127 removed_data: None,
128 })
129 }
130
131 fn release(&mut self) {
132 self.removed_data = self.mgr.borrow_mut().remove(0.into(), self.desc);
133 }
134 }
135
136 #[test]
137 fn handle() {
138 let mgr = RefCell::new(HandleMgr::new(Some(8)));
139 let mut foo = FooHandle::open((42, mgr)).unwrap();
140
141 assert_eq!(foo.x, 42);
142 let sd = foo.mgr.borrow().lookup(0.into(), foo.desc).cloned();
143 assert_eq!(sd, Some(42));
144
145 foo.release();
146 assert_eq!(foo.removed_data, Some(42));
147 assert!(foo.mgr.borrow().lookup(0.into(), foo.desc).is_none());
148 }
149}