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