#![deny(unsafe_code)]
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};
pub trait Access<T> {
type Guard: Deref<Target = T>;
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
}
}
pub trait DynAccess<T> {
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)))
}
}
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)
}
}
#[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> {
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
}
}
#[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());
}
#[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());
}
#[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)
}
#[test]
fn transition() {
let a = ArcSwap::from_pointee(42);
check_transition(&a);
check_transition(a);
}
#[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));
}
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)] 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));
let guard = Access::load(&inner);
assert_eq!(42, guard.val);
}
}