flarrow_file_ext/
file_ext_default.rs

1use crate::prelude::{thirdparty::libloading::Library, *};
2
3#[doc(hidden)]
4#[unsafe(no_mangle)]
5pub static FLARROW_FILE_EXT_PLUGIN: DynamicallyLinkedFileExtPluginInstance =
6    || DefaultFileExtPlugin::new();
7
8static DEFAULT_TOKIO_RUNTIME: std::sync::LazyLock<tokio::runtime::Runtime> =
9    std::sync::LazyLock::new(|| {
10        tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime")
11    });
12
13fn default_runtime<T: Send + 'static>(
14    task: impl Future<Output = T> + Send + 'static,
15) -> tokio::task::JoinHandle<T> {
16    match tokio::runtime::Handle::try_current() {
17        Ok(handle) => handle.spawn(task),
18        Err(_) => DEFAULT_TOKIO_RUNTIME.spawn(task),
19    }
20}
21
22pub struct DefaultFileExtPlugin {}
23
24impl FileExtPlugin for DefaultFileExtPlugin {
25    fn new() -> tokio::task::JoinHandle<Result<Box<dyn FileExtPlugin>>>
26    where
27        Self: Sized,
28    {
29        default_runtime(
30            async move { Ok(Box::new(DefaultFileExtPlugin {}) as Box<dyn FileExtPlugin>) },
31        )
32    }
33
34    fn target(&self) -> Vec<String> {
35        vec!["so".to_string(), "dylib".to_string(), "dll".to_string()]
36    }
37
38    fn load(
39        &self,
40        path: std::path::PathBuf,
41
42        inputs: Inputs,
43        outputs: Outputs,
44        queries: Queries,
45        queryables: Queryables,
46        configuration: serde_yml::Value,
47    ) -> tokio::task::JoinHandle<Result<flarrow_runtime_core::prelude::RuntimeNode>> {
48        default_runtime(async move {
49            match path.extension() {
50                Some(ext) => {
51                    if ext == std::env::consts::DLL_EXTENSION {
52                        let path_buf = path.clone();
53                        let (library, constructor) = tokio::task::spawn_blocking(move || {
54                            let library = unsafe {
55                                Library::new(path_buf.clone())
56                                    .wrap_err(format!("Failed to load path {:?}", path_buf))?
57                            };
58
59                            let constructor = unsafe {
60                                library
61                                    .get::<*mut DynamicallyLinkedNodeInstance>(b"FLARROW_NODE")
62                                    .wrap_err(format!(
63                                        "Failed to load symbol 'FLARROW_NODE' from dylib {:?}",
64                                        path_buf
65                                    ))?
66                                    .read()
67                            };
68
69                            Ok::<_, eyre::Report>((library, constructor))
70                        })
71                        .await??;
72
73                        Ok(RuntimeNode::DynamicallyLinked(DynamicallyLinkedNode {
74                            _library: library,
75                            handle: (constructor)(
76                                inputs,
77                                outputs,
78                                queries,
79                                queryables,
80                                configuration,
81                            )
82                            .await?
83                            .wrap_err(format!(
84                                "Failed to create dynamically linked node from dylib {:?}",
85                                path,
86                            ))?,
87                        }))
88                    } else {
89                        Err(eyre::eyre!(
90                            "Unsupported file extension '{:?}'. On this platform it must be '{}'",
91                            ext,
92                            std::env::consts::DLL_EXTENSION
93                        ))
94                    }
95                }
96                None => Err(eyre::eyre!("No file extension found for path {:?}", path)),
97            }
98        })
99    }
100}