devela/sys/mem/
namespace.rs

1// devela::sys::mem::namespace
2//
3//! Defines the [`Mem`] namespace.
4//
5
6#[allow(unused_imports, reason = "unsafe feature-gated")]
7use crate::_core::{
8    mem::{transmute_copy, zeroed},
9    slice::{from_raw_parts, from_raw_parts_mut},
10};
11use crate::{
12    Discriminant,
13    _core::mem::{
14        align_of, align_of_val, discriminant, drop, forget, needs_drop, replace, size_of,
15        size_of_val, swap, take,
16    },
17};
18
19#[doc = crate::TAG_NAMESPACE!()]
20/// Memory-related operations.
21///
22/// See also: [`ExtMem`][crate::ExtMem], [`Ptr`][crate::Ptr], [`Slice`][crate::Slice].
23pub struct Mem;
24
25/// # Safe methods.
26impl Mem {
27    /// Returns the minimum alignment of the type in bytes.
28    ///
29    /// See `core::mem::`[`align_of`].
30    #[must_use]
31    pub const fn align_of<T>() -> usize {
32        align_of::<T>()
33    }
34
35    /// Returns the alignment of the pointed-to value in bytes.
36    ///
37    /// See `core::mem::`[`align_of_val`].
38    #[must_use]
39    pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
40        align_of_val(val)
41    }
42
43    /// Bitwise-copies a value.
44    ///
45    /// It is useful when you want to pass a function pointer to a combinator,
46    /// rather than defining a new closure.
47    ///
48    /// # Example
49    /// ```
50    /// # use devela::Mem;
51    /// let result_from_ffi_fn: Result<(), &i32> = Err(&1);
52    /// let result_copied: Result<(), i32> = result_from_ffi_fn.map_err(Mem::copy);
53    /// ```
54    // WAIT: [core::mem::copy](https://github.com/rust-lang/rust/issues/98262)
55    #[must_use]
56    pub const fn copy<T: Copy>(x: &T) -> T {
57        *x
58    }
59
60    /// Returns a value uniquely identifying the enum variant in v.
61    #[must_use]
62    pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
63        discriminant(v)
64    }
65
66    /// Disposes of a value.
67    ///
68    /// See `core::mem::`[`drop`].
69    pub fn drop<T>(_x: T) {
70        drop(_x);
71    }
72
73    /// Takes ownership and “forgets” about `t` *without running its destructor*.
74    ///
75    /// See `core::mem::`[`forget`].
76    pub fn forget<T>(t: T) {
77        forget(t);
78    }
79
80    /// Returns true if dropping values of type T matters.
81    ///
82    /// See `core::mem::`[`needs_drop`].
83    #[must_use]
84    pub const fn needs_drop<T: ?Sized>() -> bool {
85        needs_drop::<T>()
86    }
87
88    /// Moves `src` into `dest`, returning the previous `dest` value.
89    ///
90    /// See `core::mem::`[`replace`].
91    #[must_use]
92    pub const fn replace<T>(dest: &mut T, src: T) -> T {
93        replace::<T>(dest, src)
94    }
95
96    /// Returns the size of a type in bytes.
97    ///
98    /// See `core::mem::`[`size_of`].
99    #[must_use]
100    pub const fn size_of<T>() -> usize {
101        size_of::<T>()
102    }
103
104    /// Returns the size of the pointed-to value in bytes.
105    /// See `core::mem::`[`size_of_val`].
106    #[must_use]
107    pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
108        size_of_val(val)
109    }
110
111    /// Swaps the values at two locations, without deinitializing either one.
112    ///
113    /// See `core::mem::`[`swap`].
114    pub const fn swap<T>(x: &mut T, y: &mut T) {
115        swap::<T>(x, y);
116    }
117
118    /// Replaces `dest` with `T::default()`, returning the previous `dest` value.
119    ///
120    /// See `core::mem::`[`take`].
121    #[must_use]
122    pub fn take<T: Default>(dest: &mut T) -> T {
123        take::<T>(dest)
124    }
125}
126
127/// # Extra methods
128impl Mem {
129    /// Returns the rounded up size in bytes from a size in bits.
130    ///
131    /// This is equivalent to `(bit_size + 7) / 8` but handles potential overflow.
132    #[must_use]
133    pub const fn bytes_from_bits(bit_size: usize) -> usize {
134        if let Some(t) = bit_size.checked_add(8 - 1) {
135            t / 8
136        } else {
137            Self::bytes_from_bits_cold()
138        }
139    }
140    #[cold] #[rustfmt::skip]
141    const fn bytes_from_bits_cold() -> usize { usize::MAX / 8 }
142}
143
144/// # Unsafe methods
145///
146/// ## Features
147/// They depend on enabling any `unsafe*` feature, and not enabling `safe_mem`.
148#[cfg_attr(feature = "nightly_doc", doc(cfg(unsafe··)))]
149#[cfg(all(not(feature = "safe_mem"), unsafe··))]
150impl Mem {
151    // NOTE: can't compile, errors with: error[E0512]:
152    // cannot transmute between types of different sizes, or dependently-sized types
153    //
154    // /// Reinterprets the bits of a value of one type as another type.
155    // ///
156    // /// See `core::mem::`[`transmute`].
157    // pub const unsafe fn transmute<Src: Sized, Dst: Sized>(_src: Src) -> Dst {
158    //     unsafe { transmute::<Src, Dst>(_src) }
159    // }
160
161    /// Reads `src` as having type `&Dst` without moving the contained value.
162    ///
163    /// # Safety
164    /// See `core::mem::`[`transmute_copy`].
165    #[must_use]
166    pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst {
167        // SAFETY: Caller must uphold the safety contract.
168        unsafe { transmute_copy::<Src, Dst>(src) }
169    }
170
171    /// Returns the value of type `T` represented by the all-zero byte-pattern.
172    ///
173    /// # Safety
174    /// See `core::mem::`[`zeroed`].
175    #[must_use]
176    pub const unsafe fn zeroed<T>() -> T {
177        // SAFETY: Caller must uphold the safety contract.
178        unsafe { zeroed::<T>() }
179    }
180}
181
182/// # Unsafe methods gated by `unsafe_slice`
183#[cfg(all(not(feature = "safe_data"), feature = "unsafe_slice"))]
184#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "unsafe_slice")))]
185impl Mem {
186    /// View any `T: Sync + Unpin + ?Sized` as `&[u8]`.
187    ///
188    /// This is a safer interface to `core::slice::`[`from_raw_parts`].
189    /// # Example
190    /// ```
191    /// # use devela::Mem;
192    /// #[repr(C)]
193    /// struct Data(u32);
194    ///
195    /// let data = Data(1234);
196    /// let bytes = Mem::as_bytes(&data);
197    ///
198    /// if cfg!(target_endian = "little") {
199    ///     assert!(bytes == &[210, 4, 0, 0]);
200    /// } else {
201    ///     assert!(bytes == &[0, 0, 4, 210]);
202    /// }
203    /// ```
204    #[doc = crate::doc_!(vendor: "rawbytes")]
205    #[must_use]
206    pub fn as_bytes<'t, T: Sync + Unpin + ?Sized + 't>(v: &T) -> &'t [u8] {
207        // SAFETY: `v` is valid; u8 has alignment 1, size_of_val(v) gives the exact byte length.
208        unsafe { from_raw_parts(v as *const _ as *const u8, size_of_val(v)) }
209    }
210
211    /// View any `T: Sync + Unpin + ?Sized` as `&mut [u8]`.
212    ///
213    /// This is a safer interface to `core::slice::`[`from_raw_parts_mut`].
214    /// # Examples
215    /// ```
216    /// # use devela::Mem;
217    /// #[repr(C)]
218    /// struct Data(u32);
219    ///
220    /// let mut data = Data(1234);
221    /// let bytes = Mem::as_bytes_mut(&mut data);
222    ///
223    /// if cfg!(target_endian = "little") {
224    ///     bytes[1] = 0;
225    ///     assert!(bytes == &[210, 0, 0, 0] && data.0 == 210);
226    /// } else {
227    ///     bytes[1] = 0;
228    ///     assert!(bytes == &[0, 0, 0, 210] && data.0 == 210);
229    /// }
230    /// ```
231    #[doc = crate::doc_!(vendor: "rawbytes")]
232    #[must_use]
233    pub fn as_bytes_mut<'t, T: Sync + Unpin + ?Sized + 't>(v: &mut T) -> &'t mut [u8] {
234        // SAFETY: `v` is a valid, exclusive reference;
235        // u8’s alignment is 1, and size_of_val(v) bounds the mutable slice.
236        unsafe { from_raw_parts_mut(v as *mut _ as *mut u8, size_of_val(v)) }
237    }
238
239    /// View any `T: Sync + Unpin + Sized` as `&[u8]` *compile-time* friendly.
240    ///
241    /// This is a safer interface to `core::slice::`[`from_raw_parts`], for `Sized` types.
242    /// # Examples
243    /// ```
244    /// # use devela::Mem;
245    /// const DATA: u32 = 1234;
246    /// const BYTES: &[u8] = Mem::as_bytes_sized(&DATA);
247    ///
248    /// if cfg!(target_endian = "little") {
249    ///     assert_eq!(BYTES, &[210, 4, 0, 0]);
250    /// } else {
251    ///     assert_eq!(BYTES, &[0, 0, 4, 210]);
252    /// }
253    /// ```
254    #[must_use]
255    pub const fn as_bytes_sized<T: Sync + Unpin>(v: &T) -> &[u8] {
256        // SAFETY: `v` is valid; casting to *const u8 is safe (u8 has alignment 1)
257        // and size_of::<T>() exactly covers the object.
258        unsafe { from_raw_parts(v as *const T as *const u8, size_of::<T>()) }
259    }
260}