//! Defines [`SyncView`].

use core::clone::TrivialClone;
use core::cmp::Ordering;
use core::fmt;
use core::future::Future;
use core::hash::{Hash, Hasher};
use core::marker::{StructuralPartialEq, Tuple};
use core::ops::{Coroutine, CoroutineState};
use core::pin::Pin;
use core::task::{Context, Poll};

/// `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 [`Future`]s 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`:
///
/// ```compile_fail
/// 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.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[doc(alias = "SyncWrapper")]
#[doc(alias = "SyncCell")]
#[doc(alias = "Unique")]
#[doc(alias = "Exclusive")]
// `SyncView` can't have derived `PartialOrd`, `Clone`, etc. impls as they would
// use `&` access to the inner value, violating the `Sync` impl's safety
// requirements.
#[repr(transparent)]
pub struct SyncView<T: ?Sized> {
    inner: T,
}

// See `SyncView`'s docs for justification.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
unsafe impl<T: ?Sized> Sync for SyncView<T> {}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
const impl<T> Default for SyncView<T>
where
    T: [const] Default,
{
    #[inline]
    fn default() -> Self {
        Self { inner: Default::default() }
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T: ?Sized> fmt::Debug for SyncView<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.debug_struct("SyncView").finish_non_exhaustive()
    }
}

impl<T: Sized> SyncView<T> {
    /// Wrap a value in an `SyncView`
    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[must_use]
    #[inline]
    pub const fn new(t: T) -> Self {
        Self { inner: t }
    }

    /// Unwrap the value contained in the `SyncView`
    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[must_use]
    #[inline]
    pub const fn into_inner(self) -> T {
        self.inner
    }
}

impl<T: ?Sized> SyncView<T> {
    /// Gets pinned exclusive access to the underlying value.
    ///
    /// `SyncView` is considered to _structurally pin_ the underlying
    /// value, which means _unpinned_ `SyncView`s can produce _unpinned_
    /// access to the underlying value, but _pinned_ `SyncView`s only
    /// produce _pinned_ access to the underlying value.
    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[must_use]
    #[inline]
    pub const fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
        // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned
        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
    }

    /// 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`].
    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[must_use]
    #[inline]
    pub const fn from_mut(r: &'_ mut T) -> &'_ mut SyncView<T> {
        // SAFETY: repr is ≥ C, so refs have the same layout; and `SyncView` properties are `&mut`-agnostic
        unsafe { &mut *(r as *mut T as *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`].
    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[must_use]
    #[inline]
    pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut SyncView<T>> {
        // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned
        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
        unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) }
    }
}

impl<T: ?Sized + Sync> SyncView<T> {
    /// Gets pinned shared access to the underlying value.
    ///
    /// `SyncView` is considered to _structurally pin_ the underlying
    /// value, which means _unpinned_ `SyncView`s can produce _unpinned_
    /// access to the underlying value, but _pinned_ `SyncView`s only
    /// produce _pinned_ access to the underlying value.
    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
    #[must_use]
    #[inline]
    pub const fn as_pin_ref(self: Pin<&Self>) -> Pin<&T> {
        // SAFETY: `SyncView` can only produce `&T` if itself is unpinned
        // `Pin::map_unchecked` is not const, so we do this conversion manually
        unsafe { Pin::new_unchecked(&self.get_ref().inner) }
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
const impl<T> From<T> for SyncView<T> {
    #[inline]
    fn from(t: T) -> Self {
        Self::new(t)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
const impl<F, Args> FnOnce<Args> for SyncView<F>
where
    F: [const] FnOnce<Args>,
    Args: Tuple,
{
    type Output = F::Output;

    extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
        self.into_inner().call_once(args)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
const 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 {
        self.as_mut().call_mut(args)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
const 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 {
        self.as_ref().call(args)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<F, Args> AsyncFnOnce<Args> for SyncView<F>
where
    F: AsyncFnOnce<Args>,
    Args: Tuple,
{
    type CallOnceFuture = F::CallOnceFuture;

    type Output = F::Output;

    extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture {
        self.into_inner().async_call_once(args)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<F, Args> AsyncFnMut<Args> for SyncView<F>
where
    F: AsyncFnMut<Args>,
    Args: Tuple,
{
    type CallRefFuture<'a>
        = F::CallRefFuture<'a>
    where
        F: 'a;

    extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_> {
        self.as_mut().async_call_mut(args)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
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<'_> {
        self.as_ref().async_call(args)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T> Future for SyncView<T>
where
    T: Future + ?Sized,
{
    type Output = T::Output;

    #[inline]
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        self.as_pin_mut().poll(cx)
    }
}

#[unstable(feature = "coroutine_trait", issue = "43122")] // also #98407
impl<R, G> Coroutine<R> for SyncView<G>
where
    G: Coroutine<R> + ?Sized,
{
    type Yield = G::Yield;
    type Return = G::Return;

    #[inline]
    fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
        G::resume(self.as_pin_mut(), arg)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
const impl<T> AsRef<T> for SyncView<T>
where
    T: Sync + ?Sized,
{
    /// Gets shared access to the underlying value.
    #[inline]
    fn as_ref(&self) -> &T {
        &self.inner
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
const impl<T> AsMut<T> for SyncView<T>
where
    T: ?Sized,
{
    /// Gets exclusive access to the underlying value.
    #[inline]
    fn as_mut(&mut self) -> &mut T {
        &mut self.inner
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
const impl<T> Clone for SyncView<T>
where
    T: Sync + [const] Clone,
{
    #[inline]
    fn clone(&self) -> Self {
        Self { inner: self.inner.clone() }
    }
}

#[doc(hidden)]
#[unstable(feature = "trivial_clone", issue = "none")]
#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
const unsafe impl<T> TrivialClone for SyncView<T> where T: Sync + [const] TrivialClone {}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T> Copy for SyncView<T> where T: Sync + Copy {}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
const impl<T, U> PartialEq<SyncView<U>> for SyncView<T>
where
    T: Sync + [const] PartialEq<U> + ?Sized,
    U: Sync + ?Sized,
{
    #[inline]
    fn eq(&self, other: &SyncView<U>) -> bool {
        self.inner == other.inner
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T> StructuralPartialEq for SyncView<T> where T: Sync + StructuralPartialEq + ?Sized {}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
const impl<T> Eq for SyncView<T> where T: Sync + [const] Eq + ?Sized {}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T> Hash for SyncView<T>
where
    T: Sync + Hash + ?Sized,
{
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&self.inner, state)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
const impl<T, U> PartialOrd<SyncView<U>> for SyncView<T>
where
    T: Sync + [const] PartialOrd<U> + ?Sized,
    U: Sync + ?Sized,
{
    #[inline]
    fn partial_cmp(&self, other: &SyncView<U>) -> Option<Ordering> {
        self.inner.partial_cmp(&other.inner)
    }
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
const impl<T> Ord for SyncView<T>
where
    T: Sync + [const] Ord + ?Sized,
{
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        self.inner.cmp(&other.inner)
    }
}
