1use std::any;
9use std::sync::Arc;
10
11use slotmap_careful::{Key as _, KeyData, SlotMap};
12use tor_rpcbase as rpc;
13
14pub(crate) mod methods;
15#[cfg(feature = "weakref")]
16mod weakrefs;
17
18#[cfg(any(test, feature = "weakref"))]
20fn raw_addr_of<T: ?Sized>(arc: &Arc<T>) -> RawAddr {
21 RawAddr(Arc::as_ptr(arc) as *const () as usize)
24}
25
26#[cfg(any(test, feature = "weakref"))]
28fn raw_addr_of_weak<T: ?Sized>(arc: &std::sync::Weak<T>) -> RawAddr {
29 RawAddr(std::sync::Weak::as_ptr(arc) as *const () as usize)
30}
31
32slotmap_careful::new_key_type! {
33 pub(crate) struct StrongIdx;
34 pub(crate) struct WeakIdx;
36
37}
38
39#[derive(Default)]
41pub(crate) struct ObjMap {
42 strong_arena: SlotMap<StrongIdx, Arc<dyn rpc::Object>>,
44 #[cfg(feature = "weakref")]
52 weak_arena: SlotMap<WeakIdx, weakrefs::WeakArenaEntry>,
53 #[cfg(feature = "weakref")]
61 reverse_map: std::collections::HashMap<TaggedAddr, WeakIdx>,
62 #[cfg(all(test, feature = "weakref"))]
64 n_tidies: usize,
65}
66
67#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
75struct RawAddr(usize);
76
77#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
107struct TaggedAddr {
108 addr: RawAddr,
110 type_id: any::TypeId,
112}
113
114#[derive(Copy, Clone, Debug, Eq, PartialEq)]
116pub(crate) enum GenIdx {
117 Weak(WeakIdx),
121 Strong(StrongIdx),
123}
124
125impl GenIdx {
139 pub(crate) const BYTE_LEN: usize = 16;
141
142 pub(crate) fn is_strong(&self) -> bool {
144 matches!(self, GenIdx::Strong(_))
145 }
146
147 pub(crate) fn encode(self) -> rpc::ObjectId {
149 self.encode_with_rng(&mut rand::rng())
150 }
151
152 fn encode_with_rng<R: rand::RngCore>(self, rng: &mut R) -> rpc::ObjectId {
154 use base64ct::Encoding;
155 let bytes = self.to_bytes(rng);
156 rpc::ObjectId::from(base64ct::Base64UrlUnpadded::encode_string(&bytes[..]))
157 }
158
159 pub(crate) fn to_bytes<R: rand::RngCore>(self, rng: &mut R) -> [u8; Self::BYTE_LEN] {
161 use rand::Rng;
162 use tor_bytes::Writer;
163 let (weak_bit, ffi_idx) = match self {
164 GenIdx::Weak(idx) => (1, idx.data().as_ffi()),
165 GenIdx::Strong(idx) => (0, idx.data().as_ffi()),
166 };
167 let x = rng.random::<u64>() << 1;
168 let mut bytes = Vec::with_capacity(Self::BYTE_LEN);
169 bytes.write_u64(x | weak_bit);
170 bytes.write_u64(ffi_idx.wrapping_add(x));
171
172 bytes.try_into().expect("Length was wrong!")
173 }
174
175 pub(crate) fn try_decode(id: &rpc::ObjectId) -> Result<Self, rpc::LookupError> {
177 use base64ct::Encoding;
178
179 let bytes = base64ct::Base64UrlUnpadded::decode_vec(id.as_ref())
180 .map_err(|_| rpc::LookupError::NoObject(id.clone()))?;
181 Self::from_bytes(&bytes).ok_or_else(|| rpc::LookupError::NoObject(id.clone()))
182 }
183
184 pub(crate) fn from_bytes(bytes: &[u8]) -> Option<Self> {
186 use tor_bytes::Reader;
187 let mut r = Reader::from_slice(bytes);
188 let x = r.take_u64().ok()?;
189 let is_weak = (x & 1) == 1;
190 let x = x & !1;
191 let ffi_idx = r.take_u64().ok()?;
192 r.should_be_exhausted().ok()?;
193
194 let ffi_idx = ffi_idx.wrapping_sub(x);
195
196 if is_weak {
197 Some(GenIdx::Weak(WeakIdx::from(KeyData::from_ffi(ffi_idx))))
198 } else {
199 Some(GenIdx::Strong(StrongIdx::from(KeyData::from_ffi(ffi_idx))))
200 }
201 }
202}
203
204impl ObjMap {
205 pub(crate) fn new() -> Self {
207 Self::default()
208 }
209
210 pub(crate) fn insert_strong(&mut self, value: Arc<dyn rpc::Object>) -> GenIdx {
212 GenIdx::Strong(self.strong_arena.insert(value))
213 }
214
215 pub(crate) fn lookup(&self, idx: GenIdx) -> Option<Arc<dyn rpc::Object>> {
217 match idx {
218 #[cfg(feature = "weakref")]
219 GenIdx::Weak(idx) => self
220 .weak_arena
221 .get(idx)
222 .and_then(weakrefs::WeakArenaEntry::strong),
223 #[cfg(not(feature = "weakref"))]
224 GenIdx::Weak(_) => None,
225 GenIdx::Strong(idx) => self.strong_arena.get(idx).cloned(),
226 }
227 }
228
229 pub(crate) fn remove(&mut self, idx: GenIdx) -> Option<Arc<dyn rpc::Object>> {
231 match idx {
232 #[cfg(feature = "weakref")]
233 GenIdx::Weak(idx) => {
234 if let Some(entry) = self.weak_arena.remove(idx) {
235 let old_idx = self.reverse_map.remove(&entry.tagged_addr());
236 debug_assert_eq!(old_idx, Some(idx));
237 entry.obj.upgrade()
238 } else {
239 None
240 }
241 }
242 #[cfg(not(feature = "weakref"))]
243 GenIdx::Weak(_) => None,
244 GenIdx::Strong(idx) => self.strong_arena.remove(idx),
245 }
246 }
247
248 #[cfg(test)]
250 fn assert_okay(&self) {
251 #[cfg(feature = "weakref")]
252 {
253 for (index, entry) in self.weak_arena.iter() {
254 let ptr = entry.tagged_addr();
255 assert_eq!(self.reverse_map.get(&ptr), Some(&index));
256 assert_eq!(ptr, entry.tagged_addr());
257 }
258
259 for (ptr, idx) in self.reverse_map.iter() {
260 let entry = self
261 .weak_arena
262 .get(*idx)
263 .expect("Dangling pointer in reverse map");
264
265 assert_eq!(&entry.tagged_addr(), ptr);
266 }
267 }
268 }
269}
270
271#[cfg(test)]
272mod test {
273 #![allow(clippy::bool_assert_comparison)]
275 #![allow(clippy::clone_on_copy)]
276 #![allow(clippy::dbg_macro)]
277 #![allow(clippy::mixed_attributes_style)]
278 #![allow(clippy::print_stderr)]
279 #![allow(clippy::print_stdout)]
280 #![allow(clippy::single_char_pattern)]
281 #![allow(clippy::unwrap_used)]
282 #![allow(clippy::unchecked_duration_subtraction)]
283 #![allow(clippy::useless_vec)]
284 #![allow(clippy::needless_pass_by_value)]
285 use super::*;
288 use derive_deftly::Deftly;
289 use tor_rpcbase::templates::*;
290
291 #[derive(Clone, Debug, Deftly)]
292 #[derive_deftly(Object)]
293 struct ExampleObject(#[allow(unused)] String);
294
295 impl ExampleObject {
296 fn wrap_arc(self: Arc<Self>) -> Arc<Wrapper> {
297 unsafe { Arc::from_raw(Arc::into_raw(self) as *const Wrapper) }
306 }
307 }
308
309 #[derive(Clone, Debug, Deftly)]
310 #[derive_deftly(Object)]
311 #[repr(transparent)]
312 struct Wrapper(ExampleObject);
313
314 #[cfg(feature = "weakref")]
315 #[test]
316 fn arc_to_addr() {
317 let a1 = Arc::new("Hello world");
318 let a2 = Arc::clone(&a1);
319 let a3 = Arc::new("Hello world");
320 let w1 = Arc::downgrade(&a2);
321
322 assert_eq!(raw_addr_of(&a1), raw_addr_of(&a2));
323 assert_eq!(raw_addr_of(&a1), raw_addr_of_weak(&w1));
324 assert_ne!(raw_addr_of(&a1), raw_addr_of(&a3));
325
326 let obj1: Arc<dyn rpc::Object> = Arc::new(ExampleObject("Hello world".into()));
327 let obj2 = Arc::clone(&obj1);
328 let obj3: Arc<dyn rpc::Object> = Arc::new(ExampleObject("Hello world".into()));
329 let obj4 = Arc::clone(&obj3);
330 let weak1 = Arc::downgrade(&obj1);
331 let weak2 = Arc::downgrade(&obj3);
332
333 assert_eq!(raw_addr_of(&obj1), raw_addr_of(&obj2));
334 assert_eq!(raw_addr_of(&obj1), raw_addr_of_weak(&weak1));
335 assert_eq!(raw_addr_of(&obj3), raw_addr_of(&obj4));
336 assert_eq!(raw_addr_of(&obj3), raw_addr_of_weak(&weak2));
337 assert_ne!(raw_addr_of(&obj1), raw_addr_of(&obj3));
338 assert_ne!(raw_addr_of(&obj1), raw_addr_of(&a1));
339 }
340
341 #[cfg(feature = "weakref")]
342 #[test]
343 fn obj_ptr() {
344 let object = Arc::new(ExampleObject("Ten tons of flax".into()));
345 let object2: Arc<dyn rpc::Object> = Arc::new(ExampleObject("Ten tons of flax".into()));
346
347 let wrapped: Arc<Wrapper> = object.clone().wrap_arc();
348 let object_dyn = object.clone() as Arc<dyn rpc::Object>;
349 let wrapped_dyn = wrapped.clone() as Arc<dyn rpc::Object>;
350
351 let object_dyn2 = Arc::clone(&object_dyn);
352 let wrapped_dyn2 = Arc::clone(&wrapped_dyn);
353 let wrapped_weak = Arc::downgrade(&wrapped_dyn);
354
355 assert_eq!(
356 TaggedAddr::for_object(&object_dyn),
357 TaggedAddr::for_object(&object_dyn2)
358 );
359 assert_ne!(
360 TaggedAddr::for_object(&object_dyn),
361 TaggedAddr::for_object(&object2)
362 );
363
364 assert_eq!(
365 TaggedAddr::for_object(&wrapped_dyn),
366 TaggedAddr::for_object(&wrapped_dyn2)
367 );
368
369 assert_ne!(
370 TaggedAddr::for_object(&object_dyn),
371 TaggedAddr::for_object(&wrapped_dyn)
372 );
373
374 assert_eq!(
375 TaggedAddr::for_object(&object_dyn).addr,
376 TaggedAddr::for_object(&wrapped_dyn).addr
377 );
378 #[cfg(feature = "weakref")]
379 assert_eq!(
380 TaggedAddr::for_object(&wrapped_dyn).addr,
381 raw_addr_of_weak(&wrapped_weak)
382 );
383
384 assert_eq!(
385 TaggedAddr::for_object(&object_dyn).type_id,
386 any::TypeId::of::<ExampleObject>()
387 );
388 assert_eq!(
389 TaggedAddr::for_object(&wrapped_dyn).type_id,
390 any::TypeId::of::<Wrapper>()
391 );
392
393 assert_eq!(
394 TaggedAddr::for_object(&object_dyn).addr,
395 raw_addr_of(&object)
396 );
397 assert_eq!(
398 TaggedAddr::for_object(&wrapped_dyn).addr,
399 raw_addr_of(&wrapped)
400 );
401 assert_ne!(
402 TaggedAddr::for_object(&object_dyn).addr,
403 raw_addr_of(&object2)
404 );
405 }
406
407 #[test]
408 fn map_basics() {
409 let obj1 = Arc::new(ExampleObject("abcdef".to_string()));
411 let mut map = ObjMap::new();
412 map.assert_okay();
413 let id1 = map.insert_strong(obj1.clone());
414 let id2 = map.insert_strong(obj1.clone());
415 assert_ne!(id1, id2);
416 let obj_out1 = map.lookup(id1).unwrap();
417 let obj_out2 = map.lookup(id2).unwrap();
418 assert_eq!(raw_addr_of(&obj1), raw_addr_of(&obj_out1));
419 assert_eq!(raw_addr_of(&obj1), raw_addr_of(&obj_out2));
420 map.assert_okay();
421
422 map.remove(id1);
423 assert!(map.lookup(id1).is_none());
424 let obj_out2b = map.lookup(id2).unwrap();
425 assert_eq!(raw_addr_of(&obj_out2), raw_addr_of(&obj_out2b));
426
427 map.assert_okay();
428 }
429
430 #[cfg(feature = "weakref")]
431 #[test]
432 fn strong_and_weak() {
433 let obj1: Arc<dyn rpc::Object> = Arc::new(ExampleObject("hello".to_string()));
436 let obj2: Arc<dyn rpc::Object> = Arc::new(ExampleObject("world".to_string()));
437 let mut map = ObjMap::new();
438 let id1 = map.insert_strong(obj1.clone());
439 let id2 = map.insert_weak(obj2.clone());
440
441 {
442 let out1 = map.lookup(id1);
443 let out2 = map.lookup(id2);
444 assert_eq!(raw_addr_of(&obj1), raw_addr_of(&out1.unwrap()));
445 assert_eq!(raw_addr_of(&obj2), raw_addr_of(&out2.unwrap()));
446 }
447 let addr1 = raw_addr_of(&obj1);
448 map.assert_okay();
449
450 drop(obj1);
452 drop(obj2);
453 {
454 let out1 = map.lookup(id1);
455 let out2 = map.lookup(id2);
456
457 assert!(out1.is_some());
459 assert_eq!(raw_addr_of(&out1.unwrap()), addr1);
460
461 assert!(out2.is_none());
463 }
464 map.assert_okay();
465 }
466
467 #[cfg(feature = "weakref")]
468 #[test]
469 fn remove() {
470 let obj1: Arc<dyn rpc::Object> = Arc::new(ExampleObject("hello".to_string()));
472 let obj2: Arc<dyn rpc::Object> = Arc::new(ExampleObject("world".to_string()));
473 let mut map = ObjMap::new();
474 let id1 = map.insert_strong(obj1.clone());
475 let id2 = map.insert_weak(obj2.clone());
476 map.assert_okay();
477
478 map.remove(id1);
479 map.assert_okay();
480 assert!(map.lookup(id1).is_none());
481 assert!(map.lookup(id2).is_some());
482
483 map.remove(id2);
484 map.assert_okay();
485 assert!(map.lookup(id1).is_none());
486 assert!(map.lookup(id2).is_none());
487 }
488
489 #[cfg(feature = "weakref")]
490 #[test]
491 fn duplicates() {
492 let obj1: Arc<dyn rpc::Object> = Arc::new(ExampleObject("hello".to_string()));
494 let obj2: Arc<dyn rpc::Object> = Arc::new(ExampleObject("world".to_string()));
495 let mut map = ObjMap::new();
496 let id1 = map.insert_strong(obj1.clone());
497 let id2 = map.insert_weak(obj2.clone());
498
499 {
500 assert_ne!(id2, map.insert_weak(obj1.clone()));
501 assert_eq!(id2, map.insert_weak(obj2.clone()));
502 }
503
504 {
505 assert_ne!(id1, map.insert_strong(obj1.clone()));
506 assert_ne!(id2, map.insert_strong(obj2.clone()));
507 }
508 }
509
510 #[cfg(feature = "weakref")]
511 #[test]
512 fn upgrade() {
513 let obj1: Arc<dyn rpc::Object> = Arc::new(ExampleObject("hello".to_string()));
516 let obj2: Arc<dyn rpc::Object> = Arc::new(ExampleObject("world".to_string()));
517 let addr1 = raw_addr_of(&obj1);
518 let addr2 = raw_addr_of(&obj2);
519
520 let mut map = ObjMap::new();
521 let id1 = map.insert_strong(obj1.clone());
522 let id2 = map.insert_weak(obj2.clone());
523
524 assert_ne!(id2, map.insert_weak(obj1.clone()));
525 assert_ne!(id1, map.insert_strong(obj2.clone()));
526 map.assert_okay();
527
528 drop(obj1);
529 drop(obj2);
530 let out1 = map.lookup(id1).unwrap();
531 let out2 = map.lookup(id2).unwrap();
532 assert_eq!(raw_addr_of(&out1), addr1);
533 assert_eq!(raw_addr_of(&out2), addr2);
534 }
535
536 #[cfg(feature = "weakref")]
537 #[test]
538 fn tidy() {
539 let mut map = ObjMap::new();
540 let mut keep_these = vec![];
541 let mut s = vec![];
542 let mut w = vec![];
543 for _ in 0..100 {
544 let mut t = vec![];
545 for _ in 0..10 {
546 let o = Arc::new(ExampleObject("dump".into()));
547 w.push(map.insert_weak(o.clone()));
548 t.push(o);
549 }
550 let obj = Arc::new(ExampleObject("cafe".into()));
551 keep_these.push(obj.clone());
552 s.push(map.insert_weak(obj));
553 drop(t);
554 map.assert_okay();
555 }
556
557 assert_eq!(s.len(), 100);
558 assert_eq!(w.len(), 1000);
559 assert!(w.iter().all(|id| map.lookup(*id).is_none()));
560 assert!(s.iter().all(|id| map.lookup(*id).is_some()));
561
562 assert_ne!(map.weak_arena.len() + map.strong_arena.len(), 1100);
563 map.assert_okay();
564 map.tidy();
565 map.assert_okay();
566 assert_eq!(map.weak_arena.len() + map.strong_arena.len(), 100);
567
568 assert!(dbg!(map.n_tidies) < 30);
570 }
571
572 #[test]
573 fn wrapper_magic() {
574 let obj = Arc::new(ExampleObject("dump".into()));
576 let wrap = obj.clone().wrap_arc();
577
578 let mut map = ObjMap::new();
579 map.insert_strong(obj);
580 map.insert_strong(wrap);
581 assert_eq!(map.strong_arena.len(), 2);
582 }
583
584 #[test]
585 fn objid_encoding() {
586 use rand::Rng;
587 fn test_roundtrip(a: u32, b: u32, rng: &mut tor_basic_utils::test_rng::TestingRng) {
588 let a: u64 = a.into();
589 let b: u64 = b.into();
590 let data = KeyData::from_ffi((a << 33) | (1_u64 << 32) | b);
591 let idx = if rng.random_bool(0.5) {
592 GenIdx::Strong(StrongIdx::from(data))
593 } else {
594 GenIdx::Weak(WeakIdx::from(data))
595 };
596 let s1 = idx.encode_with_rng(rng);
597 let s2 = idx.encode_with_rng(rng);
598 assert_ne!(s1, s2);
599 assert_eq!(idx, GenIdx::try_decode(&s1).unwrap());
600 assert_eq!(idx, GenIdx::try_decode(&s2).unwrap());
601 }
602 let mut rng = tor_basic_utils::test_rng::testing_rng();
603
604 test_roundtrip(0, 1, &mut rng);
605 test_roundtrip(0, 2, &mut rng);
606 test_roundtrip(1, 1, &mut rng);
607 test_roundtrip(0xffffffff, 0xffffffff, &mut rng);
608
609 for _ in 0..256 {
610 test_roundtrip(rng.random(), rng.random(), &mut rng);
611 }
612 }
613}