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            #[no_mangle]
79            extern "C" fn __rune_alloc_abort() -> ! {
80                ::core::intrinsics::abort()
81            }
82
83            #[no_mangle]
84            extern "C" fn __rune_alloc_memory_take(amount: usize) -> bool {
85                unsafe {
86                    if MEMORY == usize::MAX {
87                        return true;
88                    }
89
90                    if MEMORY >= amount {
91                        MEMORY -= amount;
92                        return true;
93                    }
94
95                    return false;
96                }
97            }
98
99            /// Release the given amount of memory to the current budget.
100            #[no_mangle]
101            extern "C" fn __rune_alloc_memory_release(amount: usize) {
102                unsafe {
103                    if MEMORY == usize::MAX {
104                        return;
105                    }
106
107                    MEMORY = MEMORY.saturating_add(amount);
108                }
109            }
110
111            /// Get the remaining memory budget for the current thread.
112            #[no_mangle]
113            extern "C" fn __rune_alloc_memory_get() -> usize {
114                unsafe { MEMORY }
115            }
116
117            /// Replace the memory budget for the current thread and return the one which
118            /// was previously set.
119            #[no_mangle]
120            extern "C" fn __rune_alloc_memory_replace(value: usize) -> usize {
121                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(MEMORY), value) }
122            }
123
124            #[no_mangle]
125            extern "C" fn __rune_budget_replace(value: usize) -> usize {
126                // SAFETY: this is only ever executed in a singlethreaded environment.
127                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(BUDGET), value) }
128            }
129
130            #[no_mangle]
131            extern "C" fn __rune_budget_get() -> usize {
132                // SAFETY: this is only ever executed in a singlethreaded environment.
133                unsafe { BUDGET }
134            }
135
136            #[no_mangle]
137            extern "C" fn __rune_env_get() -> RawEnv {
138                // SAFETY: this is only ever executed in a singlethreaded environment.
139                unsafe { RAW_ENV }
140            }
141
142            #[no_mangle]
143            extern "C" fn __rune_env_replace(env: RawEnv) -> RawEnv {
144                // SAFETY: this is only ever executed in a singlethreaded environment.
145                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(RAW_ENV), env) }
146            }
147        };
148    };
149}
150
151#[doc(hidden)]
152pub use __static_env;
153#[doc(inline)]
154pub use static_env;