Skip to content

Commit

Permalink
Merge pull request #85 from vorner/box-dyn
Browse files Browse the repository at this point in the history
Box dyn
  • Loading branch information
vorner committed Dec 25, 2022
2 parents 102bac9 + 7194930 commit a41840b
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 3 deletions.
2 changes: 2 additions & 0 deletions 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).
Expand Down
85 changes: 82 additions & 3 deletions src/access.rs
Expand Up @@ -112,13 +112,37 @@ pub trait Access<T> {
fn load(&self) -> Self::Guard;
}

impl<T, A: Access<T>, P: Deref<Target = A>> Access<T> for P {
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>;

Expand Down Expand Up @@ -206,8 +230,19 @@ where

/// [DynAccess] to [Access] wrapper.
///
/// A workaround to allow double-dyn mapping, since `Box<dyn DynAccess>` doesn't implement [Access]
/// and [Map] needs that.
/// 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;
Expand Down Expand Up @@ -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<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]
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);
}
}

1 comment on commit a41840b

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Track benchmarks

Benchmark suite Current: a41840b Previous: 102bac9 Ratio
uncontended/load 18 ns/iter (± 0) 20 ns/iter (± 0) 0.90
uncontended/load_full 32 ns/iter (± 0) 32 ns/iter (± 0) 1
uncontended/load_many 51 ns/iter (± 0) 52 ns/iter (± 0) 0.98
uncontended/store 158 ns/iter (± 0) 158 ns/iter (± 0) 1
uncontended/cache 0 ns/iter (± 0) 0 ns/iter (± 0) NaN
concurrent_loads/load 22 ns/iter (± 8) 28 ns/iter (± 9) 0.79
concurrent_loads/load_full 41 ns/iter (± 15) 40 ns/iter (± 14) 1.02
concurrent_loads/load_many 87 ns/iter (± 25) 64 ns/iter (± 24) 1.36
concurrent_loads/store 1252 ns/iter (± 712) 1437 ns/iter (± 533) 0.87
concurrent_loads/cache 1 ns/iter (± 0) 1 ns/iter (± 0) 1
concurrent_store/load 49 ns/iter (± 1) 55 ns/iter (± 4) 0.89
concurrent_store/load_full 98 ns/iter (± 17) 96 ns/iter (± 28) 1.02
concurrent_store/load_many 129 ns/iter (± 2) 131 ns/iter (± 6) 0.98
concurrent_store/store 1393 ns/iter (± 30) 1592 ns/iter (± 23) 0.88
concurrent_store/cache 1 ns/iter (± 0) 1 ns/iter (± 0) 1

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.