1use libloading::{library_filename, Library, Symbol};
4
5use crate::{PdRoute, PdRouterContext, PdStr};
6
7#[derive(Debug)]
9pub struct Plugin<'a> {
10 name: String,
11 init: Option<Symbol<'a, unsafe extern "C" fn()>>,
13 fini: Option<Symbol<'a, unsafe extern "C" fn()>>,
15 route: Option<Symbol<'a, unsafe extern "C" fn(PdRouterContext, *mut PdRoute)>>,
17 rustc_version: Option<Symbol<'a, unsafe extern "C" fn(*mut PdStr)>>,
19 pg_query_version: Option<Symbol<'a, unsafe extern "C" fn(*mut PdStr)>>,
21 plugin_version: Option<Symbol<'a, unsafe extern "C" fn(*mut PdStr)>>,
23}
24
25impl<'a> Plugin<'a> {
26 pub fn library(name: &str) -> Result<Library, libloading::Error> {
28 let name = library_filename(name);
29 unsafe { Library::new(name) }
30 }
31
32 pub fn load(name: &str, library: &'a Library) -> Self {
34 let init = unsafe { library.get(b"pgdog_init\0") }.ok();
35 let fini = unsafe { library.get(b"pgdog_fini\0") }.ok();
36 let route = unsafe { library.get(b"pgdog_route\0") }.ok();
37 let rustc_version = unsafe { library.get(b"pgdog_rustc_version\0") }.ok();
38 let pg_query_version = unsafe { library.get(b"pgdog_pg_query_version\0") }.ok();
39 let plugin_version = unsafe { library.get(b"pgdog_plugin_version\0") }.ok();
40
41 Self {
42 name: name.to_owned(),
43 init,
44 fini,
45 route,
46 rustc_version,
47 pg_query_version,
48 plugin_version,
49 }
50 }
51
52 pub fn init(&self) -> bool {
54 if let Some(init) = &self.init {
55 unsafe {
56 init();
57 }
58 true
59 } else {
60 false
61 }
62 }
63
64 pub fn fini(&self) {
65 if let Some(ref fini) = &self.fini {
66 unsafe { fini() }
67 }
68 }
69
70 pub fn route(&self, context: PdRouterContext) -> Option<PdRoute> {
71 if let Some(ref route) = &self.route {
72 let mut output = PdRoute::default();
73 unsafe {
74 route(context, &mut output as *mut PdRoute);
75 }
76 Some(output)
77 } else {
78 None
79 }
80 }
81
82 pub fn name(&self) -> &str {
84 &self.name
85 }
86
87 pub fn rustc_version(&self) -> Option<PdStr> {
89 let mut output = PdStr::default();
90 self.rustc_version.as_ref().map(|rustc_version| unsafe {
91 rustc_version(&mut output);
92 output
93 })
94 }
95
96 pub fn version(&self) -> Option<PdStr> {
98 let mut output = PdStr::default();
99 self.plugin_version.as_ref().map(|func| unsafe {
100 func(&mut output as *mut PdStr);
101 output
102 })
103 }
104
105 pub fn pg_query_version(&self) -> Option<PdStr> {
106 let mut output = PdStr::default();
107
108 self.pg_query_version.as_ref().map(|func| unsafe {
109 func(&mut output as *mut PdStr);
110 output
111 })
112 }
113}