Skip to content

Commit a6cb7d2

Browse files
Add core main-conf access helpers for ngx_core_module
1 parent e90cb5f commit a6cb7d2

3 files changed

Lines changed: 213 additions & 0 deletions

File tree

src/core/conf.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use core::ptr::NonNull;
2+
3+
use crate::ffi::{ngx_core_conf_t, ngx_module_t};
4+
5+
/// Utility trait for types containing core module main configuration.
6+
pub trait CoreModuleConfExt {
7+
/// Get a non-null reference to the main configuration structure for a core module.
8+
///
9+
/// # Safety
10+
/// Caller must ensure that type `T` matches the configuration type for the specified module.
11+
#[inline]
12+
unsafe fn core_main_conf_unchecked<T>(&self, _module: &ngx_module_t) -> Option<NonNull<T>> {
13+
None
14+
}
15+
}
16+
17+
impl CoreModuleConfExt for crate::ffi::ngx_cycle_t {
18+
#[inline]
19+
unsafe fn core_main_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
20+
let conf_ctx = NonNull::new(self.conf_ctx)?;
21+
let conf = unsafe { *conf_ctx.as_ptr().add(module.index) };
22+
NonNull::new(conf.cast())
23+
}
24+
}
25+
26+
impl CoreModuleConfExt for crate::ffi::ngx_conf_t {
27+
#[inline]
28+
unsafe fn core_main_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
29+
unsafe { self.cycle.as_ref()?.core_main_conf_unchecked(module) }
30+
}
31+
}
32+
33+
/// Get a typed reference to the main configuration structure for a core module.
34+
pub fn core_main_conf<T>(o: &impl CoreModuleConfExt, module: &ngx_module_t) -> Option<&'static T> {
35+
unsafe { Some(o.core_main_conf_unchecked(module)?.as_ref()) }
36+
}
37+
38+
/// Get a typed mutable reference to the main configuration structure for a core module.
39+
pub fn core_main_conf_mut<T>(
40+
o: &impl CoreModuleConfExt,
41+
module: &ngx_module_t,
42+
) -> Option<&'static mut T> {
43+
unsafe { Some(o.core_main_conf_unchecked(module)?.as_mut()) }
44+
}
45+
46+
/// Auxiliary structure to access `ngx_core_module` configuration.
47+
pub struct NgxCoreModule;
48+
49+
impl NgxCoreModule {
50+
/// Returns a reference to the global `ngx_core_module`.
51+
pub fn module() -> &'static ngx_module_t {
52+
unsafe { &*core::ptr::addr_of!(nginx_sys::ngx_core_module) }
53+
}
54+
55+
/// Get a typed reference to `ngx_core_module` main configuration.
56+
pub fn main_conf(o: &impl CoreModuleConfExt) -> Option<&'static ngx_core_conf_t> {
57+
core_main_conf(o, Self::module())
58+
}
59+
60+
/// Get a typed mutable reference to `ngx_core_module` main configuration.
61+
pub fn main_conf_mut(o: &impl CoreModuleConfExt) -> Option<&'static mut ngx_core_conf_t> {
62+
core_main_conf_mut(o, Self::module())
63+
}
64+
}
65+
66+
#[cfg(test)]
67+
mod tests {
68+
use core::ffi::c_void;
69+
use core::mem::MaybeUninit;
70+
71+
use super::{CoreModuleConfExt, core_main_conf, core_main_conf_mut};
72+
use crate::ffi::{ngx_conf_t, ngx_cycle_t, ngx_module_t};
73+
74+
type CoreConfSlot = *mut *mut *mut c_void;
75+
76+
fn module_with_index(index: usize) -> ngx_module_t {
77+
let mut module = ngx_module_t::default();
78+
module.index = index;
79+
module
80+
}
81+
82+
#[test]
83+
fn null_conf_ctx_returns_none() {
84+
let cycle: ngx_cycle_t = unsafe { MaybeUninit::zeroed().assume_init() };
85+
let module = module_with_index(0);
86+
assert!(unsafe { cycle.core_main_conf_unchecked::<u32>(&module) }.is_none());
87+
}
88+
89+
#[test]
90+
fn missing_module_slot_returns_none() {
91+
let mut slots: [CoreConfSlot; 2] = [core::ptr::null_mut(); 2];
92+
let mut cycle: ngx_cycle_t = unsafe { MaybeUninit::zeroed().assume_init() };
93+
cycle.conf_ctx = slots.as_mut_ptr();
94+
95+
let module = module_with_index(1);
96+
assert!(unsafe { cycle.core_main_conf_unchecked::<u32>(&module) }.is_none());
97+
}
98+
99+
#[test]
100+
fn populated_slot_returns_typed_reference() {
101+
let mut value: u32 = 42;
102+
let mut slots: [CoreConfSlot; 1] = [(&mut value as *mut u32).cast()];
103+
104+
let mut cycle: ngx_cycle_t = unsafe { MaybeUninit::zeroed().assume_init() };
105+
cycle.conf_ctx = slots.as_mut_ptr();
106+
107+
let mut conf: ngx_conf_t = unsafe { MaybeUninit::zeroed().assume_init() };
108+
conf.cycle = &mut cycle;
109+
110+
let module = module_with_index(0);
111+
112+
let got = core_main_conf::<u32>(&conf, &module).copied();
113+
assert_eq!(got, Some(42));
114+
115+
let got_mut = core_main_conf_mut::<u32>(&conf, &module);
116+
assert!(got_mut.is_some());
117+
if let Some(v) = got_mut {
118+
*v = 99;
119+
}
120+
assert_eq!(value, 99);
121+
}
122+
}

src/core/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
mod buffer;
2+
mod conf;
23
mod pool;
34
pub mod slab;
45
mod status;
56
mod string;
67

78
pub use buffer::*;
9+
pub use conf::*;
810
pub use pool::*;
911
pub use slab::SlabPool;
1012
pub use status::*;

tests/core_conf_test.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use core::ffi::c_void;
2+
use core::mem::MaybeUninit;
3+
use core::ptr;
4+
5+
use ngx::core::{CoreModuleConfExt, core_main_conf, core_main_conf_mut};
6+
use ngx::ffi::{ngx_conf_t, ngx_core_conf_t, ngx_cycle_t, ngx_module_t};
7+
8+
type CoreConfSlot = *mut *mut *mut c_void;
9+
type CoreConfCtx = *mut CoreConfSlot;
10+
11+
fn module_with_index(index: usize) -> ngx_module_t {
12+
let mut module = ngx_module_t::default();
13+
module.index = index;
14+
module
15+
}
16+
17+
// Manual baseline matching the raw NGINX traversal: cycle.conf_ctx[module.index].
18+
unsafe fn manual_core_main_conf_ptr(
19+
cycle: &ngx_cycle_t,
20+
module: &ngx_module_t,
21+
) -> *mut ngx_core_conf_t {
22+
if cycle.conf_ctx.is_null() {
23+
return ptr::null_mut();
24+
}
25+
26+
let slot = unsafe { *cycle.conf_ctx.add(module.index) };
27+
slot.cast()
28+
}
29+
30+
#[test]
31+
// Validates that cycle-based helper access resolves the exact same slot pointer
32+
// as manual top-level conf_ctx indexing.
33+
fn cycle_core_conf_matches_manual_traversal() {
34+
let mut core_conf: ngx_core_conf_t = unsafe { MaybeUninit::zeroed().assume_init() };
35+
let mut slots: [CoreConfSlot; 2] = [ptr::null_mut(); 2];
36+
slots[1] = (&mut core_conf as *mut ngx_core_conf_t).cast();
37+
38+
let mut cycle: ngx_cycle_t = unsafe { MaybeUninit::zeroed().assume_init() };
39+
let conf_ctx: CoreConfCtx = slots.as_mut_ptr();
40+
cycle.conf_ctx = conf_ctx;
41+
42+
let module = module_with_index(1);
43+
let from_manual = unsafe { manual_core_main_conf_ptr(&cycle, &module) };
44+
45+
let from_helper = unsafe { cycle.core_main_conf_unchecked::<ngx_core_conf_t>(&module) }
46+
.map(|p| p.as_ptr())
47+
.unwrap();
48+
let from_generic = core_main_conf::<ngx_core_conf_t>(&cycle, &module)
49+
.map(|r| r as *const ngx_core_conf_t)
50+
.unwrap();
51+
let from_mut = core_main_conf_mut::<ngx_core_conf_t>(&cycle, &module)
52+
.map(|r| r as *mut ngx_core_conf_t)
53+
.unwrap();
54+
55+
assert_eq!(from_helper, from_manual);
56+
assert_eq!(from_generic, from_manual);
57+
assert_eq!(from_mut, from_manual);
58+
}
59+
60+
#[test]
61+
// Validates that parser-time ngx_conf_t access delegates through cf.cycle and
62+
// still resolves the same core config slot as manual traversal.
63+
fn conf_core_conf_matches_manual_traversal() {
64+
let mut core_conf: ngx_core_conf_t = unsafe { MaybeUninit::zeroed().assume_init() };
65+
let mut slots: [CoreConfSlot; 1] = [(&mut core_conf as *mut ngx_core_conf_t).cast()];
66+
67+
let mut cycle: ngx_cycle_t = unsafe { MaybeUninit::zeroed().assume_init() };
68+
cycle.conf_ctx = slots.as_mut_ptr();
69+
70+
let mut conf: ngx_conf_t = unsafe { MaybeUninit::zeroed().assume_init() };
71+
conf.cycle = &mut cycle;
72+
73+
let module = module_with_index(0);
74+
let from_manual = unsafe { manual_core_main_conf_ptr(&cycle, &module) };
75+
76+
let from_helper = unsafe { conf.core_main_conf_unchecked::<ngx_core_conf_t>(&module) }
77+
.map(|p| p.as_ptr())
78+
.unwrap();
79+
let from_generic = core_main_conf::<ngx_core_conf_t>(&conf, &module)
80+
.map(|r| r as *const ngx_core_conf_t)
81+
.unwrap();
82+
let from_mut = core_main_conf_mut::<ngx_core_conf_t>(&conf, &module)
83+
.map(|r| r as *mut ngx_core_conf_t)
84+
.unwrap();
85+
86+
assert_eq!(from_helper, from_manual);
87+
assert_eq!(from_generic, from_manual);
88+
assert_eq!(from_mut, from_manual);
89+
}

0 commit comments

Comments
 (0)