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;