hybrid-rc 0.2.0

Thread-safe hybrid reference counting pointers
Documentation
//! Helper module for fake thread identification when `std` is not available

// Only used in `no_std` environments
#![cfg_attr(feature = "std", allow(dead_code))]

use core::num::NonZeroUsize;

const SENITEL: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(usize::MAX) };

/// A dummy identifier for a running thread.
///
/// `current_thread()` returns a senitel value that is considered unequal to any thread id including
/// itself.
///
/// This allows limited usage of `HybridRc` in `no_std` environments as anything that needs to check
/// if it's running on the same thread will fail and thus not cause data races, but everything else
/// will work.
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub(crate) struct ThreadId(pub(crate) NonZeroUsize);

impl ThreadId {
	/// Creates a new `ThreadId` for the given raw id.
	#[inline(always)]
	pub(crate) const fn new(value: NonZeroUsize) -> Self {
		Self(value)
	}

	/// Gets the senitel id for any thread.
	#[inline]
	pub(crate) fn current_thread() -> Self {
		Self::new(SENITEL)
	}
}

impl PartialEq for ThreadId {
	fn eq(&self, other: &Self) -> bool {
		match (self.0, other.0) {
			(SENITEL, _) => false,
			(_, SENITEL) => false,
			(a, b) => a == b,
		}
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use alloc::format;
	use core::convert::TryInto;

	/// Tests if thread id that aren't the senitel compare as expected
	#[test]
	fn test_thread_ids_eq() {
		let a = ThreadId::new(32.try_into().unwrap());
		let b = ThreadId::new(32.try_into().unwrap());
		let c = ThreadId::new(16.try_into().unwrap());
		assert_eq!(a, b);
		assert_ne!(a, c);
	}

	/// Tests if senitel thread ids compare unequal to anything
	#[test]
	fn test_thread_senitel_ne() {
		let a = ThreadId::current_thread();
		let b = ThreadId::current_thread();
		let c = ThreadId::new(32.try_into().unwrap());
		assert_ne!(a, b);
		assert_ne!(a, c);
		assert_ne!(c, b);
	}

	#[test]
	fn test_debug_strings() {
		let a = ThreadId::current_thread();
		let b = ThreadId::current_thread();
		let c = ThreadId::new(32.try_into().unwrap());

		assert_eq!(format!("{:?}", &a), format!("{:?}", &b));
		assert_ne!(format!("{:?}", &a), format!("{:?}", &c));
	}
}