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}