1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! A fast, thread-local cell

use crate::{runtime, LazyCell};
use core::{
    cell::UnsafeCell,
    fmt::{self, Debug, Formatter},
};

/// A fast, thread-local cell
///
/// # Warning
/// This cell must not be accessed from another thread or an interrupt context; doing so will raise a panic.
pub struct LocalCell<T> {
    /// The wrapped value
    inner: UnsafeCell<T>,
    /// The associated thread ID
    thread_id: usize,
}
impl<T> LocalCell<T> {
    /// Creates a new thread-local cell
    pub const fn new_with_threadid(value: T, thread_id: usize) -> Self {
        Self { inner: UnsafeCell::new(value), thread_id }
    }

    /// Creates a new thread-local cell
    pub fn new(value: T) -> Self {
        // Get the thread ID and init self
        let thread_id = unsafe { runtime::_runtime_threadid_ZhZIZBv4() };
        Self::new_with_threadid(value, thread_id)
    }

    /// Provides scoped access to the underlying value
    ///
    /// # Panic
    /// This function will panic if called from another thread or interrupt context
    pub fn scope<F, FR>(&self, scope: F) -> FR
    where
        F: FnOnce(&mut T) -> FR,
    {
        // Ensure that we are not in an interrupt handler
        let is_interrupted = unsafe { runtime::_runtime_isinterrupted_v5tnnoC7() };
        assert!(!is_interrupted, "cannot access local cell from an interrupt handler");

        // Ensure that we access this from the correct thread
        let thread_id = unsafe { runtime::_runtime_threadid_ZhZIZBv4() };
        assert_eq!(thread_id, self.thread_id, "cannot access local cell from another thread");

        // Provide access to the value
        unsafe { self.raw(scope) }
    }

    /// Provides an unsafe raw scoped access to the underlying value
    ///
    /// # Safety
    /// This function provides unchecked, mutable access to the underlying value, so incorrect use of this function may
    /// lead to race conditions or undefined behavior.
    pub unsafe fn raw<F, FR>(&self, scope: F) -> FR
    where
        F: FnOnce(&mut T) -> FR,
    {
        // Provide access to the inner value
        let inner_ptr = self.inner.get();
        let value = inner_ptr.as_mut().expect("unexpected NULL pointer inside cell");
        scope(value)
    }
}
impl<T> LocalCell<LazyCell<T>> {
    /// Provides scoped access to the underlying lazy cell
    ///
    /// # Panic
    /// This function will panic if called from another thread or interrupt context
    pub fn lazy_scope<F, FR>(&self, scope: F) -> FR
    where
        F: FnOnce(&mut T) -> FR,
    {
        self.scope(|lazy| lazy.scope_mut(scope))
    }
}
impl<T> Debug for LocalCell<T>
where
    T: Debug,
{
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        // Return an opaque description if we are in a different thread
        let thread_id = unsafe { runtime::_runtime_threadid_ZhZIZBv4() };
        if thread_id != self.thread_id {
            return f.debug_tuple("LocalCell").field(&"<opaque due to different thread>").finish();
        }

        // Return an opaque description if we are in an interrupt context
        let is_interrupted = unsafe { runtime::_runtime_isinterrupted_v5tnnoC7() };
        if is_interrupted {
            return f.debug_tuple("LocalCell").field(&"<opaque due to interrupt context>").finish();
        }

        // Debug the value
        self.scope(|value| value.fmt(f))
    }
}
unsafe impl<T> Sync for LocalCell<T>
where
    T: Send,
{
    // Marker trait, no members to implement
}