Struct SyncView

#[repr(transparent)]
pub struct SyncView<T: ?Sized> { pub(in ::sync::sync_view) inner: T }

SyncView provides mutable access, also referred to as exclusive access to the underlying value. However, it only permits immutable, or shared access to the underlying value when that value is Sync.

While this may seem not very useful, it allows SyncView to unconditionally implement Sync. Indeed, the safety requirements of Sync state that for SyncView to be Sync, it must be sound to share across threads, that is, it must be sound for &SyncView to cross thread boundaries. By design, a &SyncView<T> for non-Sync T has no API whatsoever, making it useless, thus harmless, thus memory safe.

Certain constructs like Futures can only be used with exclusive access, and are often Send but not Sync, so SyncView can be used as hint to the Rust compiler that something is Sync in practice.

Examples

Using a non-Sync future prevents the wrapping struct from being Sync:

use core::cell::Cell;

async fn other() {}
fn assert_sync<T: Sync>(t: T) {}
struct State<F> {
    future: F
}

assert_sync(State {
    future: async {
        let cell = Cell::new(1);
        let cell_ref = &cell;
        other().await;
        let value = cell_ref.get();
    }
});

SyncView ensures the struct is Sync without stripping the future of its functionality:

#![feature(exclusive_wrapper)]
use core::cell::Cell;
use core::sync::SyncView;

async fn other() {}
fn assert_sync<T: Sync>(t: T) {}
struct State<F> {
    future: SyncView<F>
}

assert_sync(State {
    future: SyncView::new(async {
        let cell = Cell::new(1);
        let cell_ref = &cell;
        other().await;
        let value = cell_ref.get();
    })
});

Parallels with a mutex

In some sense, SyncView can be thought of as a compile-time version of a mutex, as the borrow-checker guarantees that only one &mut can exist for any value. This is a parallel with the fact that & and &mut references together can be thought of as a compile-time version of a read-write lock.

Fields

inner: T

Implementations

impl<T: ?Sized + Sync> SyncView<T>

const fn as_pin_ref(self: Pin<&Self>) -> Pin<&T>

Gets pinned shared access to the underlying value.

SyncView is considered to structurally pin the underlying value, which means unpinned SyncViews can produce unpinned access to the underlying value, but pinned SyncViews only produce pinned access to the underlying value.

impl<T: ?Sized> SyncView<T>

const fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>

Gets pinned exclusive access to the underlying value.

SyncView is considered to structurally pin the underlying value, which means unpinned SyncViews can produce unpinned access to the underlying value, but pinned SyncViews only produce pinned access to the underlying value.

const fn from_mut(r: &mut T) -> &mut SyncView<T>

Build a mutable reference to an SyncView<T> from a mutable reference to a T. This allows you to skip building an SyncView with SyncView::new.

const fn from_pin_mut(r: Pin<&mut T>) -> Pin<&mut SyncView<T>>

Build a pinned mutable reference to an SyncView<T> from a pinned mutable reference to a T. This allows you to skip building an SyncView with SyncView::new.

impl<T: Sized> SyncView<T>

const fn new(t: T) -> Self

Wrap a value in an SyncView

const fn into_inner(self) -> T

Unwrap the value contained in the SyncView

Trait Implementations

impl<F, Args> AsyncFn<Args> for SyncView<F> where F: Sync + AsyncFn<Args>, Args: Tuple,

extern ""rust-call"" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_>

impl<F, Args> AsyncFnMut<Args> for SyncView<F> where F: AsyncFnMut<Args>, Args: Tuple,

type CallRefFuture<'a> = <F as AsyncFnMut<Args>>::CallRefFuture<'a>;
extern ""rust-call"" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_>

impl<F, Args> AsyncFnOnce<Args> for SyncView<F> where F: AsyncFnOnce<Args>, Args: Tuple,

type CallOnceFuture = <F as AsyncFnOnce<Args>>::CallOnceFuture;
type Output = <F as AsyncFnOnce<Args>>::Output;
extern ""rust-call"" fn async_call_once(self, args: Args) -> Self::CallOnceFuture

impl<F, Args> Fn<Args> for SyncView<F> where F: Sync + ~const Fn<Args>, Args: Tuple,

extern ""rust-call"" fn call(&self, args: Args) -> Self::Output

impl<F, Args> FnMut<Args> for SyncView<F> where F: ~const FnMut<Args>, Args: Tuple,

extern ""rust-call"" fn call_mut(&mut self, args: Args) -> Self::Output

impl<F, Args> FnOnce<Args> for SyncView<F> where F: ~const FnOnce<Args>, Args: Tuple,

type Output = <F as FnOnce<Args>>::Output;
extern ""rust-call"" fn call_once(self, args: Args) -> Self::Output

impl<R, G> Coroutine<R> for SyncView<G> where G: Coroutine<R> + ?Sized,

type Yield = <G as Coroutine<R>>::Yield;
type Return = <G as Coroutine<R>>::Return;
fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return>

impl<T> AsMut<T> for SyncView<T> where T: ?Sized,

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

Gets exclusive access to the underlying value.

impl<T> AsRef<T> for SyncView<T> where T: Sync + ?Sized,

fn as_ref(&self) -> &T

Gets shared access to the underlying value.

impl<T> Clone for SyncView<T> where T: Sync + ~const Clone,

fn clone(&self) -> Self

impl<T> Copy for SyncView<T> where T: Sync + Copy,

impl<T> Default for SyncView<T> where T: ~const Default,

fn default() -> Self

impl<T> Eq for SyncView<T> where T: Sync + ~const Eq + ?Sized,

impl<T> From<T> for SyncView<T>

fn from(t: T) -> Self

impl<T> Future for SyncView<T> where T: Future + ?Sized,

type Output = <T as Future>::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

impl<T> Hash for SyncView<T> where T: Sync + Hash + ?Sized,

fn hash<H: Hasher>(&self, state: &mut H)

impl<T> Ord for SyncView<T> where T: Sync + ~const Ord + ?Sized,

fn cmp(&self, other: &Self) -> Ordering

impl<T> StructuralPartialEq for SyncView<T> where T: Sync + StructuralPartialEq + ?Sized,

impl<T> TrivialClone for SyncView<T> where T: Sync + ~const TrivialClone,

impl<T, U> PartialEq<SyncView<U>> for SyncView<T> where T: Sync + ~const PartialEq<U> + ?Sized, U: Sync + ?Sized,

fn eq(&self, other: &SyncView<U>) -> bool

impl<T, U> PartialOrd<SyncView<U>> for SyncView<T> where T: Sync + ~const PartialOrd<U> + ?Sized, U: Sync + ?Sized,

fn partial_cmp(&self, other: &SyncView<U>) -> Option<Ordering>

impl<T: ?Sized> Debug for SyncView<T>

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

impl<T: ?Sized> Sync for SyncView<T>

Auto Trait Implementations

impl<T> Freeze for SyncView<T> where T: Freeze + ?Sized,

impl<T> RefUnwindSafe for SyncView<T> where T: RefUnwindSafe + ?Sized,

impl<T> Send for SyncView<T> where T: Send + ?Sized,

impl<T> Unpin for SyncView<T> where T: Unpin + ?Sized,

impl<T> UnsafeUnpin for SyncView<T> where T: UnsafeUnpin + ?Sized,

impl<T> UnwindSafe for SyncView<T> where T: UnwindSafe + ?Sized,

Blanket Implementations

impl<F> IntoFuture for SyncView<T> where F: Future,

type Output = <F as Future>::Output;
type IntoFuture = F;
fn into_future(self) -> <F as IntoFuture>::IntoFuture

impl<F> Pattern for SyncView<T> where F: FnMut(char) -> bool,

type Searcher<'a> = CharPredicateSearcher<'a, F>;
fn into_searcher<'a>(self, haystack: &'a str) -> CharPredicateSearcher<'a, F>
fn is_contained_in<'a>(self, haystack: &'a str) -> bool
fn is_prefix_of<'a>(self, haystack: &'a str) -> bool
fn strip_prefix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
where
    CharPredicateSearcher<'a, F>: ReverseSearcher<'a>,
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
where
    CharPredicateSearcher<'a, F>: ReverseSearcher<'a>,

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

fn type_id(&self) -> TypeId

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

fn borrow(&self) -> &T

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

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

impl<T> CloneToUninit for SyncView<T> where T: Clone,

unsafe fn clone_to_uninit(&self, dest: *mut u8)

impl<T> From<T> for SyncView<T>

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> From<never> for SyncView<T>

fn from(t: never) -> T

impl<T> Printable for SyncView<T> where T: Copy + Debug,

impl<T> SizeHint for SyncView<T> where T: ?Sized,

fn lower_bound(&self) -> usize
fn upper_bound(&self) -> Option<usize>

impl<T> SizedTypeProperties for SyncView<T>

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

fn into(self) -> U

Calls U::from(self).

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

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

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

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

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