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}