UnsafeSendCell

Struct UnsafeSendCell 

Source
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>

Source

pub unsafe fn new_unchecked(value: T) -> Self

Creates a new cell without verifying thread safety.

§Safety

The caller must ensure that:

  • The value T can be safely moved between threads
  • If T implements Drop, 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) };
Source

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!
Source

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);
Source

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);
Source

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>

Source

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);

Trait Implementations§

Source§

impl<T> Debug for UnsafeSendCell<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Default> Default for UnsafeSendCell<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T> From<T> for UnsafeSendCell<T>

Source§

fn from(value: T) -> Self

Converts to this type from the input type.
Source§

impl<T> Send for UnsafeSendCell<T>

Auto Trait Implementations§

§

impl<T> Freeze for UnsafeSendCell<T>
where T: Freeze,

§

impl<T> RefUnwindSafe for UnsafeSendCell<T>
where T: RefUnwindSafe,

§

impl<T> Sync for UnsafeSendCell<T>
where T: Sync,

§

impl<T> Unpin for UnsafeSendCell<T>
where T: Unpin,

§

impl<T> UnwindSafe for UnsafeSendCell<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.