blob: 35d34db07ce54ccb7caf1ad91cd356bd7d2e08f4 [file] [log] [blame] [edit]
#![deny(unsafe_code)]
//! Abstracting over accessing parts of stored value.
//!
//! Sometimes, there's a big globalish data structure (like a configuration for the whole program).
//! Then there are parts of the program that need access to up-to-date version of their *part* of
//! the configuration, but for reasons of code separation and reusability, it is not desirable to
//! pass the whole configuration to each of the parts.
//!
//! This module provides means to grant the parts access to the relevant subsets of such global
//! data structure while masking the fact it is part of the bigger whole from the component.
//!
//! Note that the [`cache`][crate::cache] module has its own [`Access`][crate::cache::Access] trait
//! that serves a similar purpose, but with cached access. The signatures are different, therefore
//! an incompatible trait.
//!
//! # The general idea
//!
//! Each part of the code accepts generic [`Access<T>`][Access] for the `T` of its interest. This
//! provides means to load current version of the structure behind the scenes and get only the
//! relevant part, without knowing what the big structure is.
//!
//! For technical reasons, the [`Access`] trait is not object safe. If type erasure is desired, it
//! is possible use the [`DynAccess`][crate::access::DynAccess] instead, which is object safe, but
//! slightly slower.
//!
//! For some cases, it is possible to use [`ArcSwapAny::map`]. If that is not flexible enough, the
//! [`Map`] type can be created directly.
//!
//! Note that the [`Access`] trait is also implemented for [`ArcSwapAny`] itself. Additionally,
//! there's the [`Constant`][crate::access::Constant] helper type, which is useful mostly for
//! testing (it doesn't allow reloading).
//!
//! # Performance
//!
//! In general, these utilities use [`ArcSwapAny::load`] internally and then apply the provided
//! transformation. This has several consequences:
//!
//! * Limitations of the [`load`][ArcSwapAny::load] apply ‒ including the recommendation to not
//! hold the returned guard object for too long, but long enough to get consistency.
//! * The transformation should be cheap ‒ optimally just borrowing into the structure.
//!
//! # Examples
//!
//! ```rust
//! use std::sync::Arc;
//! use std::thread::{self, JoinHandle};
//! use std::time::Duration;
//!
//! use arc_swap::ArcSwap;
//! use arc_swap::access::{Access, Constant, Map};
//!
//! fn work_with_usize<A: Access<usize> + Send + 'static>(a: A) -> JoinHandle<()> {
//! thread::spawn(move || {
//! let mut value = 0;
//! while value != 42 {
//! let guard = a.load();
//! value = *guard;
//! println!("{}", value);
//! // Not strictly necessary, but dropping the guard can free some resources, like
//! // slots for tracking what values are still in use. We do it before the sleeping,
//! // not at the end of the scope.
//! drop(guard);
//! thread::sleep(Duration::from_millis(50));
//! }
//! })
//! }
//!
//! // Passing the whole thing directly
//! // (If we kept another Arc to it, we could change the value behind the scenes)
//! work_with_usize(Arc::new(ArcSwap::from_pointee(42))).join().unwrap();
//!
//! // Passing a subset of a structure
//! struct Cfg {
//! value: usize,
//! }
//!
//! let cfg = Arc::new(ArcSwap::from_pointee(Cfg { value: 0 }));
//! let thread = work_with_usize(Map::new(Arc::clone(&cfg), |cfg: &Cfg| &cfg.value));
//! cfg.store(Arc::new(Cfg { value: 42 }));
//! thread.join().unwrap();
//!
//! // Passing a constant that can't change. Useful mostly for testing purposes.
//! work_with_usize(Constant(42)).join().unwrap();
//! ```
use core::marker::PhantomData;
use core::ops::Deref;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::sync::Arc;
use super::ref_cnt::RefCnt;
use super::strategy::Strategy;
use super::{ArcSwapAny, Guard};
/// Abstracts over ways code can get access to a value of type `T`.
///
/// This is the trait that parts of code will use when accessing a subpart of the big data
/// structure. See the [module documentation](index.html) for details.
pub trait Access<T> {
/// A guard object containing the value and keeping it alive.
///
/// For technical reasons, the library doesn't allow direct access into the stored value. A
/// temporary guard object must be loaded, that keeps the actual value alive for the time of
/// use.
type Guard: Deref<Target = T>;
/// The loading method.
///
/// This returns the guard that holds the actual value. Should be called anew each time a fresh
/// value is needed.
fn load(&self) -> Self::Guard;
}
impl<T, A: Access<T> + ?Sized, P: Deref<Target = A>> Access<T> for P {
type Guard = A::Guard;
fn load(&self) -> Self::Guard {
self.deref().load()
}
}
impl<T> Access<T> for dyn DynAccess<T> + '_ {
type Guard = DynGuard<T>;
fn load(&self) -> Self::Guard {
self.load()
}
}
impl<T> Access<T> for dyn DynAccess<T> + '_ + Send {
type Guard = DynGuard<T>;
fn load(&self) -> Self::Guard {
self.load()
}
}
impl<T> Access<T> for dyn DynAccess<T> + '_ + Sync + Send {
type Guard = DynGuard<T>;
fn load(&self) -> Self::Guard {
self.load()
}
}
impl<T: RefCnt, S: Strategy<T>> Access<T> for ArcSwapAny<T, S> {
type Guard = Guard<T, S>;
fn load(&self) -> Self::Guard {
self.load()
}
}
#[derive(Debug)]
#[doc(hidden)]
pub struct DirectDeref<T: RefCnt, S: Strategy<T>>(Guard<T, S>);
impl<T, S: Strategy<Arc<T>>> Deref for DirectDeref<Arc<T>, S> {
type Target = T;
fn deref(&self) -> &T {
self.0.deref().deref()
}
}
impl<T, S: Strategy<Arc<T>>> Access<T> for ArcSwapAny<Arc<T>, S> {
type Guard = DirectDeref<Arc<T>, S>;
fn load(&self) -> Self::Guard {
DirectDeref(self.load())
}
}
impl<T, S: Strategy<Rc<T>>> Deref for DirectDeref<Rc<T>, S> {
type Target = T;
fn deref(&self) -> &T {
self.0.deref().deref()
}
}
impl<T, S: Strategy<Rc<T>>> Access<T> for ArcSwapAny<Rc<T>, S> {
type Guard = DirectDeref<Rc<T>, S>;
fn load(&self) -> Self::Guard {
DirectDeref(self.load())
}
}
#[doc(hidden)]
pub struct DynGuard<T: ?Sized>(Box<dyn Deref<Target = T>>);
impl<T: ?Sized> Deref for DynGuard<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
/// An object-safe version of the [`Access`] trait.
///
/// This can be used instead of the [`Access`] trait in case a type erasure is desired. This has
/// the effect of performance hit (due to boxing of the result and due to dynamic dispatch), but
/// makes certain code simpler and possibly makes the executable smaller.
///
/// This is automatically implemented for everything that implements [`Access`].
///
/// # Examples
///
/// ```rust
/// use arc_swap::access::{Constant, DynAccess};
///
/// fn do_something(value: Box<dyn DynAccess<usize> + Send>) {
/// let v = value.load();
/// println!("{}", *v);
/// }
///
/// do_something(Box::new(Constant(42)));
/// ```
pub trait DynAccess<T> {
/// The equivalent of [`Access::load`].
fn load(&self) -> DynGuard<T>;
}
impl<T, A> DynAccess<T> for A
where
A: Access<T>,
A::Guard: 'static,
{
fn load(&self) -> DynGuard<T> {
DynGuard(Box::new(Access::load(self)))
}
}
/// [DynAccess] to [Access] wrapper.
///
/// In previous versions, `Box<dyn DynAccess>` didn't implement [Access], to use inside [Map] one
/// could use this wrapper. Since then, a way was found to solve it. In most cases, this wrapper is
/// no longer necessary.
///
/// This is left in place for two reasons:
/// * Backwards compatibility.
/// * Corner-cases not covered by the found solution. For example, trait inheritance in the form of
/// `Box<dyn SomeTrait>` where `SomeTrait: Access` doesn't work out of the box and still needs
/// this wrapper.
///
/// # Examples
///
/// The example is for the simple case (which is no longer needed, but may help as an inspiration).
///
/// ```rust
/// use std::sync::Arc;
///
/// use arc_swap::ArcSwap;
/// use arc_swap::access::{AccessConvert, DynAccess, Map};
///
/// struct Inner {
/// val: usize,
/// }
///
/// struct Middle {
/// inner: Inner,
/// }
///
/// struct Outer {
/// middle: Middle,
/// }
///
/// let outer = Arc::new(ArcSwap::from_pointee(Outer {
/// middle: Middle {
/// inner: Inner {
/// val: 42,
/// }
/// }
/// }));
///
/// let middle: Arc<dyn DynAccess<Middle>> =
/// Arc::new(Map::new(outer, |outer: &Outer| &outer.middle));
/// let inner: Arc<dyn DynAccess<Inner>> =
/// Arc::new(Map::new(AccessConvert(middle), |middle: &Middle| &middle.inner));
/// let guard = inner.load();
/// assert_eq!(42, guard.val);
/// ```
pub struct AccessConvert<D>(pub D);
impl<T, D> Access<T> for AccessConvert<D>
where
D: Deref,
D::Target: DynAccess<T>,
{
type Guard = DynGuard<T>;
fn load(&self) -> Self::Guard {
self.0.load()
}
}
#[doc(hidden)]
#[derive(Copy, Clone, Debug)]
pub struct MapGuard<G, F, T, R> {
guard: G,
projection: F,
_t: PhantomData<fn(&T) -> &R>,
}
impl<G, F, T, R> Deref for MapGuard<G, F, T, R>
where
G: Deref<Target = T>,
F: Fn(&T) -> &R,
{
type Target = R;
fn deref(&self) -> &R {
(self.projection)(&self.guard)
}
}
/// An adaptor to provide access to a part of larger structure.
///
/// This is the *active* part of this module. Use the [module documentation](index.html) for the
/// details.
#[derive(Copy, Clone, Debug)]
pub struct Map<A, T, F> {
access: A,
projection: F,
_t: PhantomData<fn() -> T>,
}
impl<A, T, F> Map<A, T, F> {
/// Creates a new instance.
///
/// # Parameters
///
/// * `access`: Access to the bigger structure. This is usually something like `Arc<ArcSwap>`
/// or `&ArcSwap`. It is technically possible to use any other [`Access`] here, though, for
/// example to sub-delegate into even smaller structure from a [`Map`] (or generic
/// [`Access`]).
/// * `projection`: A function (or closure) responsible to providing a reference into the
/// bigger bigger structure, selecting just subset of it. In general, it is expected to be
/// *cheap* (like only taking reference).
pub fn new<R>(access: A, projection: F) -> Self
where
F: Fn(&T) -> &R + Clone,
{
Map {
access,
projection,
_t: PhantomData,
}
}
}
impl<A, F, T, R> Access<R> for Map<A, T, F>
where
A: Access<T>,
F: Fn(&T) -> &R + Clone,
{
type Guard = MapGuard<A::Guard, F, T, R>;
fn load(&self) -> Self::Guard {
let guard = self.access.load();
MapGuard {
guard,
projection: self.projection.clone(),
_t: PhantomData,
}
}
}
#[doc(hidden)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ConstantDeref<T>(T);
impl<T> Deref for ConstantDeref<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
/// Access to an constant.
///
/// This wraps a constant value to provide [`Access`] to it. It is constant in the sense that,
/// unlike [`ArcSwapAny`] and [`Map`], the loaded value will always stay the same (there's no
/// remote `store`).
///
/// The purpose is mostly testing and plugging a parameter that works generically from code that
/// doesn't need the updating functionality.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Constant<T>(pub T);
impl<T: Clone> Access<T> for Constant<T> {
type Guard = ConstantDeref<T>;
fn load(&self) -> Self::Guard {
ConstantDeref(self.0.clone())
}
}
#[cfg(test)]
mod tests {
use super::super::{ArcSwap, ArcSwapOption};
use super::*;
fn check_static_dispatch_direct<A: Access<usize>>(a: A) {
assert_eq!(42, *a.load());
}
fn check_static_dispatch<A: Access<Arc<usize>>>(a: A) {
assert_eq!(42, **a.load());
}
/// Tests dispatching statically from arc-swap works
#[test]
fn static_dispatch() {
let a = ArcSwap::from_pointee(42);
check_static_dispatch_direct(&a);
check_static_dispatch(&a);
check_static_dispatch(a);
}
fn check_dyn_dispatch_direct(a: &dyn DynAccess<usize>) {
assert_eq!(42, *a.load());
}
fn check_dyn_dispatch(a: &dyn DynAccess<Arc<usize>>) {
assert_eq!(42, **a.load());
}
/// Tests we can also do a dynamic dispatch of the companion trait
#[test]
fn dyn_dispatch() {
let a = ArcSwap::from_pointee(42);
check_dyn_dispatch_direct(&a);
check_dyn_dispatch(&a);
}
fn check_transition<A>(a: A)
where
A: Access<usize>,
A::Guard: 'static,
{
check_dyn_dispatch_direct(&a)
}
/// Tests we can easily transition from the static dispatch trait to the dynamic one
#[test]
fn transition() {
let a = ArcSwap::from_pointee(42);
check_transition(&a);
check_transition(a);
}
/// Test we can dispatch from Arc<ArcSwap<_>> or similar.
#[test]
fn indirect() {
let a = Arc::new(ArcSwap::from_pointee(42));
check_static_dispatch(&a);
check_dyn_dispatch(&a);
}
struct Cfg {
value: usize,
}
#[test]
fn map() {
let a = ArcSwap::from_pointee(Cfg { value: 42 });
let map = a.map(|a: &Cfg| &a.value);
check_static_dispatch_direct(&map);
check_dyn_dispatch_direct(&map);
}
#[test]
fn map_option_some() {
let a = ArcSwapOption::from_pointee(Cfg { value: 42 });
let map = a.map(|a: &Option<Arc<Cfg>>| a.as_ref().map(|c| &c.value).unwrap());
check_static_dispatch_direct(&map);
check_dyn_dispatch_direct(&map);
}
#[test]
fn map_option_none() {
let a = ArcSwapOption::empty();
let map = a.map(|a: &Option<Arc<Cfg>>| a.as_ref().map(|c| &c.value).unwrap_or(&42));
check_static_dispatch_direct(&map);
check_dyn_dispatch_direct(&map);
}
#[test]
fn constant() {
let c = Constant(42);
check_static_dispatch_direct(c);
check_dyn_dispatch_direct(&c);
check_static_dispatch_direct(c);
}
#[test]
fn map_reload() {
let a = ArcSwap::from_pointee(Cfg { value: 0 });
let map = a.map(|cfg: &Cfg| &cfg.value);
assert_eq!(0, *Access::load(&map));
a.store(Arc::new(Cfg { value: 42 }));
assert_eq!(42, *Access::load(&map));
}
// Compile tests for dynamic access
fn _expect_access<T>(_: impl Access<T>) {}
fn _dyn_access<T>(x: Box<dyn DynAccess<T> + '_>) {
_expect_access(x)
}
fn _dyn_access_send<T>(x: Box<dyn DynAccess<T> + '_ + Send>) {
_expect_access(x)
}
fn _dyn_access_send_sync<T>(x: Box<dyn DynAccess<T> + '_ + Send + Sync>) {
_expect_access(x)
}
#[test]
#[allow(clippy::arc_with_non_send_sync)] // Whatever, it's tests...
fn double_dyn_access_complex() {
struct Inner {
val: usize,
}
struct Middle {
inner: Inner,
}
struct Outer {
middle: Middle,
}
let outer = Arc::new(ArcSwap::from_pointee(Outer {
middle: Middle {
inner: Inner { val: 42 },
},
}));
let middle: Arc<dyn DynAccess<Middle>> =
Arc::new(Map::new(outer, |outer: &Outer| &outer.middle));
let inner: Arc<dyn DynAccess<Inner>> =
Arc::new(Map::new(middle, |middle: &Middle| &middle.inner));
// Damn. We have the DynAccess wrapper in scope and need to disambiguate the inner.load()
let guard = Access::load(&inner);
assert_eq!(42, guard.val);
}
}