Coverage Report

Created: 2026-07-13 08:11

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