bevy_utils/
syncunsafecell.rs

1//! A reimplementation of the currently unstable [`std::cell::SyncUnsafeCell`]
2//!
3//! [`std::cell::SyncUnsafeCell`]: https://doc.rust-lang.org/nightly/std/cell/struct.SyncUnsafeCell.html
4
5pub use core::cell::UnsafeCell;
6use core::ptr;
7
8/// [`UnsafeCell`], but [`Sync`].
9///
10/// See [tracking issue](https://github.com/rust-lang/rust/issues/95439) for upcoming native impl,
11/// which should replace this one entirely (except `from_mut`).
12///
13/// This is just an `UnsafeCell`, except it implements `Sync`
14/// if `T` implements `Sync`.
15///
16/// `UnsafeCell` doesn't implement `Sync`, to prevent accidental misuse.
17/// You can use `SyncUnsafeCell` instead of `UnsafeCell` to allow it to be
18/// shared between threads, if that's intentional.
19/// Providing proper synchronization is still the task of the user,
20/// making this type just as unsafe to use.
21///
22/// See [`UnsafeCell`] for details.
23#[repr(transparent)]
24pub struct SyncUnsafeCell<T: ?Sized> {
25    value: UnsafeCell<T>,
26}
27
28// SAFETY: `T` is Sync, caller is responsible for upholding rust safety rules
29unsafe impl<T: ?Sized + Sync> Sync for SyncUnsafeCell<T> {}
30
31impl<T> SyncUnsafeCell<T> {
32    /// Constructs a new instance of `SyncUnsafeCell` which will wrap the specified value.
33    #[inline]
34    pub const fn new(value: T) -> Self {
35        Self {
36            value: UnsafeCell::new(value),
37        }
38    }
39
40    /// Unwraps the value.
41    #[inline]
42    pub fn into_inner(self) -> T {
43        self.value.into_inner()
44    }
45}
46
47impl<T: ?Sized> SyncUnsafeCell<T> {
48    /// Gets a mutable pointer to the wrapped value.
49    ///
50    /// This can be cast to a pointer of any kind.
51    /// Ensure that the access is unique (no active references, mutable or not)
52    /// when casting to `&mut T`, and ensure that there are no mutations
53    /// or mutable aliases going on when casting to `&T`
54    #[inline]
55    pub const fn get(&self) -> *mut T {
56        self.value.get()
57    }
58
59    /// Returns a mutable reference to the underlying data.
60    ///
61    /// This call borrows the `SyncUnsafeCell` mutably (at compile-time) which
62    /// guarantees that we possess the only reference.
63    #[inline]
64    pub fn get_mut(&mut self) -> &mut T {
65        self.value.get_mut()
66    }
67
68    /// Gets a mutable pointer to the wrapped value.
69    ///
70    /// See [`UnsafeCell::get`] for details.
71    #[inline]
72    pub const fn raw_get(this: *const Self) -> *mut T {
73        // We can just cast the pointer from `SyncUnsafeCell<T>` to `T` because
74        // of #[repr(transparent)] on both SyncUnsafeCell and UnsafeCell.
75        // See UnsafeCell::raw_get.
76        (this as *const T).cast_mut()
77    }
78
79    #[inline]
80    /// Returns a `&mut SyncUnsafeCell<T>` from a `&mut T`.
81    pub fn from_mut(t: &mut T) -> &mut SyncUnsafeCell<T> {
82        let ptr = ptr::from_mut(t) as *mut SyncUnsafeCell<T>;
83        // SAFETY: `ptr` must be safe to mutably dereference, since it was originally
84        // obtained from a mutable reference. `SyncUnsafeCell` has the same representation
85        // as the original type `T`, since the former is annotated with #[repr(transparent)].
86        unsafe { &mut *ptr }
87    }
88}
89
90impl<T> SyncUnsafeCell<[T]> {
91    /// Returns a `&[SyncUnsafeCell<T>]` from a `&SyncUnsafeCell<[T]>`.
92    /// # Examples
93    ///
94    /// ```
95    /// # use bevy_utils::syncunsafecell::SyncUnsafeCell;
96    ///
97    /// let slice: &mut [i32] = &mut [1, 2, 3];
98    /// let cell_slice: &SyncUnsafeCell<[i32]> = SyncUnsafeCell::from_mut(slice);
99    /// let slice_cell: &[SyncUnsafeCell<i32>] = cell_slice.as_slice_of_cells();
100    ///
101    /// assert_eq!(slice_cell.len(), 3);
102    /// ```
103    pub fn as_slice_of_cells(&self) -> &[SyncUnsafeCell<T>] {
104        let self_ptr: *const SyncUnsafeCell<[T]> = ptr::from_ref(self);
105        let slice_ptr = self_ptr as *const [SyncUnsafeCell<T>];
106        // SAFETY: `UnsafeCell<T>` and `SyncUnsafeCell<T>` have #[repr(transparent)]
107        // therefore:
108        // - `SyncUnsafeCell<T>` has the same layout as `T`
109        // - `SyncUnsafeCell<[T]>` has the same layout as `[T]`
110        // - `SyncUnsafeCell<[T]>` has the same layout as `[SyncUnsafeCell<T>]`
111        unsafe { &*slice_ptr }
112    }
113}
114
115impl<T: Default> Default for SyncUnsafeCell<T> {
116    /// Creates an `SyncUnsafeCell`, with the `Default` value for T.
117    fn default() -> SyncUnsafeCell<T> {
118        SyncUnsafeCell::new(Default::default())
119    }
120}
121
122impl<T> From<T> for SyncUnsafeCell<T> {
123    /// Creates a new `SyncUnsafeCell<T>` containing the given value.
124    fn from(t: T) -> SyncUnsafeCell<T> {
125        SyncUnsafeCell::new(t)
126    }
127}