flarrow_url_default/
lib.rs1use 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}