varnish_sys/extensions.rs
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
use std::ffi::c_void;
use std::ptr;
use std::ptr::null;
use crate::ffi::{vmod_priv, vmod_priv_methods, vrt_ctx};
use crate::validate_vrt_ctx;
use crate::vcl::PerVclState;
/// SAFETY: ensured by Varnish itself
unsafe impl Sync for vmod_priv_methods {}
impl vmod_priv {
/// Transfer ownership of the object to the caller, cleaning up the internal state.
///
/// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
pub unsafe fn take<T>(&mut self) -> Option<Box<T>> {
// methods does not need to be dropped because `put` always sets it to a static reference
self.methods = null();
get_owned_bbox(&mut self.priv_)
}
pub unsafe fn take_per_vcl<T>(&mut self) -> Box<PerVclState<T>> {
if let Some(v) = self.take::<PerVclState<T>>() {
v
} else {
let o = PerVclState::<T>::default();
Box::new(o)
}
}
/// Set the object and methods for the `vmod_priv`, and the corresponding static methods.
///
/// SAFETY: The type of `obj` must match the type of the function pointers in `methods`.
pub unsafe fn put<T>(&mut self, obj: Box<T>, methods: &'static vmod_priv_methods) {
self.priv_ = Box::into_raw(obj).cast();
self.methods = methods;
}
/// Use the object as a reference, without taking ownership.
///
/// SAFETY:
/// * `priv_` must reference a valid `T` object pointer or `NULL`
/// * `take()` must not be called on the same `vmod_priv` object until the returned reference is dropped
/// * cleanup must not be done on the object until the returned reference is dropped
/// * assumes `Box<T>` is equivalent to `&T` when used as a readonly reference, i.e. a box is just a pointer
pub unsafe fn get_ref<T>(&self) -> Option<&T> {
self.priv_.cast::<T>().as_ref()
}
/// A Varnish callback function to free a `vmod_priv` object.
/// Here we take the ownership and immediately drop the object of type `T`.
/// Note that here we get `*priv_` directly, not the `*vmod_priv`
///
/// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
pub unsafe extern "C" fn on_fini<T>(_ctx: *const vrt_ctx, mut priv_: *mut c_void) {
drop(get_owned_bbox::<T>(&mut priv_));
}
/// A Varnish callback function to clean up the `PerVclState` object.
/// Similar to `on_fini`, but also unregisters filters.
///
/// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
pub unsafe extern "C" fn on_fini_per_vcl<T>(ctx: *const vrt_ctx, mut priv_: *mut c_void) {
if let Some(obj) = get_owned_bbox::<PerVclState<T>>(&mut priv_) {
let PerVclState {
mut fetch_filters,
mut delivery_filters,
user_data,
} = *obj;
let ctx = validate_vrt_ctx(ctx);
ctx.fetch_filters(&mut fetch_filters).unregister_all();
ctx.delivery_filters(&mut delivery_filters).unregister_all();
drop(user_data);
}
}
}
/// Take ownership of the object of type `T` and return it as a `Box<T>`.
/// The original pointer is set to null.
///
/// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
unsafe fn get_owned_bbox<T>(priv_: &mut *mut c_void) -> Option<Box<T>> {
let obj = ptr::replace(priv_, ptr::null_mut());
if obj.is_null() {
None
} else {
Some(Box::from_raw(obj.cast::<T>()))
}
}