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}