# hotload

[![crates.io](https://img.shields.io/crates/v/hotload.svg)](https://crates.io/crates/hotload)
[![docs.rs](https://img.shields.io/docsrs/hotload)](https://docs.rs/hotload)

`hotload` is a zero-cost, lock-free dynamic library reloader for Rust that keeps symbols alive while swapping DLL/SO images in place. `hotload` 是一个零成本、无锁的动态库热更新加载器，可在不停机的情况下切换新旧库并维持函数指针安全可用。

## Overview / 概览

- 🔥 **Zero-cost hot swapping / 零成本热替换** – no RWLocks, no atomics, just direct function pointers managed by the loader.
- ♻️ **Event-driven reloads / 事件驱动热重载** – subscribe to *before load* and *before unload* hooks to sync state between DLL generations.
- 🧩 **Macro-generated APIs / 宏生成接口** – `hotload::gen_rust_no_mangle!` produces strongly typed wrappers straight from your `lib.rs`.
- 🧪 **Battle-tested examples / 测试例子齐全** – see `examples/test_easy`, `examples/test_1`, `examples/test_batch`, `examples/test_gen_lib_fun`, and `examples/call_lib` for real workflows.

## Quick Start / 快速开始

1. Add dependencies / 添加依赖：

   ```toml
   [dependencies]
   dlopen2 = "0.8"
   hotload = "0.9"
   ```

2. Generate your API surface from the DLL source / 用宏从动态库源代码生成 API：

   ```rust
   use dlopen2::wrapper::WrapperApi;
   use hotload::types::Hotload;

   hotload::gen_rust_no_mangle!((MyApi, "../call_lib/src/lib.rs", true));

   static DLL: Hotload<MyApi> = Hotload::new("../call_lib/target/debug/call_lib.dll");
   ```

3. Wire up the loader / 初始化加载器：

   ```rust
   fn main() {
       DLL.init_load(|mut new_dll, old_dll| {
           new_dll.init_data("boot".into());
           drop(new_dll); // mount the fresh symbols / 挂载新符号

           if let Some(old) = old_dll {
               old.stop_runtime(); // final clean-up / 收尾
           }
       }).unwrap();

       loop {
           DLL.test_print("Hello hotload".into());
       }
   }
   ```

## Example Gallery / 示例速览

| Example | Highlights | 命令 (PowerShell) |
|---------|------------|-------------------|
| `examples/test_easy` | Smallest loop that reloads on file change / 最小闭环示例 | ```powershell
cd examples\test_easy
cargo run
``` |
| `examples/test_1` | Multithreaded reload with Tokio + shared state / Tokio 多线程与共享状态 | ```powershell
cd examples\test_1
cargo run
``` |
| `examples/test_batch` | Batch loader managing multiple DLL instances / 批量管理多个 DLL | ```powershell
cd examples\test_batch
cargo run
``` |
| `examples/test_gen_lib_fun` | Demonstrates auto-generated Rust types / 演示宏生成的类型定义 | ```powershell
cd examples\test_gen_lib_fun
cargo run
``` |
| `examples/call_lib` | The hot-swapped library under test / 被热替换的示例库 | ```powershell
cd examples\call_lib
cargo b
``` |

## API Cheat Sheet / API 中英文速览

| API | Description (EN) | 说明 (中文) |
|-----|------------------|-------------|
| `hotload::gen_rust_no_mangle!((API, path, gen_types?))` | Generates `WrapperApi` structs and optional Rust types straight from `lib.rs`. | 从 `lib.rs` 解析并生成 `WrapperApi` 结构体，可选同步导出结构、枚举等 Rust 类型。|
| `Hotload<API>::new(path)` | Creates a zero-cost handle wired to a DLL/SO path. | 创建零成本句柄，绑定指定 DLL/SO 路径。|
| `Hotload::init_load(|new, old| { ... })` | Registers callbacks for mount/unmount while atomically swapping libraries. | 注册加载/卸载回调，在原子切换库文件时执行业务逻辑。|
| `Hotload::test_print(...)` (generated) | Any exported symbol becomes a safe method call on `Hotload`. | 所有导出符号都映射为 `Hotload` 方法，可直接调用。|
| `EventOldDll<T>::cancel()` | Abort unloading of the previous DLL generation. | 终止卸载旧版本 DLL，确保运行完毕后再释放。|
| `Hotload::borrow()/borrow_mut()` | Access static data defined inside the DLL with runtime write-guard semantics. | 以运行时写保护访问 DLL 内部静态数据，实现跨库共享状态。|

## Feature Highlights / 功能亮点

- **Zero cost & lock-free / 零成本无锁** – no runtime penalty beyond pointer swaps; perfect for low-latency systems.
- **Auto reload / 自动热重载** – file watcher detects `Create/Remove` events and refreshes handles instantly.
- **Stateful hand-off / 有状态交接** – orchestrate warm start or graceful shutdown through event hooks.
- **Type-safe bindings / 类型安全绑定** – leverage `dlopen2::WrapperApi` and the macro to eliminate manual `unsafe` glue.

## Comparison with other libraries

| Feature | dlopen2 | [hotload](https://gitee.com/guoyucode/hotload) | hot-lib-reloader |
|---------|---------|-------------------------------------------------|------------------|
| Basic functionality | Yes | Yes | Yes |
| Multiplatform | Yes | Yes | Yes |
| Dangling symbol prevention | Yes | Yes | Yes |
| Thread safety | Yes | Yes | Yes |
| Loading symbols into structs | Yes | Yes | Yes |
| Overhead | Minimal | Minimal | Minimal |
| Low-level, unsafe API | Yes | Yes | Yes |
| Object-oriented friendly | Yes | Yes | Yes |
| Load from the program itself | Yes | Yes | Yes |
| Obtaining address information (dladdr) | Yes | Yes | Yes |
| Auto reload | **No** | Yes | Yes |
| Has load-new-dll event | **No** | Yes | **No** |
| Zero cost, no locks | **No** | Yes | **No** |
| Generate Rust call methods | **No** | Yes | Yes |

## Documentation

[Cargo documentation](https://docs.rs/hotload)

## License

This code is licensed under the [MIT](./LICENSE) license.

## Changelog

[GitHub](https://gitee.com/guoyucode/hotload)

## Acknowledgement

Special thanks to [dlopen2](https://github.com/nagisa) and [hot-lib-reloader](https://crates.io/crates/hot-lib-reloader)