1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! This crate provides a set (eventually) of smart pointer types that
//! allow read access with no guards (and minimal to no overhead) and
//! no need to call [std::borrow::Borrow].  These smart pointers each
//! allow internal mutability (obtaining mutable references) by a
//! Read-Copy-Update approach, so you get a mutable reference to a
//! private copy of the data, which you can mutate at will.  When the
//! mutation is complete the pointer is atomically updated.  Old
//! references to the data may still exist, and will still be a valid
//! reference to the old data.
//!
//! Basically, these smart pointers allow internal mutability through
//! a slow and painful process, while keeping read-only access both
//! fast and easy (in particular, no need to call `ptr.borrow()`
//! everywhere).  Write access is guarded, but read access is not.
//!
//! The names of the types are based on the standard smart pointer
//! types.
//!
//! 1. `[BoxRcu]` is an owned pointer similar to [std::box::Box].  If
//!    you like, it is actually closer to `Box<RefCell<T>>`, or even
//!    `Box<Mutex<T>>`, but without the nuisance of having to call
//!    borrow when reading.
//!
//! 2. `[RcRcu]` is a reference counted pointer similar to [std::rc::Rc].
//!    If you like, it is actually closer to `Rc<RefCell<T>>`, but
//!    without the nuisance of having to call borrow when reading.
//!
//! 3. `ArcRcu` is planned to be a thread-safe reference counted
//!    pointer similar to [std::sync::Arc].  It is actually
//!    closer to `Arc<RwLock<T>>`, but without the nuisance of having to
//!    call `read` before reading.
//!
//! ### Cleaning
//!
//! Due to this crate's read-copy-update semantics, old copies of your
//! data are kept until we are confident that there are no longer any
//! references to them.  Because we do not have any guards on the read
//! references, this must be done manually.  This is the cost we pay
//! for extra convenience (and much improved read speed in the case of
//! `ArcRcu`) on the read operations.  You have two options for how to
//! handle this.
//!
//! One option is to simply store those extra copies until then entire
//! smart pointer itself is freed.  That is what happens if you do
//! nothing, and for small data that is only mutated once, it's a fine
//! option.  However, for `[ArcRcu]` and `[RcRcu]` there will be a
//! slowdown on reading until you do call clean, since an extra level
//! of pointer redirection will be required.
//!
//! The other option is to call `clean()` when convenient.  `clean`
//! takes a `&mut self`, so when it is called, the compiler will prove
//! to us that there are no other references out there via *this*
//! smart pointer.  For `BoxCell` that is sufficient to prove that we
//! can free the data.  In the case of the reference counted data
//! pointers, we keep track of a count of how many copies have been
//! dereferenced since the last time `clean` was called.  We could
//! probably be more accurate with "epoch" tracking, but I don't know
//! that the complexity will be worthwhile.

mod boxrcu;
pub use crate::boxrcu::BoxRcu;

mod rcrcu;
pub use crate::rcrcu::RcRcu;

mod arcrcu;
pub use crate::arcrcu::ArcRcu;

macro_rules! impl_stuff {
    ($t:ident) => {
        impl<T: PartialEq> PartialEq for $t<T> {
            fn eq(&self, other: &$t<T>) -> bool {
                &(**self) == &(**other)
            }
        }
        impl<T: Eq> Eq for $t<T> {}
        impl<T: PartialOrd> PartialOrd for $t<T> {
            fn partial_cmp(&self, other: &$t<T>) -> Option<std::cmp::Ordering> {
                (**self).partial_cmp(&**other)
            }
        }
        impl<T: Ord> Ord for $t<T> {
            fn cmp(&self, other: &$t<T>) -> std::cmp::Ordering {
                (**self).cmp(&**other)
            }
        }
        impl<T: std::fmt::Debug> std::fmt::Debug for $t<T> {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
                (**self).fmt(f)
            }
        }
        impl<T: std::fmt::Display> std::fmt::Display for $t<T> {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
                (**self).fmt(f)
            }
        }
    }
}

impl_stuff!(BoxRcu);
impl_stuff!(RcRcu);
impl_stuff!(ArcRcu);