From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- .../rust/crossbeam-epoch-0.8.0/src/deferred.rs | 140 +++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 third_party/rust/crossbeam-epoch-0.8.0/src/deferred.rs (limited to 'third_party/rust/crossbeam-epoch-0.8.0/src/deferred.rs') diff --git a/third_party/rust/crossbeam-epoch-0.8.0/src/deferred.rs b/third_party/rust/crossbeam-epoch-0.8.0/src/deferred.rs new file mode 100644 index 0000000000..3d22ee633e --- /dev/null +++ b/third_party/rust/crossbeam-epoch-0.8.0/src/deferred.rs @@ -0,0 +1,140 @@ +use alloc::boxed::Box; +use core::fmt; +use core::marker::PhantomData; +use core::mem; +use core::ptr; + +/// Number of words a piece of `Data` can hold. +/// +/// Three words should be enough for the majority of cases. For example, you can fit inside it the +/// function pointer together with a fat pointer representing an object that needs to be destroyed. +const DATA_WORDS: usize = 3; + +/// Some space to keep a `FnOnce()` object on the stack. +type Data = [usize; DATA_WORDS]; + +/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap. +/// +/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure. +pub struct Deferred { + call: unsafe fn(*mut u8), + data: Data, + _marker: PhantomData<*mut ()>, // !Send + !Sync +} + +impl fmt::Debug for Deferred { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + f.pad("Deferred { .. }") + } +} + +impl Deferred { + /// Constructs a new `Deferred` from a `FnOnce()`. + pub fn new(f: F) -> Self { + let size = mem::size_of::(); + let align = mem::align_of::(); + + unsafe { + if size <= mem::size_of::() && align <= mem::align_of::() { + // TODO(taiki-e): when the minimum supported Rust version is bumped to 1.36+, + // replace this with `mem::MaybeUninit`. + #[allow(deprecated)] + let mut data: Data = mem::uninitialized(); + ptr::write(&mut data as *mut Data as *mut F, f); + + unsafe fn call(raw: *mut u8) { + let f: F = ptr::read(raw as *mut F); + f(); + } + + Deferred { + call: call::, + data, + _marker: PhantomData, + } + } else { + let b: Box = Box::new(f); + // TODO(taiki-e): when the minimum supported Rust version is bumped to 1.36+, + // replace this with `mem::MaybeUninit`. + #[allow(deprecated)] + let mut data: Data = mem::uninitialized(); + ptr::write(&mut data as *mut Data as *mut Box, b); + + unsafe fn call(raw: *mut u8) { + let b: Box = ptr::read(raw as *mut Box); + (*b)(); + } + + Deferred { + call: call::, + data, + _marker: PhantomData, + } + } + } + } + + /// Calls the function. + #[inline] + pub fn call(mut self) { + let call = self.call; + unsafe { call(&mut self.data as *mut Data as *mut u8) }; + } +} + +#[cfg(test)] +mod tests { + use super::Deferred; + use std::cell::Cell; + + #[test] + fn on_stack() { + let fired = &Cell::new(false); + let a = [0usize; 1]; + + let d = Deferred::new(move || { + drop(a); + fired.set(true); + }); + + assert!(!fired.get()); + d.call(); + assert!(fired.get()); + } + + #[test] + fn on_heap() { + let fired = &Cell::new(false); + let a = [0usize; 10]; + + let d = Deferred::new(move || { + drop(a); + fired.set(true); + }); + + assert!(!fired.get()); + d.call(); + assert!(fired.get()); + } + + #[test] + fn string() { + let a = "hello".to_string(); + let d = Deferred::new(move || assert_eq!(a, "hello")); + d.call(); + } + + #[test] + fn boxed_slice_i32() { + let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice(); + let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7])); + d.call(); + } + + #[test] + fn long_slice_usize() { + let a: [usize; 5] = [2, 3, 5, 7, 11]; + let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11])); + d.call(); + } +} -- cgit v1.2.3