daemonic_error 1.0.0

Errors that compose, predict, and leave receipts - Compose: algebraic combination (in active development) - Predict: Glass/Severity - Receipts: audit trail, position, checksum - Reflection: Runtime Reflection through TopologySegment (in active development)
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use crate::daemonic::compiler::data_structures::Lock;

/// A guard holding mutable access to a `Lock` which is in a locked state.
#[must_use = "if unused the Lock will immediately unlock"]
pub struct LockGuard<'a, T> {
	lock: &'a Lock<T>,
	marker: PhantomData<&'a mut T>,
	
	/// The synchronization mode of the lock. This is explicitly passed to let LLVM relate it
	/// to the original lock operation.
	mode: Mode,
}

impl<'a, T: 'a> Deref for LockGuard<'a, T> {
	type Target = T;
	#[inline]
	fn deref(&self) -> &T {
		// SAFETY: We have shared access to the mutable access owned by this type,
		// so we can give out a shared reference.
		unsafe { &*self.lock.data.get() }
	}
}

impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
	#[inline]
	fn deref_mut(&mut self) -> &mut T {
		// SAFETY: We have mutable access to the data so we can give out a mutable reference.
		unsafe { &mut *self.lock.data.get() }
	}
}

impl<'a, T: 'a> Drop for LockGuard<'a, T> {
	#[inline]
	fn drop(&mut self) {
		// SAFETY (union access): We get `self.mode` from the lock operation so it is consistent
		// with the `lock.mode` state. This means we access the right union fields.
		match self.mode {
			Mode::NoSync => {
				let cell = unsafe { &self.lock.mode_union.no_sync };
				debug_assert!(cell.get());
				cell.set(false);
			}
			// SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
			Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
		}
	}
}