1use std::ffi::{c_int, c_void, CStr};
9use std::ptr;
10
11use crate::ffi::{vdp_ctx, vfp_ctx, vfp_entry, vrt_ctx, VdpAction, VfpStatus};
12use crate::vcl::{Ctx, VclError};
13use crate::{ffi, validate_vfp_ctx, validate_vfp_entry};
14
15#[derive(Debug, Copy, Clone)]
17pub enum PushResult {
18 Err,
20 Ok,
22 End,
24}
25
26#[derive(Debug, Copy, Clone)]
28pub enum PullResult {
29 Err,
31 Ok(usize),
34 End(usize),
36}
37
38#[derive(Debug)]
40pub enum InitResult<T> {
41 Err(VclError),
42 Ok(T),
43 Pass,
44}
45
46pub trait DeliveryProcessor: Sized {
48 fn name() -> &'static CStr;
50 fn new(vrt_ctx: &mut Ctx, vdp_ctx: &mut DeliveryProcCtx) -> InitResult<Self>;
53 fn push(&mut self, ctx: &mut DeliveryProcCtx, act: VdpAction, buf: &[u8]) -> PushResult;
56}
57
58pub unsafe extern "C" fn gen_vdp_init<T: DeliveryProcessor>(
59 vrt_ctx: *const vrt_ctx,
60 ctx_raw: *mut vdp_ctx,
61 priv_: *mut *mut c_void,
62) -> c_int {
63 assert_ne!(priv_, ptr::null_mut());
64 assert_eq!(*priv_, ptr::null_mut());
65 match T::new(
66 &mut Ctx::from_ptr(vrt_ctx),
67 &mut DeliveryProcCtx::from_ptr(ctx_raw),
68 ) {
69 InitResult::Ok(proc) => {
70 *priv_ = Box::into_raw(Box::new(proc)).cast::<c_void>();
71 0
72 }
73 InitResult::Err(_) => -1, InitResult::Pass => 1,
75 }
76}
77
78pub unsafe extern "C" fn gen_vdp_fini<T: DeliveryProcessor>(
79 _: *mut vdp_ctx,
80 priv_: *mut *mut c_void,
81) -> c_int {
82 if !priv_.is_null() {
83 assert_ne!(*priv_, ptr::null_mut());
84 drop(Box::from_raw((*priv_).cast::<T>()));
85 *priv_ = ptr::null_mut();
86 }
87
88 0
89}
90
91pub unsafe extern "C" fn gen_vdp_push<T: DeliveryProcessor>(
92 ctx_raw: *mut vdp_ctx,
93 act: VdpAction,
94 priv_: *mut *mut c_void,
95 ptr: *const c_void,
96 len: isize,
97) -> c_int {
98 assert_ne!(priv_, ptr::null_mut());
99 assert_ne!(*priv_, ptr::null_mut());
100 if !matches!(act, VdpAction::Null | VdpAction::Flush | VdpAction::End) {
101 return 1; }
103
104 let buf = if ptr.is_null() {
105 &[0; 0]
106 } else {
107 std::slice::from_raw_parts(ptr.cast::<u8>(), len as usize)
108 };
109
110 match (*(*priv_).cast::<T>()).push(&mut DeliveryProcCtx::from_ptr(ctx_raw), act, buf) {
111 PushResult::Err => -1, PushResult::Ok => 0,
113 PushResult::End => 1,
114 }
115}
116
117pub fn new_vdp<T: DeliveryProcessor>() -> ffi::vdp {
119 ffi::vdp {
120 name: T::name().as_ptr(),
121 init: Some(gen_vdp_init::<T>),
122 bytes: Some(gen_vdp_push::<T>),
123 fini: Some(gen_vdp_fini::<T>),
124 priv1: ptr::null(),
125 io_init: None,
126 io_upgrade: None,
127 io_lease: None,
128 io_fini: None,
129 }
130}
131
132#[derive(Debug)]
134pub struct DeliveryProcCtx<'a> {
135 pub raw: &'a mut vdp_ctx,
136}
137
138impl DeliveryProcCtx<'_> {
139 pub(crate) unsafe fn from_ptr(raw: *mut vdp_ctx) -> Self {
145 let raw = raw.as_mut().expect("vdp_ctx pointer must not be null");
146 assert_eq!(raw.magic, ffi::VDP_CTX_MAGIC);
147 Self { raw }
148 }
149
150 pub fn push(&mut self, act: VdpAction, buf: &[u8]) -> PushResult {
152 match unsafe {
153 ffi::VDP_bytes(
154 self.raw,
155 act,
156 buf.as_ptr().cast::<c_void>(),
157 buf.len() as isize,
158 )
159 } {
160 r if r < 0 => PushResult::Err,
161 0 => PushResult::Ok,
162 _ => PushResult::End,
163 }
164 }
165}
166
167pub trait FetchProcessor: Sized {
169 fn name() -> &'static CStr;
171 fn new(vrt_ctx: &mut Ctx, vfp_ctx: &mut FetchProcCtx) -> InitResult<Self>;
173 fn pull(&mut self, ctx: &mut FetchProcCtx, buf: &mut [u8]) -> PullResult;
176}
177
178unsafe extern "C" fn wrap_vfp_init<T: FetchProcessor>(
179 vrt_ctx: *const vrt_ctx,
180 ctxp: *mut vfp_ctx,
181 vfep: *mut vfp_entry,
182) -> VfpStatus {
183 let ctx = validate_vfp_ctx(ctxp);
184 let vfe = validate_vfp_entry(vfep);
185 match T::new(
186 &mut Ctx::from_ptr(vrt_ctx),
187 &mut FetchProcCtx::from_ptr(ctx),
188 ) {
189 InitResult::Ok(proc) => {
190 vfe.priv1 = Box::into_raw(Box::new(proc)).cast::<c_void>();
191 VfpStatus::Ok
192 }
193 InitResult::Err(_) => VfpStatus::Error, InitResult::Pass => VfpStatus::End,
195 }
196}
197
198pub unsafe extern "C" fn wrap_vfp_pull<T: FetchProcessor>(
199 ctxp: *mut vfp_ctx,
200 vfep: *mut vfp_entry,
201 ptr: *mut c_void,
202 len: *mut isize,
203) -> VfpStatus {
204 let ctx = validate_vfp_ctx(ctxp);
205 let vfe = validate_vfp_entry(vfep);
206 let buf = if ptr.is_null() {
207 [0; 0].as_mut()
208 } else {
209 std::slice::from_raw_parts_mut(ptr.cast::<u8>(), *len as usize)
210 };
211 let Some(obj) = vfe.priv1.cast::<T>().as_mut() else {
212 return VfpStatus::Error;
214 };
215 match obj.pull(&mut FetchProcCtx::from_ptr(ctx), buf) {
216 PullResult::Err => VfpStatus::Error, PullResult::Ok(l) => {
218 *len = l as isize;
219 VfpStatus::Ok
220 }
221 PullResult::End(l) => {
222 *len = l as isize;
223 VfpStatus::End
224 }
225 }
226}
227
228pub unsafe extern "C" fn wrap_vfp_fini<T: FetchProcessor>(
229 ctxp: *mut vfp_ctx,
230 vfep: *mut vfp_entry,
231) {
232 validate_vfp_ctx(ctxp);
233 let vfe = validate_vfp_entry(vfep);
234 if !vfe.priv1.is_null() {
235 let p = ptr::replace(&raw mut vfe.priv1, ptr::null_mut());
236 drop(Box::from_raw(p.cast::<T>()));
237 }
238}
239
240pub fn new_vfp<T: FetchProcessor>() -> ffi::vfp {
242 ffi::vfp {
243 name: T::name().as_ptr(),
244 init: Some(wrap_vfp_init::<T>),
245 pull: Some(wrap_vfp_pull::<T>),
246 fini: Some(wrap_vfp_fini::<T>),
247 priv1: ptr::null(),
248 }
249}
250
251#[derive(Debug)]
253pub struct FetchProcCtx<'a> {
254 pub raw: &'a mut vfp_ctx,
255}
256
257impl FetchProcCtx<'_> {
258 pub(crate) unsafe fn from_ptr(raw: *mut vfp_ctx) -> Self {
264 Self {
265 raw: validate_vfp_ctx(raw),
266 }
267 }
268
269 pub fn pull(&mut self, buf: &mut [u8]) -> PullResult {
271 let mut len = buf.len() as isize;
272 let max_len = len;
273
274 match unsafe { ffi::VFP_Suck(self.raw, buf.as_ptr() as *mut c_void, &raw mut len) } {
275 VfpStatus::Ok => {
276 assert!(len <= max_len);
277 assert!(len >= 0);
278 PullResult::Ok(len as usize)
279 }
280 VfpStatus::End => {
281 assert!(len <= max_len);
282 assert!(len >= 0);
283 PullResult::End(len as usize)
284 }
285 VfpStatus::Error => PullResult::Err,
286 VfpStatus::Null => panic!("VFP_Suck() was never supposed to return VFP_NULL!"),
287 #[expect(unreachable_patterns)]
290 n => panic!("unknown VfpStatus {n:?}"),
291 }
292 }
293}
294
295#[derive(Debug)]
296pub struct FetchFilters<'c, 'f> {
297 ctx: &'c vrt_ctx,
298 #[expect(clippy::vec_box)]
301 filters: &'f mut Vec<Box<ffi::vfp>>,
302}
303
304impl<'c, 'f> FetchFilters<'c, 'f> {
305 #[expect(clippy::vec_box)]
306 pub(crate) fn new(ctx: &'c vrt_ctx, filters: &'f mut Vec<Box<ffi::vfp>>) -> Self {
307 Self { ctx, filters }
308 }
309
310 fn find_position<T: FetchProcessor>(&self) -> Option<usize> {
311 let name = T::name().as_ptr();
312 self.filters.iter().position(|f| f.name == name)
313 }
314
315 pub fn register<T: FetchProcessor>(&mut self) -> bool {
316 if self.find_position::<T>().is_none() {
317 let instance = Box::new(new_vfp::<T>());
318 unsafe {
319 ffi::VRT_AddFilter(self.ctx, instance.as_ref(), ptr::null());
320 }
321 self.filters.push(instance);
322 true
323 } else {
324 false
325 }
326 }
327
328 pub fn unregister<T: FetchProcessor>(&mut self) -> bool {
329 if let Some(pos) = self.find_position::<T>() {
330 let filter = self.filters.swap_remove(pos);
331 unsafe {
332 ffi::VRT_RemoveFilter(self.ctx, filter.as_ref(), ptr::null());
333 }
334 true
335 } else {
336 false
337 }
338 }
339
340 pub fn unregister_all(&mut self) {
341 for filter in self.filters.drain(..) {
342 unsafe { ffi::VRT_RemoveFilter(self.ctx, filter.as_ref(), ptr::null()) }
343 }
344 }
345}
346
347#[derive(Debug)]
348pub struct DeliveryFilters<'c, 'f> {
349 ctx: &'c vrt_ctx,
350 #[expect(clippy::vec_box)]
353 filters: &'f mut Vec<Box<ffi::vdp>>,
354}
355
356impl<'c, 'f> DeliveryFilters<'c, 'f> {
357 #[expect(clippy::vec_box)]
358 pub(crate) fn new(ctx: &'c vrt_ctx, filters: &'f mut Vec<Box<ffi::vdp>>) -> Self {
359 Self { ctx, filters }
360 }
361
362 fn find_position<T: DeliveryProcessor>(&self) -> Option<usize> {
363 let name = T::name().as_ptr();
364 self.filters.iter().position(|f| f.name == name)
365 }
366
367 pub fn register<T: DeliveryProcessor>(&mut self) -> bool {
368 if self.find_position::<T>().is_none() {
369 let instance = Box::new(new_vdp::<T>());
370 unsafe {
371 ffi::VRT_AddFilter(self.ctx, ptr::null(), instance.as_ref());
372 }
373 self.filters.push(instance);
374 true
375 } else {
376 false
377 }
378 }
379
380 pub fn unregister<T: DeliveryProcessor>(&mut self) -> bool {
381 if let Some(pos) = self.find_position::<T>() {
382 let filter = self.filters.swap_remove(pos);
383 unsafe {
384 ffi::VRT_RemoveFilter(self.ctx, ptr::null(), filter.as_ref());
385 }
386 true
387 } else {
388 false
389 }
390 }
391
392 pub fn unregister_all(&mut self) {
393 for filter in self.filters.drain(..) {
394 unsafe { ffi::VRT_RemoveFilter(self.ctx, ptr::null(), filter.as_ref()) }
395 }
396 }
397}