Skip to main content

hotpatch_rs/
lib.rs

1//! hotpatch-rs: atomic function-level hot patching for long-running Rust services.
2
3pub mod abi;
4mod error;
5mod runtime;
6mod slot;
7
8pub use abi::{PatchEntryV1, PatchFn, PatchModuleV1, ABI_MAGIC_V1, ABI_VERSION_V1, MODULE_EXPORT_SYMBOL_V1};
9pub use error::{HotpatchError, Result};
10pub use runtime::{HotpatchRuntime, ModuleLoadReport};
11
12/// Export a patch module manifest with a stable C ABI.
13///
14/// This macro is intended for `cdylib` patch crates.
15///
16/// Example:
17///
18/// ```ignore
19/// use hotpatch_rs::{hotpatch_module, PatchFn};
20///
21/// unsafe extern "C" fn handler(state: *mut core::ffi::c_void, input: *const core::ffi::c_void, output: *mut core::ffi::c_void) -> i32 {
22///     0
23/// }
24///
25/// hotpatch_module!("counter", 1, [("counter.add", handler)]);
26/// ```
27#[macro_export]
28macro_rules! hotpatch_module {
29    ($module_name:literal, $module_version:expr, [$(($symbol:literal, $func:path)),+ $(,)?]) => {
30        #[doc(hidden)]
31        #[used]
32        static HOTPATCH_ENTRIES: [$crate::PatchEntryV1; hotpatch_module!(@count $(($symbol, $func)),+)] = [
33            $(
34                $crate::PatchEntryV1 {
35                    name: concat!($symbol, "\0").as_ptr() as *const core::ffi::c_char,
36                    func: $func,
37                    flags: 0,
38                    reserved: 0,
39                }
40            ),+
41        ];
42
43        #[no_mangle]
44        pub static HOTPATCH_MODULE_V1: $crate::PatchModuleV1 = $crate::PatchModuleV1 {
45            abi_magic: $crate::ABI_MAGIC_V1,
46            abi_version: $crate::ABI_VERSION_V1,
47            struct_size: core::mem::size_of::<$crate::PatchModuleV1>() as u16,
48            module_version: $module_version,
49            name: concat!($module_name, "\0").as_ptr() as *const core::ffi::c_char,
50            entry_count: HOTPATCH_ENTRIES.len() as u32,
51            reserved: 0,
52            entries: HOTPATCH_ENTRIES.as_ptr(),
53            on_load: None,
54            on_unload: None,
55        };
56    };
57    (@count $(($symbol:literal, $func:path)),+) => {
58        <[()]>::len(&[$(hotpatch_module!(@replace $symbol $func)),+])
59    };
60    (@replace $symbol:literal $func:path) => { () };
61}