zerodds_corba_poa/
active_object_map.rs1use alloc::boxed::Box;
11use alloc::collections::BTreeMap;
12use alloc::vec::Vec;
13
14use crate::error::{PoaError, PoaResult};
15use crate::object_id::ObjectId;
16use crate::policies::IdUniquenessPolicy;
17use crate::servant::Servant;
18
19pub type ServantId = u64;
23
24#[derive(Default)]
26pub struct ActiveObjectMap {
27 next_servant_id: ServantId,
28 by_oid: BTreeMap<ObjectId, ServantId>,
29 by_servant: BTreeMap<ServantId, Vec<ObjectId>>,
30 servants: BTreeMap<ServantId, Box<dyn Servant>>,
31 uniqueness: IdUniquenessPolicy,
32}
33
34impl core::fmt::Debug for ActiveObjectMap {
35 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36 f.debug_struct("ActiveObjectMap")
37 .field("entries", &self.by_oid.len())
38 .field("servants", &self.servants.len())
39 .field("uniqueness", &self.uniqueness)
40 .finish()
41 }
42}
43
44impl ActiveObjectMap {
45 #[must_use]
47 pub const fn new(uniqueness: IdUniquenessPolicy) -> Self {
48 Self {
49 next_servant_id: 1,
50 by_oid: BTreeMap::new(),
51 by_servant: BTreeMap::new(),
52 servants: BTreeMap::new(),
53 uniqueness,
54 }
55 }
56
57 pub fn activate(&mut self, oid: ObjectId, servant: Box<dyn Servant>) -> PoaResult<ServantId> {
64 if self.by_oid.contains_key(&oid) {
65 return Err(PoaError::ObjectAlreadyActive);
66 }
67 let sid = self.next_servant_id;
68 self.next_servant_id += 1;
69 self.by_oid.insert(oid.clone(), sid);
70 self.by_servant.insert(sid, alloc::vec![oid]);
71 self.servants.insert(sid, servant);
72 Ok(sid)
73 }
74
75 pub fn add_alias(&mut self, sid: ServantId, oid: ObjectId) -> PoaResult<()> {
83 if !self.servants.contains_key(&sid) {
84 return Err(PoaError::ServantNotActive);
85 }
86 if self.uniqueness == IdUniquenessPolicy::Unique {
87 return Err(PoaError::ServantAlreadyActive);
88 }
89 if self.by_oid.contains_key(&oid) {
90 return Err(PoaError::ObjectAlreadyActive);
91 }
92 self.by_oid.insert(oid.clone(), sid);
93 self.by_servant.entry(sid).or_default().push(oid);
94 Ok(())
95 }
96
97 #[must_use]
99 pub fn get(&self, oid: &ObjectId) -> Option<&dyn Servant> {
100 let sid = *self.by_oid.get(oid)?;
101 self.servants.get(&sid).map(|s| s.as_ref())
102 }
103
104 #[must_use]
106 pub fn servant_id(&self, oid: &ObjectId) -> Option<ServantId> {
107 self.by_oid.get(oid).copied()
108 }
109
110 #[must_use]
112 pub fn ids_for_servant(&self, sid: ServantId) -> &[ObjectId] {
113 self.by_servant.get(&sid).map(Vec::as_slice).unwrap_or(&[])
114 }
115
116 pub fn deactivate(&mut self, oid: &ObjectId) -> PoaResult<Box<dyn Servant>> {
122 let sid = self.by_oid.remove(oid).ok_or(PoaError::ObjectNotActive)?;
123 if let Some(list) = self.by_servant.get_mut(&sid) {
124 list.retain(|i| i != oid);
125 if list.is_empty() {
126 self.by_servant.remove(&sid);
127 let s = self.servants.remove(&sid);
128 return s.ok_or(PoaError::ServantNotActive);
129 }
130 }
131 Err(PoaError::BadInvocationOrder(
134 "servant still has other aliases".into(),
135 ))
136 }
137
138 #[must_use]
140 pub fn len(&self) -> usize {
141 self.by_oid.len()
142 }
143
144 #[must_use]
146 pub fn is_empty(&self) -> bool {
147 self.by_oid.is_empty()
148 }
149
150 pub(crate) fn set_uniqueness(&mut self, u: IdUniquenessPolicy) {
152 self.uniqueness = u;
153 }
154}
155
156#[cfg(test)]
157#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
158mod tests {
159 use super::*;
160 use crate::servant::EchoServant;
161
162 fn echo() -> Box<dyn Servant> {
163 Box::new(EchoServant {
164 repo_id: "IDL:demo/Echo:1.0".into(),
165 })
166 }
167
168 #[test]
169 fn activate_and_get_round_trip() {
170 let mut m = ActiveObjectMap::new(IdUniquenessPolicy::Unique);
171 let oid = ObjectId::system_id(1);
172 let sid = m.activate(oid.clone(), echo()).unwrap();
173 assert!(m.get(&oid).is_some());
174 assert_eq!(m.servant_id(&oid), Some(sid));
175 assert_eq!(m.len(), 1);
176 }
177
178 #[test]
179 fn activate_twice_with_same_oid_is_rejected() {
180 let mut m = ActiveObjectMap::new(IdUniquenessPolicy::Unique);
181 let oid = ObjectId::system_id(1);
182 m.activate(oid.clone(), echo()).unwrap();
183 let err = m.activate(oid, echo()).unwrap_err();
184 assert_eq!(err, PoaError::ObjectAlreadyActive);
185 }
186
187 #[test]
188 fn unique_id_rejects_alias() {
189 let mut m = ActiveObjectMap::new(IdUniquenessPolicy::Unique);
190 let sid = m.activate(ObjectId::system_id(1), echo()).unwrap();
191 let err = m.add_alias(sid, ObjectId::system_id(2)).unwrap_err();
192 assert_eq!(err, PoaError::ServantAlreadyActive);
193 }
194
195 #[test]
196 fn multiple_id_allows_aliases() {
197 let mut m = ActiveObjectMap::new(IdUniquenessPolicy::Multiple);
198 let sid = m.activate(ObjectId::system_id(1), echo()).unwrap();
199 m.add_alias(sid, ObjectId::system_id(2)).unwrap();
200 m.add_alias(sid, ObjectId::system_id(3)).unwrap();
201 assert_eq!(m.ids_for_servant(sid).len(), 3);
202 assert_eq!(m.len(), 3);
203 }
204
205 #[test]
206 fn deactivate_removes_only_when_last_alias_gone() {
207 let mut m = ActiveObjectMap::new(IdUniquenessPolicy::Multiple);
208 let sid = m.activate(ObjectId::system_id(1), echo()).unwrap();
209 m.add_alias(sid, ObjectId::system_id(2)).unwrap();
210
211 let err = m.deactivate(&ObjectId::system_id(1)).unwrap_err();
213 assert!(matches!(err, PoaError::BadInvocationOrder(_)));
214 assert_eq!(m.len(), 1);
215
216 let _s = m.deactivate(&ObjectId::system_id(2)).unwrap();
218 assert_eq!(m.len(), 0);
219 }
220
221 #[test]
222 fn deactivate_unknown_oid_is_diagnostic() {
223 let mut m = ActiveObjectMap::new(IdUniquenessPolicy::Unique);
224 let err = m.deactivate(&ObjectId::system_id(99)).unwrap_err();
225 assert_eq!(err, PoaError::ObjectNotActive);
226 }
227}