use crate::utils::Ptr;
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter};
use std::ops::{Deref, DerefMut};
#[cfg(debug_assertions)]
enum BorrowingState {
None,
Shared(usize),
Exclusive,
}
struct Inner<T> {
counter: usize,
data: T,
#[cfg(debug_assertions)]
borrowing_state: BorrowingState,
no_send_marker: std::marker::PhantomData<*const ()>,
}
pub struct LocalRef<'borrow, T> {
#[cfg(debug_assertions)]
inner: Ptr<Inner<T>>,
#[cfg(debug_assertions)]
borrow_pd: std::marker::PhantomData<&'borrow ()>,
#[cfg(not(debug_assertions))]
shared_reference: &'borrow T,
no_send_marker: std::marker::PhantomData<*const ()>,
}
impl<'borrow, T> LocalRef<'borrow, T> {
fn new(local: &'borrow Local<T>) -> Self {
Self {
#[cfg(debug_assertions)]
inner: local.inner,
#[cfg(debug_assertions)]
borrow_pd: std::marker::PhantomData,
#[cfg(not(debug_assertions))]
shared_reference: unsafe { &local.inner.as_ref().data },
no_send_marker: std::marker::PhantomData,
}
}
}
impl<T> Deref for LocalRef<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
#[cfg(debug_assertions)]
unsafe {
&self.inner.as_ref().data
}
#[cfg(not(debug_assertions))]
self.shared_reference
}
}
impl<T: Display> Display for LocalRef<'_, T> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
(**self).fmt(f)
}
}
impl<T> Drop for LocalRef<'_, T> {
fn drop(&mut self) {
#[cfg(debug_assertions)]
{
let inner = unsafe { self.inner.as_mut() };
if let BorrowingState::Shared(n) = inner.borrowing_state {
if n == 1 {
inner.borrowing_state = BorrowingState::None;
} else {
inner.borrowing_state = BorrowingState::Shared(n - 1);
}
} else {
panic!("{}", crate::BUG_MESSAGE)
}
}
}
}
pub struct LocalRefMut<'borrow, T> {
#[cfg(debug_assertions)]
inner: Ptr<Inner<T>>,
#[cfg(debug_assertions)]
borrow_pd: std::marker::PhantomData<&'borrow ()>,
#[cfg(not(debug_assertions))]
exclusive_reference: &'borrow mut T,
no_send_marker: std::marker::PhantomData<*const ()>,
}
impl<'borrow, T> LocalRefMut<'borrow, T> {
fn new(local: &'borrow Local<T>) -> Self {
Self {
#[cfg(debug_assertions)]
inner: local.inner,
#[cfg(debug_assertions)]
borrow_pd: std::marker::PhantomData,
#[cfg(not(debug_assertions))]
exclusive_reference: unsafe { &mut local.inner.as_mut().data },
no_send_marker: std::marker::PhantomData,
}
}
}
impl<T> Deref for LocalRefMut<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
#[cfg(debug_assertions)]
unsafe {
&self.inner.as_ref().data
}
#[cfg(not(debug_assertions))]
self.exclusive_reference
}
}
impl<T> DerefMut for LocalRefMut<'_, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
#[cfg(debug_assertions)]
unsafe {
&mut self.inner.as_mut().data
}
#[cfg(not(debug_assertions))]
self.exclusive_reference
}
}
impl<T: Display> Display for LocalRefMut<'_, T> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
(**self).fmt(f)
}
}
impl<T> Drop for LocalRefMut<'_, T> {
fn drop(&mut self) {
#[cfg(debug_assertions)]
{
let inner = unsafe { self.inner.as_mut() };
if matches!(inner.borrowing_state, BorrowingState::Exclusive) {
inner.borrowing_state = BorrowingState::None;
} else {
panic!("{}", crate::BUG_MESSAGE)
}
}
}
}
pub struct Local<T> {
inner: Ptr<Inner<T>>,
#[cfg(debug_assertions)]
parent_executor_id: usize,
no_send_marker: std::marker::PhantomData<*const ()>,
}
macro_rules! debug_check_parent_executor_id {
($local:expr) => {
#[cfg(debug_assertions)]
{
if $local.parent_executor_id != crate::local_executor().id() {
panic!("{}", crate::BUG_MESSAGE);
}
}
};
}
impl<T> Local<T> {
pub fn new(data: T) -> Self {
Self {
inner: Ptr::new(Inner {
data,
counter: 1,
#[cfg(debug_assertions)]
borrowing_state: BorrowingState::None,
no_send_marker: std::marker::PhantomData,
}),
#[cfg(debug_assertions)]
parent_executor_id: crate::local_executor().id(),
no_send_marker: std::marker::PhantomData,
}
}
#[inline(always)]
fn inc_counter(&self) {
debug_check_parent_executor_id!(self);
unsafe {
self.inner.as_mut().counter += 1;
}
}
#[inline(always)]
fn dec_counter(&self) -> usize {
debug_check_parent_executor_id!(self);
let reference = unsafe { self.inner.as_mut() };
reference.counter -= 1;
reference.counter
}
#[inline(always)]
pub fn borrow(&self) -> LocalRef<T> {
debug_check_parent_executor_id!(self);
#[cfg(debug_assertions)]
unsafe {
match self.inner.as_ref().borrowing_state {
BorrowingState::None => {
self.inner.as_mut().borrowing_state = BorrowingState::Shared(1);
}
BorrowingState::Shared(n) => {
self.inner.as_mut().borrowing_state = BorrowingState::Shared(n + 1);
}
BorrowingState::Exclusive => panic!(
"Local is already borrowed as mutably, use LocalMutex instead. It is almost as \
fast as RefCell, and it is safe to use in concurrent single-threaded contexts."
),
}
}
LocalRef::new(self)
}
#[inline(always)]
pub fn borrow_mut(&self) -> LocalRefMut<T> {
debug_check_parent_executor_id!(self);
#[cfg(debug_assertions)]
unsafe {
match self.inner.as_ref().borrowing_state {
BorrowingState::None => {
self.inner.as_mut().borrowing_state = BorrowingState::Exclusive;
}
BorrowingState::Shared(_) => panic!(
"Local is already borrowed as shared, use LocalMutex instead. It is almost as \
fast as RefCell, and it is safe to use in concurrent single-threaded contexts."
),
BorrowingState::Exclusive => panic!(
"Local is already borrowed as mutably, use LocalMutex instead. It is almost as \
fast as RefCell, and it is safe to use in concurrent single-threaded contexts."
),
}
}
LocalRefMut::new(self)
}
}
impl<T: Default> Default for Local<T> {
#[inline(always)]
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: Debug> Debug for Local<T> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
debug_check_parent_executor_id!(self);
self.borrow().fmt(f)
}
}
impl<T: Display> Display for Local<T> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
debug_check_parent_executor_id!(self);
self.borrow().fmt(f)
}
}
impl<T: PartialEq> PartialEq for Local<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
debug_check_parent_executor_id!(self);
*self.borrow() == *other.borrow()
}
}
impl<T: Eq> Eq for Local<T> {}
impl<T: PartialOrd> PartialOrd for Local<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
debug_check_parent_executor_id!(self);
self.borrow().partial_cmp(&*other.borrow())
}
#[inline(always)]
fn lt(&self, other: &Self) -> bool {
*self.borrow() < *other.borrow()
}
#[inline(always)]
fn le(&self, other: &Self) -> bool {
*self.borrow() <= *other.borrow()
}
#[inline(always)]
fn gt(&self, other: &Self) -> bool {
*self.borrow() > *other.borrow()
}
#[inline(always)]
fn ge(&self, other: &Self) -> bool {
*self.borrow() >= *other.borrow()
}
}
impl<T: Ord> Ord for Local<T> {
fn cmp(&self, other: &Self) -> Ordering {
debug_check_parent_executor_id!(self);
self.borrow().cmp(&*other.borrow())
}
}
impl<T> From<T> for Local<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T> Clone for Local<T> {
fn clone(&self) -> Self {
self.inc_counter();
Self {
inner: self.inner,
#[cfg(debug_assertions)]
parent_executor_id: self.parent_executor_id,
no_send_marker: std::marker::PhantomData,
}
}
}
impl<T> Drop for Local<T> {
fn drop(&mut self) {
debug_check_parent_executor_id!(self);
if self.dec_counter() == 0 {
unsafe {
self.inner.drop_and_deallocate();
}
}
}
}
#[allow(dead_code, reason = "It is used only in compile tests")]
fn test_compile_local() {}
unsafe impl<T> Sync for Local<T> {}