SafeManuallyDrop/core/
state.rs

1
2//! AtomicStates for ManuallyDrop
3
4#[cfg(all(test, feature = "support_panic_trig"))]
5use crate::core::trig::panic::PanicTrigManuallyDrop;
6use core::fmt::Display;
7use crate::core::trig::TrigManuallyDrop;
8use core::fmt::Debug;
9use core::sync::atomic::Ordering;
10use core::sync::atomic::AtomicU8;
11
12const READ_ORDERING_METHOD: Ordering = Ordering::SeqCst;
13const WRITE_ORDERING_METHOD: Ordering = Ordering::SeqCst; // 
14
15/// Atomic safe states for ManuallyDrop
16#[repr(transparent)]
17pub struct StateManuallyDrop {
18	state: AtomicU8,
19}
20
21impl Clone for StateManuallyDrop {
22	#[inline]
23	fn clone(&self) -> Self {
24		Self {
25			state: AtomicU8::new(self.__read_byte())
26		}
27	}
28}
29
30impl Debug for StateManuallyDrop {
31	#[inline]
32	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
33		f.debug_struct("StateManuallyDrop")
34		.field("state", &self.read())
35		.finish()
36	}
37}
38
39impl Display for StateManuallyDrop {
40	#[inline(always)]
41	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
42		Display::fmt(&self.read(), f)
43	}
44}
45
46/// Safe States for ManuallyDrop
47#[repr(u8)]
48#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
49pub enum StateManuallyDropData {
50	/// It is allowed to convert ManuallyDrop to 
51	/// anything without calling a trigger.
52	Empty = 1,
53	
54	/// With the take function, the value is forgotten, subsequent work 
55	/// with ManuallyDrop will necessarily call the trigger.
56	TakeModeTrig = 5,
57	/// With the drop function, the value is released, subsequent work 
58	/// with ManuallyDrop will necessarily call the trigger.
59	DropModeTrig = 15,
60	/// With the into_inner function, the value is cast, subsequent work 
61	/// with ManuallyDrop will definitely find the trigger.
62	IntoInnerModeTrig = 25,
63	
64	/// (unsafe/manual_behavior) ManuallyDrop must be forgotten, subsequent work 
65	/// with ManuallyDrop will definitely call the trigger.
66	IgnoreTrigWhenDrop = 30,
67}
68
69impl Display for StateManuallyDropData {
70	#[inline]
71	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
72		let str = match self {
73			Self::Empty => "Empty",
74			
75			Self::TakeModeTrig => "TakeModeTrig",
76			Self::DropModeTrig => "DropModeTrig",
77			Self::IntoInnerModeTrig => "IntoInnerModeTrig",
78			
79			Self::IgnoreTrigWhenDrop => "IgnoreTrigWhenDrop",
80		};
81		
82		Display::fmt(str, f)
83	}
84}
85
86impl From<u8> for StateManuallyDropData {
87	#[inline(always)]
88	fn from(a: u8) -> Self {
89		StateManuallyDropData::from_or_empty(a)
90	}
91}
92
93impl Default for StateManuallyDropData {
94	#[inline(always)]
95	fn default() -> Self {
96		Self::empty()
97	}
98}
99
100impl StateManuallyDropData {
101	/// Convert state to byte
102	#[inline(always)]
103	pub const fn into(self) -> u8 {
104		self as _
105	}
106	
107	/// Create a state from a byte, in case of an error, 
108	/// return the default state.
109	#[inline]
110	pub /*const*/ fn from_or_empty(a: u8) -> Self {
111		Self::is_valid_byte_fn(
112			a, 
113			|| unsafe {
114				Self::force_from(a)
115			},
116			|| Self::empty()
117		)
118	}
119	
120	/// Create a state from a byte, return None on error.
121	#[inline]
122	pub /*const*/ fn from(a: u8) -> Option<Self> {
123		Self::is_valid_byte_fn(
124			a, 
125			|| {
126				let sself = unsafe {
127					Self::force_from(a)
128				};
129				
130				Some(sself)
131			},
132			|| None
133		)
134	}
135	
136	/// Create default state
137	#[inline(always)]
138	const fn __empty() -> Self {
139		let sself = Self::Empty;
140		sself
141	}
142	
143	/// Create default state
144	#[inline(always)]
145	pub const fn empty() -> Self {
146		Self::__empty()
147	}
148	
149	/// Create default state
150	#[inline(always)]
151	pub const fn no_panic_state() -> Self {
152		Self::empty()
153	}
154	
155	/// Generic Status Byte Validation Function
156	#[inline(always)]
157	pub /*const*/ fn is_valid_byte_fn<R>(a: u8, next: impl FnOnce() -> R, errf: impl FnOnce() -> R) -> R {
158		match a {
159			a if a == Self::Empty as _ ||
160			
161				a == Self::TakeModeTrig as _ ||
162				a == Self::DropModeTrig as _ ||
163				a == Self::IntoInnerModeTrig as _ ||
164				
165				a == Self::IgnoreTrigWhenDrop as _ => next(),
166			_ => errf()
167		}
168	}
169	
170	/// General function to check the status byte, 
171	/// return false on error, true on success.
172	#[inline]
173	pub fn is_valid_byte(a: u8) -> bool {
174		Self::is_valid_byte_fn(
175			a, 
176			|| true,
177			|| false,
178		)
179	}
180	
181	/// Create a state from a byte quickly and without checks 
182	/// (important, the byte is checked anyway, but only in a debug build)
183	#[inline(always)]
184	pub unsafe fn force_from(a: u8) -> Self {
185		crate::__fullinternal_debug_assertions!(
186			Self::is_valid_byte(a),
187			true
188		);
189		
190		Self::__force_form(a)
191	}
192	
193	/// Create a state from a byte quickly and without checks 
194	/// (important, the byte is checked anyway, but only in a debug build)
195	#[inline(always)]
196	const fn __force_form(a: u8) -> Self {
197		let result: StateManuallyDropData = unsafe {
198			// safe, u8 -> StateManuallyDropData (enum)
199			core::mem::transmute(a as u8)
200		};
201		result
202	}
203	
204	/// Determining if a trigger should be executed
205	#[inline(always)]
206	pub const fn is_next_trig(&self) -> bool {
207		match self {
208			StateManuallyDropData::Empty => false,
209			_ => true,
210		}
211	}
212	
213	/// Whether the current state is like a new unused object.
214	#[inline(always)]
215	pub const fn is_empty(&self) -> bool {
216		match self {
217			StateManuallyDropData::Empty => true,
218			_ => false,
219		}
220	}
221}
222
223/// Empty state, needed only for some implementations of const functions.
224pub const EMPTY_STATE: StateManuallyDrop = StateManuallyDrop::__empty();
225
226impl StateManuallyDrop {
227	/// Create default state
228	#[inline(always)]
229	pub /*const*/ fn empty() -> Self {
230		let sself = Self::__empty();
231		
232		crate::__fullinternal_debug_assertions!(sself.is_empty(), true);
233		crate::__fullinternal_debug_assertions!(sself.is_next_trig(), false);
234		
235		sself
236	}
237	
238	/// Create default state
239	#[inline(always)]
240	const fn __empty() -> Self {
241		Self {
242			state: AtomicU8::new(StateManuallyDropData::empty() as _)
243		}
244	}
245	
246	/// Whether the current state is like a new unused object.
247	#[inline(always)]
248	pub fn is_empty(&self) -> bool {
249		self.read().is_empty()
250	}
251	
252	/// Getting the status byte of the current ManuallyDrop.
253	#[inline(always)]
254	fn __read_byte(&self) -> u8 {
255		self.state.load(READ_ORDERING_METHOD)
256	}
257	
258	/// Getting the status of the current ManuallyDrop.
259	#[inline(always)]
260	pub fn read(&self) -> StateManuallyDropData {
261		let byte = self.__read_byte();
262		unsafe {
263			StateManuallyDropData::force_from(byte)
264		}
265	}
266	
267	/// Quick substitution of the state of the current ManuallyDrop 
268	/// (note that the previous state of ManuallyDrop is returned)
269	#[inline(always)]
270	fn __force_write(&self, a: StateManuallyDropData) -> StateManuallyDropData {
271		let byte = self.state.swap(a as _, WRITE_ORDERING_METHOD);
272		unsafe {
273			StateManuallyDropData::force_from(byte)
274		}
275	}
276	
277	/// Resets the ManuallyDrop state to the initial state
278	pub unsafe fn get_and_reset(&self) -> StateManuallyDropData {
279		let old_value = self.__force_write(
280			StateManuallyDropData::Empty
281		);
282		crate::__fullinternal_debug_assertions!(self.is_empty(), true);
283		crate::__fullinternal_debug_assertions!(self.is_next_trig(), false);
284		
285		old_value
286	}
287	
288	/// Function to safely replace the state of the ManuallyDrop trigger 
289	/// definer (note that the new state must fire on validation)
290	#[inline]
291	fn __safe_replace_mutstate<Trig: TrigManuallyDrop>(&self, new_state: StateManuallyDropData) {
292		crate::__fullinternal_debug_assertions!(new_state.is_next_trig(), true);
293		
294		let old_state = self.__force_write(new_state);
295		
296		// COMBO REPLACE STATE -> ERR
297		if old_state.is_next_trig() {
298			Trig::trig_next_invalid_beh(
299				format_args!(
300					"Undefined behavior when using ManuallyDrop(combo_replace_manudropstate), instead of the expected default state, the current state: {:?}.", 
301					old_state
302				)
303			);
304		}
305	}
306	
307	/// Change the ManuallyDrop state to a panicked state, or execute a trigger 
308	/// function if the current state was not empty.
309	#[inline(always)]
310	pub fn to_dropmode_or_trig<Trig: TrigManuallyDrop>(&self) {
311		self.__safe_replace_mutstate::<Trig>(
312			StateManuallyDropData::DropModeTrig
313		);
314		
315		crate::__fullinternal_debug_assertions!(self.is_next_trig(), true);
316	}
317	
318	/// Change the state of ManuallyDrop to the state of the released value, 
319	/// or execute the trigger function if the current state was not empty.
320	#[inline(always)]
321	pub fn to_takemode_or_trig<Trig: TrigManuallyDrop>(&self) {
322		self.__safe_replace_mutstate::<Trig>(
323			StateManuallyDropData::TakeModeTrig
324		);
325		
326		crate::__fullinternal_debug_assertions!(self.is_next_trig(), true);
327	}
328	
329	/// Change the ManuallyDrop state to ignore freeing the value, or execute the 
330	/// trigger function if the current state was not empty.
331	#[inline(always)]
332	pub fn to_ignore_trig_when_drop<Trig: TrigManuallyDrop>(&self) {
333		self.__safe_replace_mutstate::<Trig>(
334			StateManuallyDropData::IgnoreTrigWhenDrop
335		);
336		
337		crate::__fullinternal_debug_assertions!(self.is_next_trig(), true);
338	}
339	
340	/// Change the state of ManuallyDrop to the state of the released value, or execute 
341	/// the trigger function if the current state was not empty.
342	#[inline(always)]
343	pub fn to_intoinnermode_or_trig<Trig: TrigManuallyDrop>(&self) {
344		self.__safe_replace_mutstate::<Trig>(
345			StateManuallyDropData::IntoInnerModeTrig
346		);
347		
348		crate::__fullinternal_debug_assertions!(self.is_next_trig(), true);
349	}
350	
351	/// Check the state of ManuallyDrop for a readable state, or execute a trigger 
352	/// function if the current state was not empty.
353	#[inline(always)]
354	pub fn deref_or_trig<Trig: TrigManuallyDrop>(&self) {
355		let a_state = self.read();
356		
357		if a_state.is_next_trig() {
358			Trig::trig_next_invalid_beh(
359				format_args!(
360					"Undefined behavior when using ManuallyDrop.deref(), instead of the expected default state, the current state: {:?}.",
361					a_state
362				)
363			)
364		}
365	}
366	
367	/// Check if the ManuallyDrop state is empty, or execute the trigger function if 
368	/// the current state was not empty.
369	pub fn if_empty_then_run_trigfn<Trig: TrigManuallyDrop, F: FnOnce()>(&self, exp_str: &'static str, fn_trig: F) {
370		let a_state = self.read();
371		
372		if a_state.is_empty() {
373			fn_trig();
374			
375			Trig::trig_next_invalid_beh(
376				format_args!(
377					"Undefined behavior when using ManuallyDrop ({}), state should not be default, current state is {:?}.",
378					exp_str,
379					a_state
380				)
381			)
382		}
383	}
384	
385	/// Determining if a trigger should be executed
386	#[inline(always)]
387	pub fn is_next_trig(&self) -> bool {
388		self.read().is_next_trig()
389	}
390}
391
392impl Default for StateManuallyDrop {
393	#[inline(always)]
394	fn default() -> Self {
395		StateManuallyDrop::empty()
396	}
397}
398
399#[cfg(all(test, feature = "support_panic_trig"))]
400#[test]
401fn test_state() {
402	let state = StateManuallyDrop::empty();
403	assert_eq!(state.is_empty(), true);
404	assert_eq!(state.is_next_trig(), false);
405	
406	state.deref_or_trig::<PanicTrigManuallyDrop>(); // ok
407}
408
409#[cfg(all(test, feature = "support_panic_trig"))]
410#[test]
411fn test_const_empty_state() {
412	let state = EMPTY_STATE; // Copy
413	assert_eq!(state.is_empty(), true);
414	assert_eq!(state.is_next_trig(), false);
415	
416	state.deref_or_trig::<PanicTrigManuallyDrop>(); // ok
417}
418
419
420#[cfg(all(test, feature = "support_panic_trig"))]
421#[test]
422fn test_reset() {
423	let state = StateManuallyDrop::empty();
424	assert_eq!(state.is_empty(), true);
425	assert_eq!(state.is_next_trig(), false);
426	
427	state.deref_or_trig::<PanicTrigManuallyDrop>(); // ok
428	state.to_dropmode_or_trig::<PanicTrigManuallyDrop>();
429	
430	assert_eq!(state.is_empty(), false);
431	assert_eq!(state.is_next_trig(), true);
432	
433	let old_state = unsafe {
434		state.get_and_reset()
435	};
436	assert_eq!(state.is_empty(), true);
437	assert_eq!(state.is_next_trig(), false);
438	assert_eq!(old_state.is_empty(), false);
439	assert_eq!(old_state.is_next_trig(), true);
440	assert_eq!(old_state, StateManuallyDropData::DropModeTrig);
441}
442