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}
14
15impl RawEnv {
16    /// Initialize an empty raw environment.
17    pub const fn null() -> RawEnv {
18        RawEnv {
19            context: None,
20            unit: None,
21            globals: None,
22            diagnostics: None,
23        }
24    }
25}
26
27/// Defines a static budget and environment implementation suitable for
28/// singlethreaded no-std environments. This can be used in `#[no_std]`
29/// environments to implement the necessary hooks for Rune to work.
30///
31/// The alternative is to implement these manually.
32///
33/// If the `std` feature is enabled, thread-local budgeting will be used and
34/// calling this will do nothing.
35///
36/// # Examples
37///
38/// ```
39/// rune::no_std::static_env!();
40/// ```
41#[macro_export]
42macro_rules! static_env {
43    () => {
44        $crate::no_std::__static_env!();
45    };
46}
47
48#[cfg(feature = "std")]
49#[macro_export]
50#[doc(hidden)]
51macro_rules! __static_env {
52    () => {};
53}
54
55#[cfg(not(feature = "std"))]
56#[macro_export]
57#[doc(hidden)]
58macro_rules! __static_env {
59    () => {
60        const _: () = {
61            use $crate::no_std::RawEnv;
62
63            static mut BUDGET: usize = usize::MAX;
64            static mut MEMORY: usize = usize::MAX;
65            static mut RAW_ENV: RawEnv = RawEnv::null();
66
67            /// Necessary hook to abort the current process.
68            #[no_mangle]
69            extern "C" fn __rune_alloc_abort() -> ! {
70                ::core::intrinsics::abort()
71            }
72
73            #[no_mangle]
74            extern "C" fn __rune_alloc_memory_take(amount: usize) -> bool {
75                unsafe {
76                    if MEMORY == usize::MAX {
77                        return true;
78                    }
79
80                    if MEMORY >= amount {
81                        MEMORY -= amount;
82                        return true;
83                    }
84
85                    return false;
86                }
87            }
88
89            /// Release the given amount of memory to the current budget.
90            #[no_mangle]
91            extern "C" fn __rune_alloc_memory_release(amount: usize) {
92                unsafe {
93                    if MEMORY == usize::MAX {
94                        return;
95                    }
96
97                    MEMORY = MEMORY.saturating_add(amount);
98                }
99            }
100
101            /// Get the remaining memory budget for the current thread.
102            #[no_mangle]
103            extern "C" fn __rune_alloc_memory_get() -> usize {
104                unsafe { MEMORY }
105            }
106
107            /// Replace the memory budget for the current thread and return the one which
108            /// was previously set.
109            #[no_mangle]
110            extern "C" fn __rune_alloc_memory_replace(value: usize) -> usize {
111                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(MEMORY), value) }
112            }
113
114            #[no_mangle]
115            extern "C" fn __rune_budget_replace(value: usize) -> usize {
116                // SAFETY: this is only ever executed in a singlethreaded environment.
117                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(BUDGET), value) }
118            }
119
120            #[no_mangle]
121            extern "C" fn __rune_budget_get() -> usize {
122                // SAFETY: this is only ever executed in a singlethreaded environment.
123                unsafe { BUDGET }
124            }
125
126            #[no_mangle]
127            extern "C" fn __rune_env_get() -> RawEnv {
128                // SAFETY: this is only ever executed in a singlethreaded environment.
129                unsafe { RAW_ENV }
130            }
131
132            #[no_mangle]
133            extern "C" fn __rune_env_replace(env: RawEnv) -> RawEnv {
134                // SAFETY: this is only ever executed in a singlethreaded environment.
135                unsafe { core::ptr::replace(core::ptr::addr_of_mut!(RAW_ENV), env) }
136            }
137        };
138    };
139}
140
141#[doc(hidden)]
142pub use __static_env;
143#[doc(inline)]
144pub use static_env;