1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! Module entry point dispatch
//!
//! Port from zsh/Src/modentry.c (43 lines).
//!
//! In C, this is the dlopen entry point that dispatches setup/boot/cleanup/finish
//! calls to loaded modules. In Rust, all modules are statically compiled,
//! so this provides the ModuleLifecycle trait dispatch instead.
//!
//! C signature: `int modentry(int boot, Module m, void *ptr)`. The `boot`
//! int is the op selector — `0=setup_`, `1=boot_`, `2=cleanup_`,
//! `3=finish_`, `4=features_`, `5=enables_` per Src/modentry.c switch.
use crate::module::ModuleLifecycle;
/// Port of `modentry(int boot, Module m, void *ptr)` from Src/modentry.c:7. Direct port of the
/// C `int modentry(int boot, Module m, void *ptr)` switch — `boot`
/// selects which lifecycle function to dispatch. Unknown values
/// return 1 (matches C's `zerr("bad call to modentry"); return 1`).
/// WARNING: param names don't match C — Rust=(boot, module) vs C=(boot, m, ptr)
pub fn modentry(boot: i32, module: &mut dyn ModuleLifecycle) -> i32 { // c:7
match boot {
0 => module.setup(), // c:14
1 => module.boot(), // c:18
2 => module.cleanup(), // c:22
3 => module.finish(), // c:26
4 | 5 => 0, // c:30,34 features_/enables_
_ => 1, // c:38-40 zerr default
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestModule {
booted: bool,
}
impl ModuleLifecycle for TestModule {
fn boot(&mut self) -> i32 {
self.booted = true;
0
}
}
#[test]
fn modentry_dispatches_setup_and_boot() {
let mut m = TestModule { booted: false };
assert_eq!(modentry(0, &mut m), 0); // c:14 setup_
assert!(!m.booted);
assert_eq!(modentry(1, &mut m), 0); // c:18 boot_
assert!(m.booted);
}
#[test]
fn modentry_unknown_op_returns_one() {
let mut m = TestModule { booted: false };
assert_eq!(modentry(6, &mut m), 1); // c:38 default
assert_eq!(modentry(-1, &mut m), 1);
}
}