Skip to main content

rune/no_std/
mod.rs

1//! Public types related to using rune in `#[no_std]` environments.
2
3use core::ptr::NonNull;
4
5/// Environment that needs to be stored somewhere.
6#[derive(Clone, Copy)]
7#[repr(C)]
8pub struct RawEnv {
9    pub(crate) context: Option<NonNull<()>>,
10    pub(crate) unit: Option<NonNull<()>>,
11    pub(crate) globals: Option<NonNull<()>>,
12    pub(crate) diagnostics: Option<NonNull<()>>,
13    /// How deeply the walk over a value in progress has descended, which has to
14    /// be stored along with the rest of the environment since a walk which goes
15    /// through a protocol function is counted across it.
16    pub(crate) depth: usize,
17    /// How deeply the executions in progress are nested, which is stored here
18    /// for the same reason: an execution entered through a native frame is
19    /// counted across it.
20    pub(crate) executions: usize,
21}
22
23impl RawEnv {
24    /// Initialize an empty raw environment.
25    pub const fn null() -> RawEnv {
26        RawEnv {
27            context: None,
28            unit: None,
29            globals: None,
30            diagnostics: None,
31            depth: 0,
32            executions: 0,
33        }
34    }
35}
36
37/// Defines a static budget and environment implementation suitable for
38/// singlethreaded no-std environments. This can be used in `#[no_std]`
39/// environments to implement the necessary hooks for Rune to work.
40///
41/// The alternative is to implement these manually.
42///
43/// If the `std` feature is enabled, thread-local budgeting will be used and
44/// calling this will do nothing.
45///
46/// # Examples
47///
48/// ```
49/// rune::no_std::static_env!();
50/// ```
51#[macro_export]
52macro_rules! static_env {
53    () => {
54        $crate::no_std::__static_env!();
55    };
56}
57
58#[cfg(feature = "std")]
59#[macro_export]
60#[doc(hidden)]
61macro_rules! __static_env {
62    () => {};
63}
64
65#[cfg(not(feature = "std"))]
66#[macro_export]
67#[doc(hidden)]
68macro_rules! __static_env {
69    () => {
70        const _: () = {
71            use $crate::no_std::RawEnv;
72
73            static mut BUDGET: usize = usize::MAX;
74            static mut MEMORY: usize = usize::MAX;
75            static mut RAW_ENV: RawEnv = RawEnv::null();
76
77            /// Necessary hook to abort the current process.
78            ///
79            /// This defers to the embedder's own `#[panic_handler]`, which
80            /// every `no_std` binary has and which cannot return, so that the
81            /// expansion needs no unstable feature.
82            #[no_mangle]
83            extern "C" fn __rune_alloc_abort() -> ! {
84                ::core::panic!("rune: abort")
85            }
86
87            #[no_mangle]
88            extern "C" fn __rune_alloc_memory_take(amount: usize) -> bool {
89                unsafe {
90                    if MEMORY == usize::MAX {
91                        return true;
92                    }
93
94                    if MEMORY >= amount {
95                        MEMORY -= amount;
96                        return true;
97                    }
98
99                    return false;
100                }
101            }
102
103            /// Release the given amount of memory to the current budget.
104            #[no_mangle]
105            extern "C" fn __rune_alloc_memory_release(amount: usize) {
106                unsafe {
107                    if MEMORY == usize::MAX {
108                        return;
109                    }
110
111                    MEMORY = MEMORY.saturating_add(amount);
112                }
113            }
114
115            /// Get the remaining memory budget for the current thread.
116            #[no_mangle]
117            extern "C" fn __rune_alloc_memory_get() -> usize {
118                unsafe { MEMORY }
119            }
120
121            /// Replace the memory budget for the current thread and return the one which
122            /// was previously set.
123            #[no_mangle]
124            extern "C" fn __rune_alloc_memory_replace(value: usize) -> usize {
125                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(MEMORY), value) }
126            }
127
128            #[no_mangle]
129            extern "C" fn __rune_budget_replace(value: usize) -> usize {
130                // SAFETY: this is only ever executed in a singlethreaded environment.
131                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(BUDGET), value) }
132            }
133
134            #[no_mangle]
135            extern "C" fn __rune_budget_get() -> usize {
136                // SAFETY: this is only ever executed in a singlethreaded environment.
137                unsafe { BUDGET }
138            }
139
140            #[no_mangle]
141            extern "C" fn __rune_env_get() -> RawEnv {
142                // SAFETY: this is only ever executed in a singlethreaded environment.
143                unsafe { RAW_ENV }
144            }
145
146            #[no_mangle]
147            extern "C" fn __rune_env_replace(env: RawEnv) -> RawEnv {
148                // SAFETY: this is only ever executed in a singlethreaded environment.
149                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(RAW_ENV), env) }
150            }
151        };
152    };
153}
154
155#[doc(hidden)]
156pub use __static_env;
157#[doc(inline)]
158pub use static_env;