varnish_sys/
extensions.rs

1use std::ffi::c_void;
2use std::ptr;
3
4use crate::ffi::{vmod_data, vmod_priv};
5use crate::vcl::PerVclState;
6
7/// SAFETY: ensured by Varnish itself
8unsafe impl Sync for vmod_data {}
9
10/// Take ownership of the object of type `T` and return it as a `Box<T>`.
11/// The original pointer is set to null.
12///
13/// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
14unsafe fn get_owned_bbox<T>(priv_: &mut *mut c_void) -> Option<Box<T>> {
15    let obj = ptr::replace(priv_, ptr::null_mut());
16    if obj.is_null() {
17        None
18    } else {
19        Some(Box::from_raw(obj.cast::<T>()))
20    }
21}
22
23impl vmod_priv {
24    /// Transfer ownership of the object to the caller, cleaning up the internal state.
25    ///
26    /// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
27    pub unsafe fn take<T>(&mut self) -> Option<Box<T>> {
28        // methods does not need to be dropped because `put` always sets it to a static reference
29        #[cfg(not(varnishsys_6))]
30        {
31            self.methods = ptr::null();
32        }
33        get_owned_bbox(&mut self.priv_)
34    }
35
36    #[expect(clippy::unnecessary_box_returns)]
37    pub unsafe fn take_per_vcl<T>(&mut self) -> Box<PerVclState<T>> {
38        if let Some(v) = self.take::<PerVclState<T>>() {
39            v
40        } else {
41            let o = PerVclState::<T>::default();
42            Box::new(o)
43        }
44    }
45
46    /// Use the object as a reference, without taking ownership.
47    ///
48    /// SAFETY:
49    /// * `priv_` must reference a valid `T` object pointer or `NULL`
50    /// * `take()` must not be called on the same `vmod_priv` object until the returned reference is dropped
51    /// * cleanup must not be done on the object until the returned reference is dropped
52    /// * assumes `Box<T>` is equivalent to `&T` when used as a readonly reference, i.e. a box is just a pointer
53    pub unsafe fn get_ref<T>(&self) -> Option<&T> {
54        self.priv_.cast::<T>().as_ref()
55    }
56}
57
58#[cfg(varnishsys_6)]
59mod version_v6 {
60    use std::ffi::c_void;
61
62    use super::get_owned_bbox;
63    use crate::ffi::{vmod_priv, vmod_priv_free_f};
64    use crate::vcl::PerVclState;
65
66    impl vmod_priv {
67        /// Set the object and methods for the `vmod_priv`, and the corresponding static methods.
68        ///
69        /// SAFETY: The type of `obj` must match the type of the function pointers in `methods`.
70        pub unsafe fn put<T>(&mut self, obj: Box<T>, free_method: vmod_priv_free_f) {
71            self.priv_ = Box::into_raw(obj).cast();
72            self.free = free_method;
73        }
74
75        /// A Varnish callback function to free a `vmod_priv` object.
76        /// Here we take the ownership and immediately drop the object of type `T`.
77        /// Note that here we get `*priv_` directly, not the `*vmod_priv`
78        ///
79        /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
80        pub unsafe extern "C" fn on_fini<T>(mut priv_: *mut c_void) {
81            drop(get_owned_bbox::<T>(&mut priv_));
82        }
83
84        /// A Varnish callback function to clean up the `PerVclState` object.
85        /// Similar to `on_fini`, but also unregisters filters.
86        ///
87        /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
88        pub unsafe extern "C" fn on_fini_per_vcl<T>(mut priv_: *mut c_void) {
89            if let Some(obj) = get_owned_bbox::<PerVclState<T>>(&mut priv_) {
90                let PerVclState { user_data } = *obj;
91                drop(user_data);
92            }
93        }
94    }
95}
96
97#[cfg(not(varnishsys_6))]
98mod version_after_v6 {
99    use std::ffi::c_void;
100
101    use super::get_owned_bbox;
102    use crate::ffi::{vmod_priv, vmod_priv_methods, vrt_ctx};
103    use crate::validate_vrt_ctx;
104    use crate::vcl::PerVclState;
105
106    /// SAFETY: ensured by Varnish itself
107    unsafe impl Sync for vmod_priv_methods {}
108
109    impl vmod_priv {
110        /// Set the object and methods for the `vmod_priv`, and the corresponding static methods.
111        ///
112        /// SAFETY: The type of `obj` must match the type of the function pointers in `methods`.
113        pub unsafe fn put<T>(&mut self, obj: Box<T>, methods: &'static vmod_priv_methods) {
114            self.priv_ = Box::into_raw(obj).cast();
115            self.methods = methods;
116        }
117
118        /// A Varnish callback function to free a `vmod_priv` object.
119        /// Here we take the ownership and immediately drop the object of type `T`.
120        /// Note that here we get `*priv_` directly, not the `*vmod_priv`
121        ///
122        /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
123        pub unsafe extern "C" fn on_fini<T>(_ctx: *const vrt_ctx, mut priv_: *mut c_void) {
124            drop(get_owned_bbox::<T>(&mut priv_));
125        }
126
127        /// A Varnish callback function to clean up the `PerVclState` object.
128        /// Similar to `on_fini`, but also unregisters filters.
129        ///
130        /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
131        pub unsafe extern "C" fn on_fini_per_vcl<T>(ctx: *const vrt_ctx, mut priv_: *mut c_void) {
132            if let Some(obj) = get_owned_bbox::<PerVclState<T>>(&mut priv_) {
133                let PerVclState {
134                    mut fetch_filters,
135                    mut delivery_filters,
136                    user_data,
137                } = *obj;
138                let ctx = validate_vrt_ctx(ctx);
139                ctx.fetch_filters(&mut fetch_filters).unregister_all();
140                ctx.delivery_filters(&mut delivery_filters).unregister_all();
141                drop(user_data);
142            }
143        }
144    }
145}