diff --git a/CHANGELOG.md b/CHANGELOG.md index 3be615b..b41d0c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +* The `AccessConvert` wrapper is needed less often in practice (#77). + # 1.5.1 * bug: Insufficient synchronization on weak platforms (#76). diff --git a/src/access.rs b/src/access.rs index 2bb098e..c50e20d 100644 --- a/src/access.rs +++ b/src/access.rs @@ -112,13 +112,37 @@ pub trait Access { fn load(&self) -> Self::Guard; } -impl, P: Deref> Access for P { +impl + ?Sized, P: Deref> Access for P { type Guard = A::Guard; fn load(&self) -> Self::Guard { self.deref().load() } } +impl Access for dyn DynAccess + '_ { + type Guard = DynGuard; + + fn load(&self) -> Self::Guard { + self.load() + } +} + +impl Access for dyn DynAccess + '_ + Send { + type Guard = DynGuard; + + fn load(&self) -> Self::Guard { + self.load() + } +} + +impl Access for dyn DynAccess + '_ + Sync + Send { + type Guard = DynGuard; + + fn load(&self) -> Self::Guard { + self.load() + } +} + impl> Access for ArcSwapAny { type Guard = Guard; @@ -206,8 +230,19 @@ where /// [DynAccess] to [Access] wrapper. /// -/// A workaround to allow double-dyn mapping, since `Box` doesn't implement [Access] -/// and [Map] needs that. +/// In previous versions, `Box` 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` 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; @@ -462,4 +497,48 @@ mod tests { a.store(Arc::new(Cfg { value: 42 })); assert_eq!(42, *Access::load(&map)); } + + // Compile tests for dynamic access + fn _expect_access(_: impl Access) {} + + fn _dyn_access(x: Box + '_>) { + _expect_access(x) + } + + fn _dyn_access_send(x: Box + '_ + Send>) { + _expect_access(x) + } + + fn _dyn_access_send_sync(x: Box + '_ + Send + Sync>) { + _expect_access(x) + } + + #[test] + 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> = + Arc::new(Map::new(outer, |outer: &Outer| &outer.middle)); + let inner: Arc> = + 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); + } }