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