ngx/core/pool.rs
1use core::ffi::c_void;
2use core::{mem, ptr};
3
4use crate::core::buffer::{Buffer, MemoryBuffer, TemporaryBuffer};
5use crate::ffi::*;
6
7/// Wrapper struct for an [`ngx_pool_t`] pointer, providing methods for working with memory pools.
8///
9/// See <https://nginx.org/en/docs/dev/development_guide.html#pool>
10pub struct Pool(*mut ngx_pool_t);
11
12impl Pool {
13 /// Creates a new `Pool` from an `ngx_pool_t` pointer.
14 ///
15 /// # Safety
16 /// The caller must ensure that a valid `ngx_pool_t` pointer is provided, pointing to valid memory and non-null.
17 /// A null argument will cause an assertion failure and panic.
18 pub unsafe fn from_ngx_pool(pool: *mut ngx_pool_t) -> Pool {
19 assert!(!pool.is_null());
20 Pool(pool)
21 }
22
23 /// Creates a buffer of the specified size in the memory pool.
24 ///
25 /// Returns `Some(TemporaryBuffer)` if the buffer is successfully created, or `None` if allocation fails.
26 pub fn create_buffer(&mut self, size: usize) -> Option<TemporaryBuffer> {
27 let buf = unsafe { ngx_create_temp_buf(self.0, size) };
28 if buf.is_null() {
29 return None;
30 }
31
32 Some(TemporaryBuffer::from_ngx_buf(buf))
33 }
34
35 /// Creates a buffer from a string in the memory pool.
36 ///
37 /// Returns `Some(TemporaryBuffer)` if the buffer is successfully created, or `None` if allocation fails.
38 pub fn create_buffer_from_str(&mut self, str: &str) -> Option<TemporaryBuffer> {
39 let mut buffer = self.create_buffer(str.len())?;
40 unsafe {
41 let buf = buffer.as_ngx_buf_mut();
42 ptr::copy_nonoverlapping(str.as_ptr(), (*buf).pos, str.len());
43 (*buf).last = (*buf).pos.add(str.len());
44 }
45 Some(buffer)
46 }
47
48 /// Creates a buffer from a static string in the memory pool.
49 ///
50 /// Returns `Some(MemoryBuffer)` if the buffer is successfully created, or `None` if allocation fails.
51 pub fn create_buffer_from_static_str(&mut self, str: &'static str) -> Option<MemoryBuffer> {
52 let buf = self.calloc_type::<ngx_buf_t>();
53 if buf.is_null() {
54 return None;
55 }
56
57 // We cast away const, but buffers with the memory flag are read-only
58 let start = str.as_ptr() as *mut u8;
59 let end = unsafe { start.add(str.len()) };
60
61 unsafe {
62 (*buf).start = start;
63 (*buf).pos = start;
64 (*buf).last = end;
65 (*buf).end = end;
66 (*buf).set_memory(1);
67 }
68
69 Some(MemoryBuffer::from_ngx_buf(buf))
70 }
71
72 /// Adds a cleanup handler for a value in the memory pool.
73 ///
74 /// Returns `Ok(())` if the cleanup handler is successfully added, or `Err(())` if the cleanup handler cannot be added.
75 ///
76 /// # Safety
77 /// This function is marked as unsafe because it involves raw pointer manipulation.
78 unsafe fn add_cleanup_for_value<T>(&mut self, value: *mut T) -> Result<(), ()> {
79 let cln = ngx_pool_cleanup_add(self.0, 0);
80 if cln.is_null() {
81 return Err(());
82 }
83 (*cln).handler = Some(cleanup_type::<T>);
84 (*cln).data = value as *mut c_void;
85
86 Ok(())
87 }
88
89 /// Allocates memory from the pool of the specified size.
90 /// The resulting pointer is aligned to a platform word size.
91 ///
92 /// Returns a raw pointer to the allocated memory.
93 pub fn alloc(&mut self, size: usize) -> *mut c_void {
94 unsafe { ngx_palloc(self.0, size) }
95 }
96
97 /// Allocates memory for a type from the pool.
98 /// The resulting pointer is aligned to a platform word size.
99 ///
100 /// Returns a typed pointer to the allocated memory.
101 pub fn alloc_type<T: Copy>(&mut self) -> *mut T {
102 self.alloc(mem::size_of::<T>()) as *mut T
103 }
104
105 /// Allocates zeroed memory from the pool of the specified size.
106 /// The resulting pointer is aligned to a platform word size.
107 ///
108 /// Returns a raw pointer to the allocated memory.
109 pub fn calloc(&mut self, size: usize) -> *mut c_void {
110 unsafe { ngx_pcalloc(self.0, size) }
111 }
112
113 /// Allocates zeroed memory for a type from the pool.
114 /// The resulting pointer is aligned to a platform word size.
115 ///
116 /// Returns a typed pointer to the allocated memory.
117 pub fn calloc_type<T: Copy>(&mut self) -> *mut T {
118 self.calloc(mem::size_of::<T>()) as *mut T
119 }
120
121 /// Allocates unaligned memory from the pool of the specified size.
122 ///
123 /// Returns a raw pointer to the allocated memory.
124 pub fn alloc_unaligned(&mut self, size: usize) -> *mut c_void {
125 unsafe { ngx_pnalloc(self.0, size) }
126 }
127
128 /// Allocates unaligned memory for a type from the pool.
129 ///
130 /// Returns a typed pointer to the allocated memory.
131 pub fn alloc_type_unaligned<T: Copy>(&mut self) -> *mut T {
132 self.alloc_unaligned(mem::size_of::<T>()) as *mut T
133 }
134
135 /// Allocates memory for a value of a specified type and adds a cleanup handler to the memory pool.
136 ///
137 /// Returns a typed pointer to the allocated memory if successful, or a null pointer if allocation or cleanup handler addition fails.
138 pub fn allocate<T>(&mut self, value: T) -> *mut T {
139 unsafe {
140 let p = self.alloc(mem::size_of::<T>()) as *mut T;
141 ptr::write(p, value);
142 if self.add_cleanup_for_value(p).is_err() {
143 ptr::drop_in_place(p);
144 return ptr::null_mut();
145 };
146 p
147 }
148 }
149}
150
151/// Cleanup handler for a specific type `T`.
152///
153/// This function is called when cleaning up a value of type `T` in an FFI context.
154///
155/// # Safety
156/// This function is marked as unsafe due to the raw pointer manipulation and the assumption that `data` is a valid pointer to `T`.
157///
158/// # Arguments
159///
160/// * `data` - A raw pointer to the value of type `T` to be cleaned up.
161unsafe extern "C" fn cleanup_type<T>(data: *mut c_void) {
162 ptr::drop_in_place(data as *mut T);
163}