flarrow_url_default/
lib.rs

1use std::path::PathBuf;
2
3use flarrow_builtins::prelude::{Builtin, new_builtin};
4use flarrow_url::prelude::*;
5use libloading::Library;
6
7#[doc(hidden)]
8#[unsafe(no_mangle)]
9pub static FLARROW_URL_PLUGIN: DynamicallyLinkedUrlPluginInstance = || UrlDefaultPlugin::new();
10
11static DEFAULT_TOKIO_RUNTIME: std::sync::LazyLock<tokio::runtime::Runtime> =
12    std::sync::LazyLock::new(|| {
13        tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime")
14    });
15
16fn default_runtime<T: Send + 'static>(
17    task: impl Future<Output = T> + Send + 'static,
18) -> tokio::task::JoinHandle<T> {
19    match tokio::runtime::Handle::try_current() {
20        Ok(handle) => handle.spawn(task),
21        Err(_) => DEFAULT_TOKIO_RUNTIME.spawn(task),
22    }
23}
24
25pub struct UrlDefaultPlugin {}
26
27impl UrlPlugin for UrlDefaultPlugin {
28    fn new() -> tokio::task::JoinHandle<Result<Box<dyn UrlPlugin>>>
29    where
30        Self: Sized,
31    {
32        default_runtime(async move { Ok(Box::new(UrlDefaultPlugin {}) as Box<dyn UrlPlugin>) })
33    }
34
35    fn load(
36        &self,
37        url: url::Url,
38        inputs: Inputs,
39        outputs: Outputs,
40        configuration: serde_yml::Value,
41    ) -> tokio::task::JoinHandle<Result<RuntimeNode>> {
42        default_runtime(async move {
43            match url.scheme() {
44                "builtin" => {
45                    let builtin_name = url.path().trim_start_matches('/').to_string();
46
47                    let builtin = Builtin::from_string(builtin_name)
48                        .wrap_err("Failed to parse builtin name")?;
49
50                    Ok(RuntimeNode::StaticallyLinked(
51                        new_builtin(builtin, inputs, outputs, configuration)
52                            .await
53                            .wrap_err("Failed to create builtin node")?,
54                    ))
55                }
56                "file" => {
57                    let path = PathBuf::from(url.path());
58
59                    match path.extension() {
60                        Some(ext) => {
61                            if ext == std::env::consts::DLL_EXTENSION {
62                                let library = unsafe { Library::new(path)? };
63                                let constructor = unsafe {
64                                    library
65                                        .get::<*mut DynamicallyLinkedNodeInstance>(b"FLARROW_NODE")?
66                                        .read()
67                                };
68
69                                Ok(RuntimeNode::DynamicallyLinked(DynamicallyLinkedNode {
70                                    _library: library,
71                                    handle: (constructor)(inputs, outputs, configuration)
72                                        .await
73                                        .wrap_err("Failed to await for dynamically linked node")?
74                                        .wrap_err("Failed to create dynamically linked node")?,
75                                }))
76                            } else {
77                                Err(eyre::eyre!("Unsupported file extension!"))
78                            }
79                        }
80                        None => Err(eyre::eyre!("No file extension found")),
81                    }
82                }
83                _ => Err(eyre::eyre!("Unsupported scheme")),
84            }
85        })
86    }
87}