hybrid-rc 0.2.0

Thread-safe hybrid reference counting pointers
Documentation
//! Helper module for thread identification

use core::convert::TryInto;
use core::num::NonZeroUsize;

thread_local! {
	/// Zero-sized thread-local variable to differentiate threads.
	static THREAD_MARKER: () = ();
}

/// A unique identifier for a running thread.
///
/// Uniqueness is guaranteed between running threads. However, the ids of dead
/// threads may be reused.
///
/// There is a chance that this implementation can be replaced by [`std::thread::ThreadId`]
/// when [`as_u64()`] is stabilized.
///
/// **Note:** The current (non platform specific) implementation uses the address of a
/// thread local static variable for thread identification.
///
/// [`as_u64()`]: std::thread::ThreadId::as_u64
#[derive(PartialEq, Eq, 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 id for the thread that invokes it.
	#[inline]
	pub(crate) fn current_thread() -> Self {
		Self::new(
			THREAD_MARKER
				.try_with(|x| x as *const _ as usize)
				.expect("the thread's local data has already been destroyed")
				.try_into()
				.expect("thread id should never be zero"),
		)
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use alloc::format;
	use std::thread;

	/// Tests if the thread id stays the same on the same thread.
	#[test]
	fn test_thread_ids_eq() {
		let a = ThreadId::current_thread();
		let b = ThreadId::current_thread();
		assert_eq!(a, b);
		assert_eq!(format!("{:?}", &a), format!("{:?}", &b));
	}

	/// Tests if the thread id of two different threads differ.
	#[test]
	fn test_thread_ids_ne() {
		let a = ThreadId::current_thread();
		let b = thread::spawn(move || ThreadId::current_thread())
			.join()
			.unwrap();
		assert_ne!(a, b);
		assert_ne!(format!("{:?}", &a), format!("{:?}", &b));
	}

	#[test]
	fn test_thread_ids_clone() {
		let a = ThreadId::current_thread();
		let b = a.clone();
		assert_eq!(a, b);
	}
}