From 3e5a8f3bd43c420ef923e975b4afb80f6d6f120f Mon Sep 17 00:00:00 2001 From: Michael de Silva <michael@mwdesilva.com> Date: Mon, 11 Oct 2021 13:40:37 +0530 Subject: [PATCH 1/5] WIP adding Fn* impls to Arc; FIXME cannot move out of Arc as Fn does not Copy --- library/alloc/src/sync.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 6e8da849e64cd..1fbcd4af1c3c1 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1663,6 +1663,26 @@ impl Arc<dyn Any + Send + Sync> { } } +impl<Args, F: FnOnce<Args> + ?Sized> FnOnce<Args> for Arc<F> { + type Output = <F as FnOnce<Args>>::Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output { + <F as FnOnce<Args>>::call_once(*self, args) + } +} + +impl<Args, F: FnMut<Args> + ?Sized> FnMut<Args> for Arc<F> { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { + <F as FnMut<Args>>::call_mut(self, args) + } +} + +impl<Args, F: Fn<Args> + ?Sized> Fn<Args> for Arc<F> { + extern "rust-call" fn call(&self, args: Args) -> Self::Output { + <F as Fn<Args>>::call(self, args) + } +} + impl<T> Weak<T> { /// Constructs a new `Weak<T>`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. From ad0b709fb3b3e7567aeb721512223d338c0766a2 Mon Sep 17 00:00:00 2001 From: Michael de Silva <michael@mwdesilva.com> Date: Mon, 11 Oct 2021 16:36:24 +0530 Subject: [PATCH 2/5] Allow Copy for closure --- library/alloc/src/sync.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1fbcd4af1c3c1..a7cb74fcb6799 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1663,7 +1663,7 @@ impl Arc<dyn Any + Send + Sync> { } } -impl<Args, F: FnOnce<Args> + ?Sized> FnOnce<Args> for Arc<F> { +impl<Args, F: FnOnce<Args> + ?Sized + Copy> FnOnce<Args> for Arc<F> { type Output = <F as FnOnce<Args>>::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output { @@ -1671,13 +1671,13 @@ impl<Args, F: FnOnce<Args> + ?Sized> FnOnce<Args> for Arc<F> { } } -impl<Args, F: FnMut<Args> + ?Sized> FnMut<Args> for Arc<F> { +impl<Args, F: FnMut<Args> + ?Sized + Copy> FnMut<Args> for Arc<F> { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { <F as FnMut<Args>>::call_mut(self, args) } } -impl<Args, F: Fn<Args> + ?Sized> Fn<Args> for Arc<F> { +impl<Args, F: Fn<Args> + ?Sized + Copy> Fn<Args> for Arc<F> { extern "rust-call" fn call(&self, args: Args) -> Self::Output { <F as Fn<Args>>::call(self, args) } From e0cffea7b63c3f276c222f7945d0a9c5e351f915 Mon Sep 17 00:00:00 2001 From: Michael de Silva <michael@mwdesilva.com> Date: Mon, 11 Oct 2021 18:52:53 +0530 Subject: [PATCH 3/5] Remove Copy and add impls for Fn only, due to Arc --- library/alloc/src/sync.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a7cb74fcb6799..cb0b0ad2adcb9 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1663,21 +1663,24 @@ impl Arc<dyn Any + Send + Sync> { } } -impl<Args, F: FnOnce<Args> + ?Sized + Copy> FnOnce<Args> for Arc<F> { +#[stable(feature = "arc_fn_impls", since = "1.57.0")] +impl<Args, F: Fn<Args> + ?Sized> FnOnce<Args> for Arc<F> { type Output = <F as FnOnce<Args>>::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output { - <F as FnOnce<Args>>::call_once(*self, args) + <F as Fn<Args>>::call(&self, args) } } -impl<Args, F: FnMut<Args> + ?Sized + Copy> FnMut<Args> for Arc<F> { +#[stable(feature = "arc_fn_impls", since = "1.57.0")] +impl<Args, F: Fn<Args> + ?Sized> FnMut<Args> for Arc<F> { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { - <F as FnMut<Args>>::call_mut(self, args) + <F as Fn<Args>>::call(self, args) } } -impl<Args, F: Fn<Args> + ?Sized + Copy> Fn<Args> for Arc<F> { +#[stable(feature = "arc_fn_impls", since = "1.57.0")] +impl<Args, F: Fn<Args> + ?Sized> Fn<Args> for Arc<F> { extern "rust-call" fn call(&self, args: Args) -> Self::Output { <F as Fn<Args>>::call(self, args) } From 655aa927cef59c060856c037578033dbfccdba33 Mon Sep 17 00:00:00 2001 From: Michael de Silva <michael@mwdesilva.com> Date: Mon, 11 Oct 2021 20:04:59 +0530 Subject: [PATCH 4/5] Add tests for adding Fn impl to Arc --- library/alloc/src/sync/tests.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 4ccb32fbbf63d..a62b86adf890e 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -618,3 +618,18 @@ fn test_arc_cyclic_two_refs() { assert_eq!(Arc::strong_count(&two_refs), 3); assert_eq!(Arc::weak_count(&two_refs), 2); } + +#[test] +fn test_arc_fn() { + let f = || String::from("hello"); + let f: Arc<dyn Fn() -> String> = Arc::new(f); + + assert_eq!(quox(&f), "hello"); +} + +fn quox<F>(f: &F) -> String +where + F: Fn() -> String, +{ + f() +} From 1f60e2f032bea49521b23377552ca8e07d6378d9 Mon Sep 17 00:00:00 2001 From: Michael de Silva <michael@mwdesilva.com> Date: Tue, 12 Oct 2021 19:21:28 +0530 Subject: [PATCH 5/5] Improve test, using test in #71570 --- library/alloc/src/sync/tests.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index a62b86adf890e..3b7620f23e5f2 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -633,3 +633,25 @@ where { f() } + +#[test] +fn test_arc_fn2() { + fn apply_fn_once<T>(v: T, f: impl FnOnce(T)) { + f(v) + } + fn apply_fn_mut<T>(v: T, mut f: impl FnMut(T)) { + f(v) + } + fn apply_fn<T>(v: T, f: impl Fn(T)) { + f(v) + } + + let x = Mutex::new(0); + let f = Arc::new(|v: i32| *x.lock().unwrap() += v); + + apply_fn_once(1, f.clone()); + apply_fn_mut(2, f.clone()); + apply_fn(4, f.clone()); + + assert_eq!(*x.lock().unwrap(), 7); +}