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 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! 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) } } #[cfg(serde)] impl<T: serde::Serialize> serde::Serialize for $t<T> { fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { (*self).serialize(serializer) } } #[cfg(serde)] impl<'de, T: Deserialize<'de>> Deserialize<'de> for $t<T> { fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { T::deserialize(deserializer).map(|v| $t::new(v)) } } } } impl_stuff!(BoxRcu); impl_stuff!(RcRcu); impl_stuff!(ArcRcu);