Skip to main content

selium_userland/
lib.rs

1//! Guest-side helpers for building Selium userland services.
2//!
3//! Selium guests communicate exclusively via channels and typed hostcalls.
4//!
5//! # Examples
6//! ```
7//! use futures::{SinkExt, StreamExt};
8//! use selium_userland::{entrypoint, io::DriverError};
9//!
10//! // Services can return results.
11//! #[entrypoint]
12//! pub async fn result_service() -> Result<(), DriverError> {
13//!     Ok(())
14//! }
15//!
16//! // You can also define services that do not have return values.
17//! #[entrypoint]
18//! pub async fn void_service() {
19//!     ()
20//! }
21//! ```
22
23// Appease #[schema] macro that can't find `selium_userland::` without it.
24extern crate self as selium_userland;
25
26macro_rules! driver_module {
27    ($mod_name:ident, $import:ident, $import_module:literal) => {
28        mod $mod_name {
29            use selium_abi::{GuestInt, GuestUint};
30
31            use crate::driver::DriverModule;
32
33            #[allow(dead_code)]
34            pub struct Module;
35
36            #[cfg(target_arch = "wasm32")]
37            #[link(wasm_import_module = $import_module)]
38            unsafe extern "C" {
39                pub fn create(args_ptr: GuestInt, args_len: GuestUint) -> GuestUint;
40                pub fn poll(
41                    handle: GuestUint,
42                    task_id: GuestUint,
43                    result_ptr: GuestInt,
44                    result_len: GuestUint,
45                ) -> GuestUint;
46                pub fn drop(
47                    handle: GuestUint,
48                    result_ptr: GuestInt,
49                    result_len: GuestUint,
50                ) -> GuestUint;
51            }
52
53            #[allow(dead_code)]
54            #[cfg(all(not(target_arch = "wasm32"), test))]
55            unsafe fn create(args_ptr: GuestInt, args_len: GuestUint) -> GuestUint {
56                crate::driver::test_driver::create(
57                    selium_abi::hostcall_name!($import),
58                    args_ptr,
59                    args_len,
60                )
61            }
62
63            #[allow(dead_code)]
64            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
65            unsafe fn create(_args_ptr: GuestInt, _args_len: GuestUint) -> GuestUint {
66                selium_abi::driver_encode_error(2)
67            }
68
69            #[allow(dead_code)]
70            #[cfg(all(not(target_arch = "wasm32"), test))]
71            unsafe fn poll(
72                handle: GuestUint,
73                task_id: GuestUint,
74                result_ptr: GuestInt,
75                result_len: GuestUint,
76            ) -> GuestUint {
77                crate::driver::test_driver::poll(
78                    selium_abi::hostcall_name!($import),
79                    handle,
80                    task_id,
81                    result_ptr,
82                    result_len,
83                )
84            }
85
86            #[allow(dead_code)]
87            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
88            unsafe fn poll(
89                _handle: GuestUint,
90                _task_id: GuestUint,
91                _result_ptr: GuestInt,
92                _result_len: GuestUint,
93            ) -> GuestUint {
94                selium_abi::driver_encode_error(2)
95            }
96
97            #[allow(dead_code)]
98            #[cfg(all(not(target_arch = "wasm32"), test))]
99            unsafe fn drop(
100                handle: GuestUint,
101                result_ptr: GuestInt,
102                result_len: GuestUint,
103            ) -> GuestUint {
104                crate::driver::test_driver::drop(
105                    selium_abi::hostcall_name!($import),
106                    handle,
107                    result_ptr,
108                    result_len,
109                )
110            }
111
112            #[allow(dead_code)]
113            #[cfg(all(not(target_arch = "wasm32"), not(test)))]
114            unsafe fn drop(
115                _handle: GuestUint,
116                _result_ptr: GuestInt,
117                _result_len: GuestUint,
118            ) -> GuestUint {
119                0
120            }
121
122            impl DriverModule for Module {
123                unsafe fn create(args_ptr: GuestInt, args_len: GuestUint) -> GuestUint {
124                    unsafe { create(args_ptr, args_len) }
125                }
126
127                unsafe fn poll(
128                    handle: GuestUint,
129                    task_id: GuestUint,
130                    result_ptr: GuestInt,
131                    result_len: GuestUint,
132                ) -> GuestUint {
133                    unsafe { poll(handle, task_id, result_ptr, result_len) }
134                }
135
136                unsafe fn drop(
137                    handle: GuestUint,
138                    result_ptr: GuestInt,
139                    result_len: GuestUint,
140                ) -> GuestUint {
141                    unsafe { drop(handle, result_ptr, result_len) }
142                }
143            }
144        }
145    };
146}
147
148pub mod abi;
149mod r#async;
150pub mod context;
151mod driver;
152pub mod encoding;
153/// Generated Flatbuffers schema bindings.
154///
155/// The types in this module are generated from Selium `.fbs` schema files and are primarily used
156/// by higher-level helpers (for example, [`crate::encoding`]).
157///
158/// # Examples
159/// ```
160/// use selium_userland::encoding::{FlatMsg, FlatResult};
161///
162/// let bytes = FlatMsg::encode(&FlatResult::ok(1, Vec::new()));
163/// assert!(selium_userland::fbs::selium::result::flat_result_buffer_has_identifier(&bytes));
164/// ```
165#[allow(missing_docs)]
166#[allow(warnings)]
167#[rustfmt::skip]
168pub mod fbs;
169pub mod io;
170pub mod logging;
171pub mod net;
172pub mod process;
173pub mod singleton;
174pub mod time;
175
176/// Re-export of the `rkyv` crate used for internal Selium serialisation.
177pub use rkyv;
178
179pub use r#async::{block_on, spawn, yield_now};
180pub use context::{Context, Dependency, DependencyDescriptor};
181/// Re-export of Selium's derive and attribute macros for guest crates.
182pub use selium_userland_macros::*;
183
184/// Re-export of singleton dependency identifiers.
185pub use selium_abi::DependencyId;
186
187pub trait FromHandle: Sized {
188    /// Construct a typed wrapper from raw handle(s).
189    ///
190    /// # Safety
191    /// The provided handles must have been minted by Selium for the current guest and must match
192    /// the expected capability type. Supplying forged or stale handles may be rejected by the host
193    /// kernel or result in undefined guest behaviour.
194    unsafe fn from_handle(handles: Self::Handles) -> Self;
195    /// The raw handle type(s) required by this wrapper.
196    type Handles;
197}