use std::marker::PhantomData;
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
use super::gen_lock::LockStorage;
use super::ref_cnt::RefCnt;
use super::{ArcSwapAny, Guard};
pub trait Access<T> {
type Guard: Deref<Target = T>;
fn load(&self) -> Self::Guard;
}
impl<T, A: Access<T>, P: Deref<Target = A>> Access<T> for P {
type Guard = A::Guard;
fn load(&self) -> Self::Guard {
self.deref().load()
}
}
impl<T: RefCnt, S: LockStorage> Access<T> for ArcSwapAny<T, S> {
type Guard = Guard<'static, T>;
fn load(&self) -> Self::Guard {
self.load()
}
}
#[derive(Debug)]
pub struct DirectDeref<T: RefCnt>(Guard<'static, T>);
impl<T> Deref for DirectDeref<Arc<T>> {
type Target = T;
fn deref(&self) -> &T {
self.0.deref().deref()
}
}
impl<T, S: LockStorage> Access<T> for ArcSwapAny<Arc<T>, S> {
type Guard = DirectDeref<Arc<T>>;
fn load(&self) -> Self::Guard {
DirectDeref(self.load())
}
}
impl<T> Deref for DirectDeref<Rc<T>> {
type Target = T;
fn deref(&self) -> &T {
self.0.deref().deref()
}
}
impl<T, S: LockStorage> Access<T> for ArcSwapAny<Rc<T>, S> {
type Guard = DirectDeref<Rc<T>>;
fn load(&self) -> Self::Guard {
DirectDeref(self.load())
}
}
pub struct DynGuard<T: ?Sized>(Box<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)))
}
}
#[derive(Copy, Clone, Debug)]
pub struct MapGuard<G, T> {
_guard: G,
value: *const T,
}
unsafe impl<G, T> Send for MapGuard<G, T>
where
G: Send,
for<'a> &'a T: Send,
{
}
unsafe impl<G, T> Sync for MapGuard<G, T>
where
G: Sync,
for<'a> &'a T: Sync,
{
}
impl<G, T> Deref for MapGuard<G, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.value }
}
}
#[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,
{
Map {
access,
projection,
_t: PhantomData,
}
}
}
impl<A, T, F, R> Access<R> for Map<A, T, F>
where
A: Access<T>,
F: Fn(&T) -> &R,
{
type Guard = MapGuard<A::Guard, R>;
fn load(&self) -> Self::Guard {
let guard = self.access.load();
let value: *const _ = (self.projection)(&guard);
MapGuard {
_guard: guard,
value,
}
}
}
#[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: &DynAccess<usize>) {
assert_eq!(42, *a.load());
}
fn check_dyn_dispatch(a: &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));
}
}