Reborrowing turns a raw pointer into a Rust reference. In an NGINX callback, the request arrives as a raw pointer, but the function that reads its body takes a reference. After checking that the pointer is not null, `let request = &*r;` dereferences it with `*` and takes a reference with `&`. section 4.4
The pointer and reference are the same at runtime; the difference is what Rust assumes about them. A reference must point to aligned, initialized data, must not be null, and has a lifetime during which it remains valid. A null check establishes only one of those conditions. Creating the reference from a raw pointer still requires care in unsafe code, even though ordinary code can then use the reference without dereferencing the raw pointer repeatedly. section 4.4
unsafe extern "C" fn read_body_handler(r: *mut ngx_http_request_t)
{
if r.is_null() {
eprintln!("got null request in body handler");
return;
}
let request = &*r;
let body = match request_body_as_str(request) {
Ok(body) => body,
Err(e) => {
eprintln!("failed to parse body: {}", e);
return;
}
};
eprintln!("Read request body: {:?}", body);
}
See the callback’s null check, `&*r` conversion, and call to a body-reading function that accepts the resulting reference. section 4.4
When the code needs to modify a value, it can make a mutable reborrow instead. After checking that an NGINX-allocated buffer pointer is not null, `let buf = &mut (*buf_p);` gives the response-writing code a mutable reference for setting buffer fields. This avoids repeating raw-pointer dereferences. section 4.6
let buf_p =
ngx_pcalloc(request.pool, std::mem::size_of::<
ngx_buf_t>() as size_t)
as *mut ngx_buf_t;
if buf_p.is_null() {
return Err("Failed to allocate buffer");
}
let buf = &mut (*buf_p);
buf.set_last_buf(1);
buf.set_last_in_chain(1);
buf.set_memory(1);
See the allocation, null check, mutable reborrow, and subsequent buffer-setting calls together. section 4.6
