summaryrefslogtreecommitdiff
path: root/src/no_threads.rs
blob: f831f5f41af498823a94d046d5da25914e98273e (plain)
use core::cell::Cell;

pub struct Mutex {
	// This platform has no threads, so we can use a Cell here.
	locked: Cell<bool>,
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {} // no threads on this platform

impl Mutex {
	#[inline]
	pub const fn new() -> Mutex {
		Mutex {
			locked: Cell::new(false),
		}
	}

	/// Locks the mutex
	///
	/// # Safety
	///
	/// UB occurs if the mutex is already locked by the current thread and the
	/// `unsafe_lock` feature is enabled.
	#[inline]
	pub unsafe fn lock(&self) {
		if self.locked.replace(true) {
			if cfg!(feature = "unsafe_lock") {
				// safety: it's UB to lock this when it's already locked
				unsafe { core::hint::unreachable_unchecked() };
			} else {
				panic!("deadlock on a platform with no threads");
			}
		}
	}

	/// If the mutex is unlocked, it is locked, and this function returns
	/// `true'. Otherwise, `false` is returned.
	#[inline]
	pub unsafe fn try_lock(&self) -> bool {
		self.locked.replace(true) == false
	}

	/// Unlocks the mutex
	///
	/// # Safety
	///
	/// UB occurs if the mutex is already unlocked or if it has been locked on
	/// a different thread.
	#[inline]
	pub unsafe fn unlock(&self) {
		self.locked.set(false);
	}

	#[inline]
	pub unsafe fn is_locked(&self) -> bool {
		self.locked.get()
	}
}

pub struct RwLock {
	// This platform has no threads, so we can use a Cell here.
	mode: Cell<isize>,
}

unsafe impl Send for RwLock {}
unsafe impl Sync for RwLock {} // no threads on this platform

impl RwLock {
	#[inline]
	pub const fn new() -> RwLock {
		RwLock { mode: Cell::new(0) }
	}

	#[inline]
	pub unsafe fn read(&self) {
		let m = self.mode.get();
		if m >= 0 {
			self.mode.set(m + 1);
		} else {
			unsafe { core::hint::unreachable_unchecked() };
		}
	}

	#[inline]
	pub unsafe fn try_read(&self) -> bool {
		let m = self.mode.get();
		if m >= 0 {
			self.mode.set(m + 1);
			true
		} else {
			false
		}
	}

	#[inline]
	pub unsafe fn write(&self) {
		if self.mode.replace(isize::MAX) != 0 {
			unsafe { core::hint::unreachable_unchecked() };
		}
	}

	#[inline]
	pub unsafe fn try_write(&self) -> bool {
		if self.mode.get() == 0 {
			self.mode.set(-1);
			true
		} else {
			false
		}
	}

	#[inline]
	pub unsafe fn read_unlock(&self) {
		self.mode.set(self.mode.get() - 1);
	}

	#[inline]
	pub unsafe fn write_unlock(&self) {
		assert_eq!(self.mode.replace(0), -1);
	}
}