1use std::any::Any;
19use std::ffi::c_void;
20use std::sync::Arc;
21
22use datafusion_common::error::Result;
23use datafusion_execution::TaskContext;
24use datafusion_expr::{
25 AggregateUDF, AggregateUDFImpl, ScalarUDF, ScalarUDFImpl, WindowUDF, WindowUDFImpl,
26};
27use datafusion_physical_plan::ExecutionPlan;
28use datafusion_proto::physical_plan::{
29 DefaultPhysicalProtoConverter, PhysicalExtensionCodec,
30 PhysicalProtoConverterExtension,
31};
32
33use stabby::slice::Slice as SSlice;
34use stabby::str::Str as SStr;
35use stabby::vec::Vec as SVec;
36use tokio::runtime::Handle;
37
38use crate::execution::FFI_TaskContextProvider;
39use crate::execution_plan::FFI_ExecutionPlan;
40use crate::udaf::FFI_AggregateUDF;
41use crate::udf::FFI_ScalarUDF;
42use crate::udwf::FFI_WindowUDF;
43use crate::util::FFI_Result;
44use crate::{df_result, sresult_return};
45
46#[repr(C)]
48#[derive(Debug)]
49pub struct FFI_PhysicalExtensionCodec {
50 try_decode: unsafe extern "C" fn(
52 &Self,
53 buf: SSlice<u8>,
54 inputs: SVec<FFI_ExecutionPlan>,
55 ) -> FFI_Result<FFI_ExecutionPlan>,
56
57 try_encode:
59 unsafe extern "C" fn(&Self, node: FFI_ExecutionPlan) -> FFI_Result<SVec<u8>>,
60
61 try_decode_udf: unsafe extern "C" fn(
63 &Self,
64 name: SStr,
65 buf: SSlice<u8>,
66 ) -> FFI_Result<FFI_ScalarUDF>,
67
68 try_encode_udf:
70 unsafe extern "C" fn(&Self, node: FFI_ScalarUDF) -> FFI_Result<SVec<u8>>,
71
72 try_decode_udaf: unsafe extern "C" fn(
74 &Self,
75 name: SStr,
76 buf: SSlice<u8>,
77 ) -> FFI_Result<FFI_AggregateUDF>,
78
79 try_encode_udaf:
81 unsafe extern "C" fn(&Self, node: FFI_AggregateUDF) -> FFI_Result<SVec<u8>>,
82
83 try_decode_udwf: unsafe extern "C" fn(
85 &Self,
86 name: SStr,
87 buf: SSlice<u8>,
88 ) -> FFI_Result<FFI_WindowUDF>,
89
90 try_encode_udwf:
92 unsafe extern "C" fn(&Self, node: FFI_WindowUDF) -> FFI_Result<SVec<u8>>,
93
94 pub(crate) task_ctx_provider: FFI_TaskContextProvider,
96
97 pub clone: unsafe extern "C" fn(plan: &Self) -> Self,
100
101 pub release: unsafe extern "C" fn(arg: &mut Self),
103
104 pub version: unsafe extern "C" fn() -> u64,
106
107 pub private_data: *mut c_void,
110
111 pub library_marker_id: extern "C" fn() -> usize,
114}
115
116unsafe impl Send for FFI_PhysicalExtensionCodec {}
117unsafe impl Sync for FFI_PhysicalExtensionCodec {}
118
119struct PhysicalExtensionCodecPrivateData {
120 codec: Arc<dyn PhysicalExtensionCodec>,
121 runtime: Option<Handle>,
122}
123
124impl FFI_PhysicalExtensionCodec {
125 fn inner(&self) -> &Arc<dyn PhysicalExtensionCodec> {
126 let private_data = self.private_data as *const PhysicalExtensionCodecPrivateData;
127 unsafe { &(*private_data).codec }
128 }
129
130 fn runtime(&self) -> &Option<Handle> {
131 let private_data = self.private_data as *const PhysicalExtensionCodecPrivateData;
132 unsafe { &(*private_data).runtime }
133 }
134}
135
136unsafe extern "C" fn try_decode_fn_wrapper(
137 codec: &FFI_PhysicalExtensionCodec,
138 buf: SSlice<u8>,
139 inputs: SVec<FFI_ExecutionPlan>,
140) -> FFI_Result<FFI_ExecutionPlan> {
141 let runtime = codec.runtime().clone();
142 let task_ctx: Arc<TaskContext> =
143 sresult_return!((&codec.task_ctx_provider).try_into());
144 let codec = codec.inner();
145 let inputs = inputs
146 .into_iter()
147 .map(|plan| <Arc<dyn ExecutionPlan>>::try_from(&plan))
148 .collect::<Result<Vec<_>>>();
149 let inputs = sresult_return!(inputs);
150
151 let plan = sresult_return!(codec.try_decode(
152 buf.as_ref(),
153 &inputs,
154 task_ctx.as_ref(),
155 &DefaultPhysicalProtoConverter {},
156 ));
157
158 FFI_Result::Ok(FFI_ExecutionPlan::new(plan, runtime))
159}
160
161unsafe extern "C" fn try_encode_fn_wrapper(
162 codec: &FFI_PhysicalExtensionCodec,
163 node: FFI_ExecutionPlan,
164) -> FFI_Result<SVec<u8>> {
165 let codec = codec.inner();
166
167 let plan: Arc<dyn ExecutionPlan> = sresult_return!((&node).try_into());
168
169 let mut bytes = Vec::new();
170 sresult_return!(codec.try_encode(
171 plan,
172 &mut bytes,
173 &DefaultPhysicalProtoConverter {}
174 ));
175
176 FFI_Result::Ok(bytes.into_iter().collect())
177}
178
179unsafe extern "C" fn try_decode_udf_fn_wrapper(
180 codec: &FFI_PhysicalExtensionCodec,
181 name: SStr,
182 buf: SSlice<u8>,
183) -> FFI_Result<FFI_ScalarUDF> {
184 let codec = codec.inner();
185
186 let udf = sresult_return!(codec.try_decode_udf(name.as_str(), buf.as_ref()));
187 let udf = FFI_ScalarUDF::from(udf);
188
189 FFI_Result::Ok(udf)
190}
191
192unsafe extern "C" fn try_encode_udf_fn_wrapper(
193 codec: &FFI_PhysicalExtensionCodec,
194 node: FFI_ScalarUDF,
195) -> FFI_Result<SVec<u8>> {
196 let codec = codec.inner();
197 let node: Arc<dyn ScalarUDFImpl> = (&node).into();
198 let node = ScalarUDF::new_from_shared_impl(node);
199
200 let mut bytes = Vec::new();
201 sresult_return!(codec.try_encode_udf(&node, &mut bytes));
202
203 FFI_Result::Ok(bytes.into_iter().collect())
204}
205
206unsafe extern "C" fn try_decode_udaf_fn_wrapper(
207 codec: &FFI_PhysicalExtensionCodec,
208 name: SStr,
209 buf: SSlice<u8>,
210) -> FFI_Result<FFI_AggregateUDF> {
211 let codec_inner = codec.inner();
212 let udaf = sresult_return!(codec_inner.try_decode_udaf(name.into(), buf.as_ref()));
213 let udaf = FFI_AggregateUDF::from(udaf);
214
215 FFI_Result::Ok(udaf)
216}
217
218unsafe extern "C" fn try_encode_udaf_fn_wrapper(
219 codec: &FFI_PhysicalExtensionCodec,
220 node: FFI_AggregateUDF,
221) -> FFI_Result<SVec<u8>> {
222 let codec = codec.inner();
223 let udaf: Arc<dyn AggregateUDFImpl> = (&node).into();
224 let udaf = AggregateUDF::new_from_shared_impl(udaf);
225
226 let mut bytes = Vec::new();
227 sresult_return!(codec.try_encode_udaf(&udaf, &mut bytes));
228
229 FFI_Result::Ok(bytes.into_iter().collect())
230}
231
232unsafe extern "C" fn try_decode_udwf_fn_wrapper(
233 codec: &FFI_PhysicalExtensionCodec,
234 name: SStr,
235 buf: SSlice<u8>,
236) -> FFI_Result<FFI_WindowUDF> {
237 let codec = codec.inner();
238 let udwf = sresult_return!(codec.try_decode_udwf(name.into(), buf.as_ref()));
239 let udwf = FFI_WindowUDF::from(udwf);
240
241 FFI_Result::Ok(udwf)
242}
243
244unsafe extern "C" fn try_encode_udwf_fn_wrapper(
245 codec: &FFI_PhysicalExtensionCodec,
246 node: FFI_WindowUDF,
247) -> FFI_Result<SVec<u8>> {
248 let codec = codec.inner();
249 let udwf: Arc<dyn WindowUDFImpl> = (&node).into();
250 let udwf = WindowUDF::new_from_shared_impl(udwf);
251
252 let mut bytes = Vec::new();
253 sresult_return!(codec.try_encode_udwf(&udwf, &mut bytes));
254
255 FFI_Result::Ok(bytes.into_iter().collect())
256}
257
258unsafe extern "C" fn release_fn_wrapper(codec: &mut FFI_PhysicalExtensionCodec) {
259 unsafe {
260 let private_data =
261 Box::from_raw(codec.private_data as *mut PhysicalExtensionCodecPrivateData);
262 drop(private_data);
263 }
264}
265
266unsafe extern "C" fn clone_fn_wrapper(
267 codec: &FFI_PhysicalExtensionCodec,
268) -> FFI_PhysicalExtensionCodec {
269 let old_codec = Arc::clone(codec.inner());
270 let runtime = codec.runtime().clone();
271
272 FFI_PhysicalExtensionCodec::new(old_codec, runtime, codec.task_ctx_provider.clone())
273}
274
275impl Drop for FFI_PhysicalExtensionCodec {
276 fn drop(&mut self) {
277 unsafe { (self.release)(self) }
278 }
279}
280
281impl FFI_PhysicalExtensionCodec {
282 pub fn new(
284 codec: Arc<dyn PhysicalExtensionCodec>,
285 runtime: Option<Handle>,
286 task_ctx_provider: impl Into<FFI_TaskContextProvider>,
287 ) -> Self {
288 if let Some(codec) = (Arc::clone(&codec) as Arc<dyn Any>)
289 .downcast_ref::<ForeignPhysicalExtensionCodec>()
290 {
291 return codec.0.clone();
292 }
293
294 let task_ctx_provider = task_ctx_provider.into();
295 let private_data = Box::new(PhysicalExtensionCodecPrivateData { codec, runtime });
296
297 Self {
298 try_decode: try_decode_fn_wrapper,
299 try_encode: try_encode_fn_wrapper,
300 try_decode_udf: try_decode_udf_fn_wrapper,
301 try_encode_udf: try_encode_udf_fn_wrapper,
302 try_decode_udaf: try_decode_udaf_fn_wrapper,
303 try_encode_udaf: try_encode_udaf_fn_wrapper,
304 try_decode_udwf: try_decode_udwf_fn_wrapper,
305 try_encode_udwf: try_encode_udwf_fn_wrapper,
306 task_ctx_provider,
307
308 clone: clone_fn_wrapper,
309 release: release_fn_wrapper,
310 version: crate::version,
311 private_data: Box::into_raw(private_data) as *mut c_void,
312 library_marker_id: crate::get_library_marker_id,
313 }
314 }
315}
316
317#[derive(Debug)]
322pub struct ForeignPhysicalExtensionCodec(pub FFI_PhysicalExtensionCodec);
323
324unsafe impl Send for ForeignPhysicalExtensionCodec {}
325unsafe impl Sync for ForeignPhysicalExtensionCodec {}
326
327impl From<&FFI_PhysicalExtensionCodec> for Arc<dyn PhysicalExtensionCodec> {
328 fn from(codec: &FFI_PhysicalExtensionCodec) -> Self {
329 if (codec.library_marker_id)() == crate::get_library_marker_id() {
330 Arc::clone(codec.inner())
331 } else {
332 Arc::new(ForeignPhysicalExtensionCodec(codec.clone()))
333 }
334 }
335}
336
337impl Clone for FFI_PhysicalExtensionCodec {
338 fn clone(&self) -> Self {
339 unsafe { (self.clone)(self) }
340 }
341}
342
343impl PhysicalExtensionCodec for ForeignPhysicalExtensionCodec {
344 fn try_decode(
345 &self,
346 buf: &[u8],
347 inputs: &[Arc<dyn ExecutionPlan>],
348 _ctx: &TaskContext,
349 _proto_converter: &dyn PhysicalProtoConverterExtension,
350 ) -> Result<Arc<dyn ExecutionPlan>> {
351 let inputs = inputs
352 .iter()
353 .map(|plan| FFI_ExecutionPlan::new(Arc::clone(plan), None))
354 .collect();
355
356 let plan =
357 df_result!(unsafe { (self.0.try_decode)(&self.0, buf.into(), inputs) })?;
358 let plan: Arc<dyn ExecutionPlan> = (&plan).try_into()?;
359
360 Ok(plan)
361 }
362
363 fn try_encode(
364 &self,
365 node: Arc<dyn ExecutionPlan>,
366 buf: &mut Vec<u8>,
367 _proto_converter: &dyn PhysicalProtoConverterExtension,
368 ) -> Result<()> {
369 let plan = FFI_ExecutionPlan::new(node, None);
370 let bytes = df_result!(unsafe { (self.0.try_encode)(&self.0, plan) })?;
371
372 buf.extend(bytes);
373 Ok(())
374 }
375
376 fn try_decode_udf(&self, name: &str, buf: &[u8]) -> Result<Arc<ScalarUDF>> {
377 let udf = unsafe {
378 df_result!((self.0.try_decode_udf)(&self.0, name.into(), buf.into()))
379 }?;
380 let udf: Arc<dyn ScalarUDFImpl> = (&udf).into();
381
382 Ok(Arc::new(ScalarUDF::new_from_shared_impl(udf)))
383 }
384
385 fn try_encode_udf(&self, node: &ScalarUDF, buf: &mut Vec<u8>) -> Result<()> {
386 let node = FFI_ScalarUDF::from(Arc::new(node.clone()));
387 let bytes = df_result!(unsafe { (self.0.try_encode_udf)(&self.0, node) })?;
388
389 buf.extend(bytes);
390
391 Ok(())
392 }
393
394 fn try_decode_udaf(&self, name: &str, buf: &[u8]) -> Result<Arc<AggregateUDF>> {
395 let udaf = unsafe {
396 df_result!((self.0.try_decode_udaf)(&self.0, name.into(), buf.into()))
397 }?;
398 let udaf: Arc<dyn AggregateUDFImpl> = (&udaf).into();
399
400 Ok(Arc::new(AggregateUDF::new_from_shared_impl(udaf)))
401 }
402
403 fn try_encode_udaf(&self, node: &AggregateUDF, buf: &mut Vec<u8>) -> Result<()> {
404 let node = Arc::new(node.clone());
405 let node = FFI_AggregateUDF::from(node);
406 let bytes = df_result!(unsafe { (self.0.try_encode_udaf)(&self.0, node) })?;
407
408 buf.extend(bytes);
409
410 Ok(())
411 }
412
413 fn try_decode_udwf(&self, name: &str, buf: &[u8]) -> Result<Arc<WindowUDF>> {
414 let udwf = unsafe {
415 df_result!((self.0.try_decode_udwf)(&self.0, name.into(), buf.into()))
416 }?;
417 let udwf: Arc<dyn WindowUDFImpl> = (&udwf).into();
418
419 Ok(Arc::new(WindowUDF::new_from_shared_impl(udwf)))
420 }
421
422 fn try_encode_udwf(&self, node: &WindowUDF, buf: &mut Vec<u8>) -> Result<()> {
423 let node = Arc::new(node.clone());
424 let node = FFI_WindowUDF::from(node);
425 let bytes = df_result!(unsafe { (self.0.try_encode_udwf)(&self.0, node) })?;
426
427 buf.extend(bytes);
428
429 Ok(())
430 }
431}
432
433#[cfg(test)]
434pub(crate) mod tests {
435 use std::sync::Arc;
436
437 use arrow_schema::{DataType, Field, Schema};
438 use datafusion_common::{Result, exec_err};
439 use datafusion_execution::TaskContext;
440 use datafusion_expr::ptr_eq::arc_ptr_eq;
441 use datafusion_expr::{AggregateUDF, ScalarUDF, WindowUDF, WindowUDFImpl};
442 use datafusion_functions::math::abs::AbsFunc;
443 use datafusion_functions_aggregate::sum::Sum;
444 use datafusion_functions_window::rank::{Rank, RankType};
445 use datafusion_physical_plan::ExecutionPlan;
446 use datafusion_proto::physical_plan::{
447 DefaultPhysicalProtoConverter, PhysicalExtensionCodec,
448 PhysicalProtoConverterExtension,
449 };
450
451 use crate::execution_plan::tests::EmptyExec;
452 use crate::proto::physical_extension_codec::FFI_PhysicalExtensionCodec;
453
454 #[derive(Debug)]
455 pub(crate) struct TestExtensionCodec;
456
457 impl TestExtensionCodec {
458 pub(crate) const MAGIC_NUMBER: u8 = 127;
459 pub(crate) const EMPTY_EXEC_SERIALIZED: u8 = 1;
460 pub(crate) const ABS_FUNC_SERIALIZED: u8 = 2;
461 pub(crate) const SUM_UDAF_SERIALIZED: u8 = 3;
462 pub(crate) const RANK_UDWF_SERIALIZED: u8 = 4;
463 pub(crate) const MEMTABLE_SERIALIZED: u8 = 5;
464 }
465
466 impl PhysicalExtensionCodec for TestExtensionCodec {
467 fn try_decode(
468 &self,
469 buf: &[u8],
470 _inputs: &[Arc<dyn ExecutionPlan>],
471 _ctx: &TaskContext,
472 _proto_converter: &dyn PhysicalProtoConverterExtension,
473 ) -> Result<Arc<dyn ExecutionPlan>> {
474 if buf[0] != Self::MAGIC_NUMBER {
475 return exec_err!(
476 "TestExtensionCodec input buffer does not start with magic number"
477 );
478 }
479
480 if buf.len() != 2 || buf[1] != Self::EMPTY_EXEC_SERIALIZED {
481 return exec_err!("TestExtensionCodec unable to decode execution plan");
482 }
483
484 Ok(create_test_exec())
485 }
486
487 fn try_encode(
488 &self,
489 node: Arc<dyn ExecutionPlan>,
490 buf: &mut Vec<u8>,
491 _proto_converter: &dyn PhysicalProtoConverterExtension,
492 ) -> Result<()> {
493 buf.push(Self::MAGIC_NUMBER);
494
495 let Some(_) = node.downcast_ref::<EmptyExec>() else {
496 return exec_err!("TestExtensionCodec only expects EmptyExec");
497 };
498
499 buf.push(Self::EMPTY_EXEC_SERIALIZED);
500
501 Ok(())
502 }
503
504 fn try_decode_udf(&self, _name: &str, buf: &[u8]) -> Result<Arc<ScalarUDF>> {
505 if buf[0] != Self::MAGIC_NUMBER {
506 return exec_err!(
507 "TestExtensionCodec input buffer does not start with magic number"
508 );
509 }
510
511 if buf.len() != 2 || buf[1] != Self::ABS_FUNC_SERIALIZED {
512 return exec_err!("TestExtensionCodec unable to decode udf");
513 }
514
515 Ok(Arc::new(ScalarUDF::from(AbsFunc::new())))
516 }
517
518 fn try_encode_udf(&self, node: &ScalarUDF, buf: &mut Vec<u8>) -> Result<()> {
519 buf.push(Self::MAGIC_NUMBER);
520
521 let udf = node.inner();
522 if !udf.is::<AbsFunc>() {
523 return exec_err!("TestExtensionCodec only expects Abs UDF");
524 };
525
526 buf.push(Self::ABS_FUNC_SERIALIZED);
527
528 Ok(())
529 }
530
531 fn try_decode_udaf(&self, _name: &str, buf: &[u8]) -> Result<Arc<AggregateUDF>> {
532 if buf[0] != Self::MAGIC_NUMBER {
533 return exec_err!(
534 "TestExtensionCodec input buffer does not start with magic number"
535 );
536 }
537
538 if buf.len() != 2 || buf[1] != Self::SUM_UDAF_SERIALIZED {
539 return exec_err!("TestExtensionCodec unable to decode udaf");
540 }
541
542 Ok(Arc::new(AggregateUDF::from(Sum::new())))
543 }
544
545 fn try_encode_udaf(&self, node: &AggregateUDF, buf: &mut Vec<u8>) -> Result<()> {
546 buf.push(Self::MAGIC_NUMBER);
547
548 let udf = node.inner();
549 let Some(_udf) = udf.downcast_ref::<Sum>() else {
550 return exec_err!("TestExtensionCodec only expects Sum UDAF");
551 };
552
553 buf.push(Self::SUM_UDAF_SERIALIZED);
554
555 Ok(())
556 }
557
558 fn try_decode_udwf(&self, _name: &str, buf: &[u8]) -> Result<Arc<WindowUDF>> {
559 if buf[0] != Self::MAGIC_NUMBER {
560 return exec_err!(
561 "TestExtensionCodec input buffer does not start with magic number"
562 );
563 }
564
565 if buf.len() != 2 || buf[1] != Self::RANK_UDWF_SERIALIZED {
566 return exec_err!("TestExtensionCodec unable to decode udwf");
567 }
568
569 Ok(Arc::new(WindowUDF::from(Rank::new(
570 "my_rank".to_owned(),
571 RankType::Basic,
572 ))))
573 }
574
575 fn try_encode_udwf(&self, node: &WindowUDF, buf: &mut Vec<u8>) -> Result<()> {
576 buf.push(Self::MAGIC_NUMBER);
577
578 let udf = node.inner();
579 let Some(udf) = udf.downcast_ref::<Rank>() else {
580 return exec_err!("TestExtensionCodec only expects Rank UDWF");
581 };
582
583 if udf.name() != "my_rank" {
584 return exec_err!("TestExtensionCodec only expects my_rank UDWF name");
585 }
586
587 buf.push(Self::RANK_UDWF_SERIALIZED);
588
589 Ok(())
590 }
591 }
592
593 fn create_test_exec() -> Arc<dyn ExecutionPlan> {
594 let schema =
595 Arc::new(Schema::new(vec![Field::new("a", DataType::Float32, false)]));
596 Arc::new(EmptyExec::new(schema)) as Arc<dyn ExecutionPlan>
597 }
598
599 #[test]
600 fn roundtrip_ffi_physical_extension_codec_exec_plan() -> Result<()> {
601 let codec = Arc::new(TestExtensionCodec {});
602 let (ctx, task_ctx_provider) = crate::util::tests::test_session_and_ctx();
603
604 let mut ffi_codec =
605 FFI_PhysicalExtensionCodec::new(codec, None, task_ctx_provider);
606 ffi_codec.library_marker_id = crate::mock_foreign_marker_id;
607 let foreign_codec: Arc<dyn PhysicalExtensionCodec> = (&ffi_codec).into();
608
609 let exec = create_test_exec();
610 let input_execs = [create_test_exec()];
611 let mut bytes = Vec::new();
612 foreign_codec.try_encode(
613 Arc::clone(&exec),
614 &mut bytes,
615 &DefaultPhysicalProtoConverter {},
616 )?;
617
618 let returned_exec = foreign_codec.try_decode(
619 &bytes,
620 &input_execs,
621 ctx.task_ctx().as_ref(),
622 &DefaultPhysicalProtoConverter {},
623 )?;
624
625 assert!(returned_exec.is::<EmptyExec>());
626
627 Ok(())
628 }
629
630 #[test]
631 fn roundtrip_ffi_physical_extension_codec_udf() -> Result<()> {
632 let codec = Arc::new(TestExtensionCodec {});
633 let (_ctx, task_ctx_provider) = crate::util::tests::test_session_and_ctx();
634
635 let mut ffi_codec =
636 FFI_PhysicalExtensionCodec::new(codec, None, task_ctx_provider);
637 ffi_codec.library_marker_id = crate::mock_foreign_marker_id;
638 let foreign_codec: Arc<dyn PhysicalExtensionCodec> = (&ffi_codec).into();
639
640 let udf = Arc::new(ScalarUDF::from(AbsFunc::new()));
641 let mut bytes = Vec::new();
642 foreign_codec.try_encode_udf(udf.as_ref(), &mut bytes)?;
643
644 let returned_udf = foreign_codec.try_decode_udf(udf.name(), &bytes)?;
645
646 assert!(returned_udf.inner().is::<AbsFunc>());
647
648 Ok(())
649 }
650
651 #[test]
652 fn roundtrip_ffi_physical_extension_codec_udaf() -> Result<()> {
653 let codec = Arc::new(TestExtensionCodec {});
654 let (_ctx, task_ctx_provider) = crate::util::tests::test_session_and_ctx();
655
656 let mut ffi_codec =
657 FFI_PhysicalExtensionCodec::new(codec, None, task_ctx_provider);
658 ffi_codec.library_marker_id = crate::mock_foreign_marker_id;
659 let foreign_codec: Arc<dyn PhysicalExtensionCodec> = (&ffi_codec).into();
660
661 let udf = Arc::new(AggregateUDF::from(Sum::new()));
662 let mut bytes = Vec::new();
663 foreign_codec.try_encode_udaf(udf.as_ref(), &mut bytes)?;
664
665 let returned_udf = foreign_codec.try_decode_udaf(udf.name(), &bytes)?;
666
667 assert!(returned_udf.inner().is::<Sum>());
668
669 Ok(())
670 }
671
672 #[test]
673 fn roundtrip_ffi_physical_extension_codec_udwf() -> Result<()> {
674 let codec = Arc::new(TestExtensionCodec {});
675 let (_ctx, task_ctx_provider) = crate::util::tests::test_session_and_ctx();
676
677 let mut ffi_codec =
678 FFI_PhysicalExtensionCodec::new(codec, None, task_ctx_provider);
679 ffi_codec.library_marker_id = crate::mock_foreign_marker_id;
680 let foreign_codec: Arc<dyn PhysicalExtensionCodec> = (&ffi_codec).into();
681
682 let udf = Arc::new(WindowUDF::from(Rank::new(
683 "my_rank".to_owned(),
684 RankType::Basic,
685 )));
686 let mut bytes = Vec::new();
687 foreign_codec.try_encode_udwf(udf.as_ref(), &mut bytes)?;
688
689 let returned_udf = foreign_codec.try_decode_udwf(udf.name(), &bytes)?;
690
691 assert!(returned_udf.inner().is::<Rank>());
692
693 Ok(())
694 }
695
696 #[test]
697 fn ffi_physical_extension_codec_local_bypass() {
698 let codec = Arc::new(TestExtensionCodec {}) as Arc<dyn PhysicalExtensionCodec>;
699 let (_ctx, task_ctx_provider) = crate::util::tests::test_session_and_ctx();
700
701 let mut ffi_codec =
702 FFI_PhysicalExtensionCodec::new(Arc::clone(&codec), None, task_ctx_provider);
703
704 let foreign_codec: Arc<dyn PhysicalExtensionCodec> = (&ffi_codec).into();
706 assert!(arc_ptr_eq(&foreign_codec, &codec));
707
708 ffi_codec.library_marker_id = crate::mock_foreign_marker_id;
710 let foreign_codec: Arc<dyn PhysicalExtensionCodec> = (&ffi_codec).into();
711 assert!(!arc_ptr_eq(&foreign_codec, &codec));
712 }
713}