arc_swap/
access.rs

1#![deny(unsafe_code)]
2
3//! Abstracting over accessing parts of stored value.
4//!
5//! Sometimes, there's a big globalish data structure (like a configuration for the whole program).
6//! Then there are parts of the program that need access to up-to-date version of their *part* of
7//! the configuration, but for reasons of code separation and reusability, it is not desirable to
8//! pass the whole configuration to each of the parts.
9//!
10//! This module provides means to grant the parts access to the relevant subsets of such global
11//! data structure while masking the fact it is part of the bigger whole from the component.
12//!
13//! Note that the [`cache`][crate::cache] module has its own [`Access`][crate::cache::Access] trait
14//! that serves a similar purpose, but with cached access. The signatures are different, therefore
15//! an incompatible trait.
16//!
17//! # The general idea
18//!
19//! Each part of the code accepts generic [`Access<T>`][Access] for the `T` of its interest. This
20//! provides means to load current version of the structure behind the scenes and get only the
21//! relevant part, without knowing what the big structure is.
22//!
23//! For technical reasons, the [`Access`] trait is not object safe. If type erasure is desired, it
24//! is possible use the [`DynAccess`][crate::access::DynAccess] instead, which is object safe, but
25//! slightly slower.
26//!
27//! For some cases, it is possible to use [`ArcSwapAny::map`]. If that is not flexible enough, the
28//! [`Map`] type can be created directly.
29//!
30//! Note that the [`Access`] trait is also implemented for [`ArcSwapAny`] itself. Additionally,
31//! there's the [`Constant`][crate::access::Constant] helper type, which is useful mostly for
32//! testing (it doesn't allow reloading).
33//!
34//! # Performance
35//!
36//! In general, these utilities use [`ArcSwapAny::load`] internally and then apply the provided
37//! transformation. This has several consequences:
38//!
39//! * Limitations of the [`load`][ArcSwapAny::load] apply ‒ including the recommendation to not
40//!   hold the returned guard object for too long, but long enough to get consistency.
41//! * The transformation should be cheap ‒ optimally just borrowing into the structure.
42//!
43//! # Examples
44//!
45//! ```rust
46//! use std::sync::Arc;
47//! use std::thread::{self, JoinHandle};
48//! use std::time::Duration;
49//!
50//! use arc_swap::ArcSwap;
51//! use arc_swap::access::{Access, Constant, Map};
52//!
53//! fn work_with_usize<A: Access<usize> + Send + 'static>(a: A) -> JoinHandle<()> {
54//!     thread::spawn(move || {
55//!         let mut value = 0;
56//!         while value != 42 {
57//!             let guard = a.load();
58//!             value = *guard;
59//!             println!("{}", value);
60//!             // Not strictly necessary, but dropping the guard can free some resources, like
61//!             // slots for tracking what values are still in use. We do it before the sleeping,
62//!             // not at the end of the scope.
63//!             drop(guard);
64//!             thread::sleep(Duration::from_millis(50));
65//!         }
66//!     })
67//! }
68//!
69//! // Passing the whole thing directly
70//! // (If we kept another Arc to it, we could change the value behind the scenes)
71//! work_with_usize(Arc::new(ArcSwap::from_pointee(42))).join().unwrap();
72//!
73//! // Passing a subset of a structure
74//! struct Cfg {
75//!     value: usize,
76//! }
77//!
78//! let cfg = Arc::new(ArcSwap::from_pointee(Cfg { value: 0 }));
79//! let thread = work_with_usize(Map::new(Arc::clone(&cfg), |cfg: &Cfg| &cfg.value));
80//! cfg.store(Arc::new(Cfg { value: 42 }));
81//! thread.join().unwrap();
82//!
83//! // Passing a constant that can't change. Useful mostly for testing purposes.
84//! work_with_usize(Constant(42)).join().unwrap();
85//! ```
86use core::marker::PhantomData;
87use core::ops::Deref;
88
89use alloc::boxed::Box;
90use alloc::rc::Rc;
91use alloc::sync::Arc;
92
93use super::ref_cnt::RefCnt;
94use super::strategy::Strategy;
95use super::{ArcSwapAny, Guard};
96
97/// Abstracts over ways code can get access to a value of type `T`.
98///
99/// This is the trait that parts of code will use when accessing a subpart of the big data
100/// structure. See the [module documentation](index.html) for details.
101pub trait Access<T> {
102    /// A guard object containing the value and keeping it alive.
103    ///
104    /// For technical reasons, the library doesn't allow direct access into the stored value. A
105    /// temporary guard object must be loaded, that keeps the actual value alive for the time of
106    /// use.
107    type Guard: Deref<Target = T>;
108
109    /// The loading method.
110    ///
111    /// This returns the guard that holds the actual value. Should be called anew each time a fresh
112    /// value is needed.
113    fn load(&self) -> Self::Guard;
114}
115
116impl<T, A: Access<T> + ?Sized, P: Deref<Target = A>> Access<T> for P {
117    type Guard = A::Guard;
118    fn load(&self) -> Self::Guard {
119        self.deref().load()
120    }
121}
122
123impl<T> Access<T> for dyn DynAccess<T> + '_ {
124    type Guard = DynGuard<T>;
125
126    fn load(&self) -> Self::Guard {
127        self.load()
128    }
129}
130
131impl<T> Access<T> for dyn DynAccess<T> + '_ + Send {
132    type Guard = DynGuard<T>;
133
134    fn load(&self) -> Self::Guard {
135        self.load()
136    }
137}
138
139impl<T> Access<T> for dyn DynAccess<T> + '_ + Sync + Send {
140    type Guard = DynGuard<T>;
141
142    fn load(&self) -> Self::Guard {
143        self.load()
144    }
145}
146
147impl<T: RefCnt, S: Strategy<T>> Access<T> for ArcSwapAny<T, S> {
148    type Guard = Guard<T, S>;
149
150    fn load(&self) -> Self::Guard {
151        self.load()
152    }
153}
154
155#[derive(Debug)]
156#[doc(hidden)]
157pub struct DirectDeref<T: RefCnt, S: Strategy<T>>(Guard<T, S>);
158
159impl<T, S: Strategy<Arc<T>>> Deref for DirectDeref<Arc<T>, S> {
160    type Target = T;
161    fn deref(&self) -> &T {
162        self.0.deref().deref()
163    }
164}
165
166impl<T, S: Strategy<Arc<T>>> Access<T> for ArcSwapAny<Arc<T>, S> {
167    type Guard = DirectDeref<Arc<T>, S>;
168    fn load(&self) -> Self::Guard {
169        DirectDeref(self.load())
170    }
171}
172
173impl<T, S: Strategy<Rc<T>>> Deref for DirectDeref<Rc<T>, S> {
174    type Target = T;
175    fn deref(&self) -> &T {
176        self.0.deref().deref()
177    }
178}
179
180impl<T, S: Strategy<Rc<T>>> Access<T> for ArcSwapAny<Rc<T>, S> {
181    type Guard = DirectDeref<Rc<T>, S>;
182    fn load(&self) -> Self::Guard {
183        DirectDeref(self.load())
184    }
185}
186
187#[doc(hidden)]
188pub struct DynGuard<T: ?Sized>(Box<dyn Deref<Target = T>>);
189
190impl<T: ?Sized> Deref for DynGuard<T> {
191    type Target = T;
192    fn deref(&self) -> &T {
193        &self.0
194    }
195}
196
197/// An object-safe version of the [`Access`] trait.
198///
199/// This can be used instead of the [`Access`] trait in case a type erasure is desired. This has
200/// the effect of performance hit (due to boxing of the result and due to dynamic dispatch), but
201/// makes certain code simpler and possibly makes the executable smaller.
202///
203/// This is automatically implemented for everything that implements [`Access`].
204///
205/// # Examples
206///
207/// ```rust
208/// use arc_swap::access::{Constant, DynAccess};
209///
210/// fn do_something(value: Box<dyn DynAccess<usize> + Send>) {
211///     let v = value.load();
212///     println!("{}", *v);
213/// }
214///
215/// do_something(Box::new(Constant(42)));
216/// ```
217pub trait DynAccess<T> {
218    /// The equivalent of [`Access::load`].
219    fn load(&self) -> DynGuard<T>;
220}
221
222impl<T, A> DynAccess<T> for A
223where
224    A: Access<T>,
225    A::Guard: 'static,
226{
227    fn load(&self) -> DynGuard<T> {
228        DynGuard(Box::new(Access::load(self)))
229    }
230}
231
232/// [DynAccess] to [Access] wrapper.
233///
234/// In previous versions, `Box<dyn DynAccess>` didn't implement [Access], to use inside [Map] one
235/// could use this wrapper. Since then, a way was found to solve it. In most cases, this wrapper is
236/// no longer necessary.
237///
238/// This is left in place for two reasons:
239/// * Backwards compatibility.
240/// * Corner-cases not covered by the found solution. For example, trait inheritance in the form of
241///   `Box<dyn SomeTrait>` where `SomeTrait: Access` doesn't work out of the box and still needs
242///   this wrapper.
243///
244/// # Examples
245///
246/// The example is for the simple case (which is no longer needed, but may help as an inspiration).
247///
248/// ```rust
249/// use std::sync::Arc;
250///
251/// use arc_swap::ArcSwap;
252/// use arc_swap::access::{AccessConvert, DynAccess, Map};
253///
254/// struct Inner {
255///     val: usize,
256/// }
257///
258/// struct Middle {
259///     inner: Inner,
260/// }
261///
262/// struct Outer {
263///     middle: Middle,
264/// }
265///
266/// let outer = Arc::new(ArcSwap::from_pointee(Outer {
267///     middle: Middle {
268///         inner: Inner {
269///             val: 42,
270///         }
271///     }
272/// }));
273///
274/// let middle: Arc<dyn DynAccess<Middle>> =
275///     Arc::new(Map::new(outer, |outer: &Outer| &outer.middle));
276/// let inner: Arc<dyn DynAccess<Inner>> =
277///     Arc::new(Map::new(AccessConvert(middle), |middle: &Middle| &middle.inner));
278/// let guard = inner.load();
279/// assert_eq!(42, guard.val);
280/// ```
281pub struct AccessConvert<D>(pub D);
282
283impl<T, D> Access<T> for AccessConvert<D>
284where
285    D: Deref,
286    D::Target: DynAccess<T>,
287{
288    type Guard = DynGuard<T>;
289
290    fn load(&self) -> Self::Guard {
291        self.0.load()
292    }
293}
294
295#[doc(hidden)]
296#[derive(Copy, Clone, Debug)]
297pub struct MapGuard<G, F, T, R> {
298    guard: G,
299    projection: F,
300    _t: PhantomData<fn(&T) -> &R>,
301}
302
303impl<G, F, T, R> Deref for MapGuard<G, F, T, R>
304where
305    G: Deref<Target = T>,
306    F: Fn(&T) -> &R,
307{
308    type Target = R;
309    fn deref(&self) -> &R {
310        (self.projection)(&self.guard)
311    }
312}
313
314/// An adaptor to provide access to a part of larger structure.
315///
316/// This is the *active* part of this module. Use the [module documentation](index.html) for the
317/// details.
318#[derive(Copy, Clone, Debug)]
319pub struct Map<A, T, F> {
320    access: A,
321    projection: F,
322    _t: PhantomData<fn() -> T>,
323}
324
325impl<A, T, F> Map<A, T, F> {
326    /// Creates a new instance.
327    ///
328    /// # Parameters
329    ///
330    /// * `access`: Access to the bigger structure. This is usually something like `Arc<ArcSwap>`
331    ///   or `&ArcSwap`. It is technically possible to use any other [`Access`] here, though, for
332    ///   example to sub-delegate into even smaller structure from a [`Map`] (or generic
333    ///   [`Access`]).
334    /// * `projection`: A function (or closure) responsible to providing a reference into the
335    ///   bigger bigger structure, selecting just subset of it. In general, it is expected to be
336    ///   *cheap* (like only taking reference).
337    pub fn new<R>(access: A, projection: F) -> Self
338    where
339        F: Fn(&T) -> &R + Clone,
340    {
341        Map {
342            access,
343            projection,
344            _t: PhantomData,
345        }
346    }
347}
348
349impl<A, F, T, R> Access<R> for Map<A, T, F>
350where
351    A: Access<T>,
352    F: Fn(&T) -> &R + Clone,
353{
354    type Guard = MapGuard<A::Guard, F, T, R>;
355    fn load(&self) -> Self::Guard {
356        let guard = self.access.load();
357        MapGuard {
358            guard,
359            projection: self.projection.clone(),
360            _t: PhantomData,
361        }
362    }
363}
364
365#[doc(hidden)]
366#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
367pub struct ConstantDeref<T>(T);
368
369impl<T> Deref for ConstantDeref<T> {
370    type Target = T;
371    fn deref(&self) -> &T {
372        &self.0
373    }
374}
375
376/// Access to an constant.
377///
378/// This wraps a constant value to provide [`Access`] to it. It is constant in the sense that,
379/// unlike [`ArcSwapAny`] and [`Map`], the loaded value will always stay the same (there's no
380/// remote `store`).
381///
382/// The purpose is mostly testing and plugging a parameter that works generically from code that
383/// doesn't need the updating functionality.
384#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
385pub struct Constant<T>(pub T);
386
387impl<T: Clone> Access<T> for Constant<T> {
388    type Guard = ConstantDeref<T>;
389    fn load(&self) -> Self::Guard {
390        ConstantDeref(self.0.clone())
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use super::super::{ArcSwap, ArcSwapOption};
397
398    use super::*;
399
400    fn check_static_dispatch_direct<A: Access<usize>>(a: A) {
401        assert_eq!(42, *a.load());
402    }
403
404    fn check_static_dispatch<A: Access<Arc<usize>>>(a: A) {
405        assert_eq!(42, **a.load());
406    }
407
408    /// Tests dispatching statically from arc-swap works
409    #[test]
410    fn static_dispatch() {
411        let a = ArcSwap::from_pointee(42);
412        check_static_dispatch_direct(&a);
413        check_static_dispatch(&a);
414        check_static_dispatch(a);
415    }
416
417    fn check_dyn_dispatch_direct(a: &dyn DynAccess<usize>) {
418        assert_eq!(42, *a.load());
419    }
420
421    fn check_dyn_dispatch(a: &dyn DynAccess<Arc<usize>>) {
422        assert_eq!(42, **a.load());
423    }
424
425    /// Tests we can also do a dynamic dispatch of the companion trait
426    #[test]
427    fn dyn_dispatch() {
428        let a = ArcSwap::from_pointee(42);
429        check_dyn_dispatch_direct(&a);
430        check_dyn_dispatch(&a);
431    }
432
433    fn check_transition<A>(a: A)
434    where
435        A: Access<usize>,
436        A::Guard: 'static,
437    {
438        check_dyn_dispatch_direct(&a)
439    }
440
441    /// Tests we can easily transition from the static dispatch trait to the dynamic one
442    #[test]
443    fn transition() {
444        let a = ArcSwap::from_pointee(42);
445        check_transition(&a);
446        check_transition(a);
447    }
448
449    /// Test we can dispatch from Arc<ArcSwap<_>> or similar.
450    #[test]
451    fn indirect() {
452        let a = Arc::new(ArcSwap::from_pointee(42));
453        check_static_dispatch(&a);
454        check_dyn_dispatch(&a);
455    }
456
457    struct Cfg {
458        value: usize,
459    }
460
461    #[test]
462    fn map() {
463        let a = ArcSwap::from_pointee(Cfg { value: 42 });
464        let map = a.map(|a: &Cfg| &a.value);
465        check_static_dispatch_direct(&map);
466        check_dyn_dispatch_direct(&map);
467    }
468
469    #[test]
470    fn map_option_some() {
471        let a = ArcSwapOption::from_pointee(Cfg { value: 42 });
472        let map = a.map(|a: &Option<Arc<Cfg>>| a.as_ref().map(|c| &c.value).unwrap());
473        check_static_dispatch_direct(&map);
474        check_dyn_dispatch_direct(&map);
475    }
476
477    #[test]
478    fn map_option_none() {
479        let a = ArcSwapOption::empty();
480        let map = a.map(|a: &Option<Arc<Cfg>>| a.as_ref().map(|c| &c.value).unwrap_or(&42));
481        check_static_dispatch_direct(&map);
482        check_dyn_dispatch_direct(&map);
483    }
484
485    #[test]
486    fn constant() {
487        let c = Constant(42);
488        check_static_dispatch_direct(c);
489        check_dyn_dispatch_direct(&c);
490        check_static_dispatch_direct(c);
491    }
492
493    #[test]
494    fn map_reload() {
495        let a = ArcSwap::from_pointee(Cfg { value: 0 });
496        let map = a.map(|cfg: &Cfg| &cfg.value);
497        assert_eq!(0, *Access::load(&map));
498        a.store(Arc::new(Cfg { value: 42 }));
499        assert_eq!(42, *Access::load(&map));
500    }
501
502    // Compile tests for dynamic access
503    fn _expect_access<T>(_: impl Access<T>) {}
504
505    fn _dyn_access<T>(x: Box<dyn DynAccess<T> + '_>) {
506        _expect_access(x)
507    }
508
509    fn _dyn_access_send<T>(x: Box<dyn DynAccess<T> + '_ + Send>) {
510        _expect_access(x)
511    }
512
513    fn _dyn_access_send_sync<T>(x: Box<dyn DynAccess<T> + '_ + Send + Sync>) {
514        _expect_access(x)
515    }
516
517    #[test]
518    #[allow(clippy::arc_with_non_send_sync)] // Whatever, it's tests...
519    fn double_dyn_access_complex() {
520        struct Inner {
521            val: usize,
522        }
523
524        struct Middle {
525            inner: Inner,
526        }
527
528        struct Outer {
529            middle: Middle,
530        }
531
532        let outer = Arc::new(ArcSwap::from_pointee(Outer {
533            middle: Middle {
534                inner: Inner { val: 42 },
535            },
536        }));
537
538        let middle: Arc<dyn DynAccess<Middle>> =
539            Arc::new(Map::new(outer, |outer: &Outer| &outer.middle));
540        let inner: Arc<dyn DynAccess<Inner>> =
541            Arc::new(Map::new(middle, |middle: &Middle| &middle.inner));
542        // Damn. We have the DynAccess wrapper in scope and need to disambiguate the inner.load()
543        let guard = Access::load(&inner);
544        assert_eq!(42, guard.val);
545    }
546}