From 3e5a8f3bd43c420ef923e975b4afb80f6d6f120f Mon Sep 17 00:00:00 2001 From: Michael de Silva 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 { } } +impl + ?Sized> FnOnce for Arc { + type Output = >::Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output { + >::call_once(*self, args) + } +} + +impl + ?Sized> FnMut for Arc { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { + >::call_mut(self, args) + } +} + +impl + ?Sized> Fn for Arc { + extern "rust-call" fn call(&self, args: Args) -> Self::Output { + >::call(self, args) + } +} + impl Weak { /// Constructs a new `Weak`, 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 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 { } } -impl + ?Sized> FnOnce for Arc { +impl + ?Sized + Copy> FnOnce for Arc { type Output = >::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output { @@ -1671,13 +1671,13 @@ impl + ?Sized> FnOnce for Arc { } } -impl + ?Sized> FnMut for Arc { +impl + ?Sized + Copy> FnMut for Arc { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { >::call_mut(self, args) } } -impl + ?Sized> Fn for Arc { +impl + ?Sized + Copy> Fn for Arc { extern "rust-call" fn call(&self, args: Args) -> Self::Output { >::call(self, args) } From e0cffea7b63c3f276c222f7945d0a9c5e351f915 Mon Sep 17 00:00:00 2001 From: Michael de Silva 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 { } } -impl + ?Sized + Copy> FnOnce for Arc { +#[stable(feature = "arc_fn_impls", since = "1.57.0")] +impl + ?Sized> FnOnce for Arc { type Output = >::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output { - >::call_once(*self, args) + >::call(&self, args) } } -impl + ?Sized + Copy> FnMut for Arc { +#[stable(feature = "arc_fn_impls", since = "1.57.0")] +impl + ?Sized> FnMut for Arc { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { - >::call_mut(self, args) + >::call(self, args) } } -impl + ?Sized + Copy> Fn for Arc { +#[stable(feature = "arc_fn_impls", since = "1.57.0")] +impl + ?Sized> Fn for Arc { extern "rust-call" fn call(&self, args: Args) -> Self::Output { >::call(self, args) } From 655aa927cef59c060856c037578033dbfccdba33 Mon Sep 17 00:00:00 2001 From: Michael de Silva 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 String> = Arc::new(f); + + assert_eq!(quox(&f), "hello"); +} + +fn quox(f: &F) -> String +where + F: Fn() -> String, +{ + f() +} From 1f60e2f032bea49521b23377552ca8e07d6378d9 Mon Sep 17 00:00:00 2001 From: Michael de Silva 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(v: T, f: impl FnOnce(T)) { + f(v) + } + fn apply_fn_mut(v: T, mut f: impl FnMut(T)) { + f(v) + } + fn apply_fn(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); +}