pub struct UnsafeSendCell<T>(/* private fields */);Expand description
A cell that can be sent across threads without runtime checks.
UnsafeSendCell<T> wraps a value of type T (which may not implement Send) and
provides an unsafe Send implementation. Unlike crate::SendCell, this type
performs no runtime checks and requires manual verification of thread safety.
All access to the wrapped value requires unsafe blocks, making the safety
requirements explicit at the call site.
§Safety
When using UnsafeSendCell<T>, you must ensure:
- The wrapped value is never accessed concurrently from multiple threads
- If the value is moved between threads, it’s safe to do so
- Drop implementations are safe to run on any thread
- External synchronization is provided when necessary
§Examples
§With Non-Drop Types (Safe Constructor)
use send_cells::UnsafeSendCell;
// i32 doesn't implement Drop, so this is safe
let cell = UnsafeSendCell::new(42);
let value = unsafe { cell.get() };
assert_eq!(*value, 42);§With Drop Types (Unsafe Constructor)
use send_cells::UnsafeSendCell;
use std::rc::Rc;
let data = Rc::new("hello");
// SAFETY: We guarantee this won't be accessed from multiple threads
let cell = unsafe { UnsafeSendCell::new_unchecked(data) };
// SAFETY: We're still on the original thread
let value = unsafe { cell.get() };
assert_eq!(**value, "hello");§Thread Safety Verification
use send_cells::UnsafeSendCell;
use std::rc::Rc;
fn assert_send<T: Send>(_: T) {}
let data = Rc::new(42);
let cell = unsafe { UnsafeSendCell::new_unchecked(data) };
// The cell implements Send even though Rc<T> doesn't
assert_send(cell);§When to Use
This type is appropriate when:
- You have platform guarantees about thread usage
- Maximum performance is required and safety can be manually verified
- Working with callback-based APIs with thread guarantees
- Prototyping concurrent code
For safer alternatives with runtime checks, see crate::SendCell.
Implementations§
Source§impl<T> UnsafeSendCell<T>
impl<T> UnsafeSendCell<T>
Sourcepub unsafe fn new_unchecked(value: T) -> Self
pub unsafe fn new_unchecked(value: T) -> Self
Creates a new cell without verifying thread safety.
§Safety
The caller must ensure that:
- The value
Tcan be safely moved between threads - If
TimplementsDrop, it’s safe to drop on any thread - The value won’t be accessed concurrently from multiple threads
- Any thread-local state dependencies are properly handled
§Examples
use send_cells::UnsafeSendCell;
use std::rc::Rc;
let data = Rc::new(42);
// SAFETY: We guarantee this won't be shared between threads
let cell = unsafe { UnsafeSendCell::new_unchecked(data) };Sourcepub fn new(value: T) -> Self
pub fn new(value: T) -> Self
Creates a new cell for types that don’t implement Drop.
This constructor is safe because it statically verifies that the type T
does not implement Drop. Types without custom drop implementations are
generally safe to move between threads (assuming no other thread-local
dependencies).
§Panics
Panics if T implements Drop. Use Self::new_unchecked for types
that implement Drop.
§Examples
use send_cells::UnsafeSendCell;
// i32 doesn't implement Drop, so this is safe
let cell = UnsafeSendCell::new(42);
let value = unsafe { cell.get() };
assert_eq!(*value, 42);use send_cells::UnsafeSendCell;
use std::rc::Rc;
// This will panic because Rc<T> implements Drop
let data = Rc::new(42);
let cell = UnsafeSendCell::new(data); // Panics!Sourcepub unsafe fn get(&self) -> &T
pub unsafe fn get(&self) -> &T
Gets a reference to the underlying value.
§Safety
The caller must ensure that:
- No other thread is concurrently accessing the value
- The value is safe to access from the current thread
- All thread-safety invariants are maintained
This method is unsafe because it bypasses Rust’s normal Send/Sync checking. The safety requirements depend on your specific use case:
- If the cell was never actually sent between threads, this is safe
- If the cell was sent between threads, you must have external guarantees about thread safety
§Examples
use send_cells::UnsafeSendCell;
let cell = UnsafeSendCell::new(42);
// SAFETY: We're on the same thread and i32 is safe to access
let value = unsafe { cell.get() };
assert_eq!(*value, 42);Sourcepub unsafe fn get_mut(&mut self) -> &mut T
pub unsafe fn get_mut(&mut self) -> &mut T
Gets a mutable reference to the underlying value.
§Safety
The caller must ensure that:
- No other thread is concurrently accessing the value
- The value is safe to access mutably from the current thread
- No other references (mutable or immutable) to the value exist
- All thread-safety invariants are maintained
This method is unsafe because it bypasses Rust’s normal Send/Sync checking and because mutable access requires exclusive access guarantees.
§Examples
use send_cells::UnsafeSendCell;
let mut cell = UnsafeSendCell::new(42);
// SAFETY: We have exclusive access and i32 is safe to mutate
unsafe {
*cell.get_mut() = 100;
}
let value = unsafe { cell.get() };
assert_eq!(*value, 100);Sourcepub unsafe fn into_inner(self) -> T
pub unsafe fn into_inner(self) -> T
Consumes the cell and returns the wrapped value.
§Safety
The caller must ensure that:
- It’s safe to take ownership of the value on the current thread
- The value can be safely dropped on the current thread
- No other references to the value exist
This method is unsafe because it bypasses Rust’s normal Send checking when taking ownership of the value.
§Examples
use send_cells::UnsafeSendCell;
let cell = UnsafeSendCell::new(42);
// SAFETY: i32 is safe to take ownership of on any thread
let value = unsafe { cell.into_inner() };
assert_eq!(value, 42);Source§impl<T: Future> UnsafeSendCell<T>
impl<T: Future> UnsafeSendCell<T>
Sourcepub unsafe fn into_future(self) -> UnsafeSendFuture<T> ⓘ
pub unsafe fn into_future(self) -> UnsafeSendFuture<T> ⓘ
Converts the cell into a future that implements Send.
This method consumes the UnsafeSendCell and returns an UnsafeSendFuture
that implements Send. The returned future can be moved between threads
but requires the same safety guarantees as the original cell.
§Safety
The caller must ensure that:
- The future won’t be polled concurrently from multiple threads
- If the future is moved between threads, it’s safe to do so
- The future’s state and any captured variables are thread-safe
- Drop implementations are safe to run on any thread
§Examples
use send_cells::UnsafeSendCell;
use std::rc::Rc;
async fn non_send_future() -> i32 {
let _local = Rc::new(42); // Non-Send
42
}
let future = non_send_future();
// SAFETY: We guarantee this future won't be sent between threads
let cell = unsafe { UnsafeSendCell::new_unchecked(future) };
let send_future = unsafe { cell.into_future() };
// Now it can be used in Send contexts
fn requires_send<T: Send>(_: T) {}
requires_send(send_future);