Skip to content

Commit 118d76a

Browse files
committed
feat(closure): add a specific impl of IntoClosureConst for passing exactly one &(impl Sized)
1 parent 17eba81 commit 118d76a

File tree

1 file changed

+44
-10
lines changed

1 file changed

+44
-10
lines changed

src/r3_core/src/closure.rs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,19 @@ impl Closure {
160160
}
161161
}
162162

163+
unsafe extern "C" fn trampoline_zst<T: FnOnce()>(_: ClosureEnv) {
164+
let func: T = unsafe { transmute(()) };
165+
func()
166+
}
167+
168+
unsafe extern "C" fn trampoline_indirect<T: FnOnce()>(env: ClosureEnv) {
169+
let p_func: *const T = unsafe { transmute(env) };
170+
// FIXME: Since there's no trait indicating the lack of interior mutability,
171+
// we have to copy `T` onto stack
172+
let func: T = unsafe { p_func.read() };
173+
func()
174+
}
175+
163176
/// A trait for converting a value into a [`Closure`] at compile time.
164177
///
165178
/// The conversion may involve compile-time heap allocation
@@ -174,6 +187,9 @@ impl Closure {
174187
///
175188
/// // `impl FnOnce()` → `Closure`
176189
/// const _: Closure = (|| {}).into_closure_const();
190+
///
191+
/// // `(&'static P0, impl FnOnce(&'static P0))` → `Closure`
192+
/// const _: Closure = (&42, |_: &i32| {}).into_closure_const();
177193
/// ```
178194
pub trait IntoClosureConst {
179195
/// Perform conversion to [`Closure`], potentially using a compile-time
@@ -188,17 +204,29 @@ impl<T: FnOnce() + Copy + Send + 'static> const IntoClosureConst for T {
188204
}
189205
}
190206

191-
unsafe extern "C" fn trampoline_zst<T: FnOnce()>(_: ClosureEnv) {
192-
let func: T = unsafe { transmute(()) };
193-
func()
194-
}
207+
/// Packs `&P0` directly in [`ClosureEnv`][] if `T` is zero-sized.
208+
///
209+
/// Due to compiler restrictions, this optimization is currently impossible
210+
/// to do in the generic constructor ([`Closure::from_fn_const`]).
211+
// FIXME: See above
212+
impl<T: FnOnce(&'static P0) + Copy + Send + 'static, P0: Sync + 'static> const IntoClosureConst
213+
for (&'static P0, T)
214+
{
215+
fn into_closure_const(self) -> Closure {
216+
unsafe extern "C" fn trampoline_ptr_spec<T: FnOnce(&'static P0), P0: 'static>(
217+
env: ClosureEnv,
218+
) {
219+
let p0: &'static P0 = unsafe { transmute(env) };
220+
let func: T = unsafe { transmute(()) };
221+
func(p0)
222+
}
195223

196-
unsafe extern "C" fn trampoline_indirect<T: FnOnce()>(env: ClosureEnv) {
197-
let p_func: *const T = unsafe { transmute(env) };
198-
// FIXME: Since there's no trait indicating the lack of interior mutability,
199-
// we have to copy `T` onto stack
200-
let func: T = unsafe { p_func.read() };
201-
func()
224+
if size_of::<T>() == 0 {
225+
unsafe { Closure::from_raw_parts(trampoline_zst_param::<T, P0>, transmute(self.0)) }
226+
} else {
227+
(move || (self.1)(self.0)).into_closure_const()
228+
}
229+
}
202230
}
203231

204232
#[cfg(test)]
@@ -269,4 +297,10 @@ mod tests {
269297
ADD2.call();
270298
assert_eq!(STATE.load(Ordering::Relaxed), 1 + 4 + 2);
271299
}
300+
301+
#[test]
302+
fn ptr_env_spec() {
303+
const C: Closure = (&42, |x: &i32| assert_eq!(*x, 42)).into_closure_const();
304+
C.call();
305+
}
272306
}

0 commit comments

Comments
 (0)