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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
//! Example demonstrating how to use apr-rs when creating bindings for C libraries that use APR.
//!
//! This example shows the typical pattern for integrating with APR-based C libraries:
//! 1. Creating APR memory pools
//! 2. Passing APR types to C functions
//! 3. Handling APR status codes
//! 4. Managing memory lifecycle
use apr::{Pool, Result, Status};
use std::ffi::CString;
// Example: Simulating bindings for a hypothetical C library that uses APR
// In a real scenario, these would be actual FFI declarations to your C library
#[allow(dead_code)]
mod ffi {
use std::os::raw::{c_char, c_int};
// Simulated C function signatures that would come from your C library
// In reality, these would be:
// extern "C" {
// pub fn library_init(pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t;
// pub fn library_process_data(
// data: *const c_char,
// len: c_int,
// pool: *mut apr_sys::apr_pool_t
// ) -> apr_sys::apr_status_t;
// pub fn library_cleanup(pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t;
// }
// For this example, we'll simulate these functions
pub unsafe fn library_init(_pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t {
0 // APR_SUCCESS
}
pub unsafe fn library_process_data(
_data: *const c_char,
_len: c_int,
_pool: *mut apr_sys::apr_pool_t,
) -> apr_sys::apr_status_t {
0 // APR_SUCCESS
}
pub unsafe fn library_cleanup(_pool: *mut apr_sys::apr_pool_t) -> apr_sys::apr_status_t {
0 // APR_SUCCESS
}
}
/// Wrapper struct for our C library
pub struct CLibraryWrapper {
pool: Pool,
}
impl CLibraryWrapper {
/// Initialize the C library with its own memory pool
pub fn new() -> Result<Self> {
// Create a dedicated pool for this library instance
let pool = Pool::new();
// Initialize the C library
let status = unsafe { Status::from(ffi::library_init(pool.as_mut_ptr())) };
if !status.is_success() {
return Err(status.into());
}
Ok(CLibraryWrapper { pool })
}
/// Process data using the C library
pub fn process_data(&self, data: &str) -> Result<()> {
// Convert Rust string to C string
let c_data = CString::new(data)
.map_err(|_| apr::Error::from(Status::from(apr_sys::APR_EINVAL as i32)))?;
// Call the C function
let status = unsafe {
Status::from(ffi::library_process_data(
c_data.as_ptr(),
data.len() as i32,
self.pool.as_mut_ptr(),
))
};
if status.is_success() {
Ok(())
} else {
Err(status.into())
}
}
/// Create a sub-operation with its own memory scope
pub fn scoped_operation<F, R>(&self, operation: F) -> Result<R>
where
F: FnOnce(&Pool) -> Result<R>,
{
// Create a subpool for this operation
let subpool = Pool::new();
// Execute the operation with the subpool
// Subpool is automatically cleaned up when dropped
operation(&subpool)
}
}
impl Drop for CLibraryWrapper {
fn drop(&mut self) {
// Clean up the C library
unsafe {
let _ = ffi::library_cleanup(self.pool.as_mut_ptr());
}
// Pool is automatically cleaned up when dropped
}
}
fn main() -> Result<()> {
println!("Demonstrating C library integration with APR...\n");
// Initialize our wrapped C library
let library = CLibraryWrapper::new()?;
println!("✓ C library initialized with APR pool");
// Process some data
library.process_data("Hello from Rust!")?;
println!("✓ Processed data through C library");
// Demonstrate scoped memory management
library.scoped_operation(|subpool| {
println!("✓ Created subpool for scoped operation");
// In a real scenario, you might pass this subpool to C functions
// that need temporary memory
let _subpool_ptr = subpool.as_mut_ptr();
// Simulate some work...
println!(" Performing work with subpool...");
Ok(())
})?;
println!("✓ Subpool automatically cleaned up");
// Demonstrate error handling
match library.process_data("Another message") {
Ok(()) => println!("✓ Successfully processed second message"),
Err(e) => eprintln!("✗ Error processing message: {}", e),
}
println!("\n✓ Library will be cleaned up when dropped");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_library_lifecycle() {
// Test that we can create and destroy the library wrapper
let library = CLibraryWrapper::new().expect("Failed to create library");
drop(library);
}
#[test]
fn test_scoped_operations() {
let library = CLibraryWrapper::new().expect("Failed to create library");
let result = library.scoped_operation(|_pool| {
// Simulate some operation
Ok(42)
});
assert_eq!(result.unwrap(), 42);
}
}
|