godwit_daemon/core/
mod.rs1use crate::errors::{BackendError, TraceError};
2use glob;
3use libloading::Library;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::ffi::OsStr;
7use std::path::Path;
8use std::rc::Rc;
9
10#[macro_export]
11macro_rules! export_backend {
12 ($register:expr) => {
13 #[doc(hidden)]
14 #[no_mangle]
15 pub static backend_declaration: $crate::core::BackendDeclaration =
16 $crate::core::BackendDeclaration {
17 rustc_version: $crate::RUSTC_VERSION,
18 core_version: $crate::CORE_VERSION,
19 register: $register,
20 };
21 };
22}
23
24#[derive(Debug, Serialize, Deserialize, Copy, PartialEq, Clone)]
25pub enum Ops {
26 Trace,
27}
28
29pub trait Backend {
30 fn trace(&self, args: BackendArgs) -> Result<(), TraceError>;
31 fn help(&self) -> Option<&str> {
32 None
33 }
34}
35
36pub trait Registrar {
37 fn register_backend(&mut self, name: &str, backend: Box<dyn Backend>);
38}
39
40pub struct BackendDeclaration {
41 pub rustc_version: &'static str,
42 pub core_version: &'static str,
43 pub register: unsafe extern "C" fn(&mut dyn Registrar),
44}
45
46pub struct BackendArgs {
47 pub refresh: bool,
48}
49
50pub struct BackendProxy {
51 backend: Box<dyn Backend>,
52 _lib: Rc<Library>,
53}
54
55impl Backend for BackendProxy {
56 fn trace(&self, args: BackendArgs) -> Result<(), TraceError> {
57 self.backend.trace(args)
58 }
59
60 fn help(&self) -> Option<&str> {
61 self.backend.help()
62 }
63}
64
65struct BackendRegistrar {
66 backends: HashMap<String, BackendProxy>,
67 lib: Rc<Library>,
68}
69
70impl BackendRegistrar {
71 fn new(lib: Rc<Library>) -> BackendRegistrar {
72 BackendRegistrar {
73 backends: HashMap::default(),
74 lib,
75 }
76 }
77}
78
79impl Registrar for BackendRegistrar {
80 fn register_backend(&mut self, name: &str, backend: Box<dyn Backend>) {
81 let proxy = BackendProxy {
82 backend,
83 _lib: Rc::clone(&self.lib),
84 };
85 self.backends.insert(name.to_string().to_lowercase(), proxy);
86 }
87}
88
89pub struct ExternalBackends {
90 pub backends: HashMap<String, BackendProxy>,
91 libraries: Vec<Rc<Library>>,
92}
93
94impl ExternalBackends {
95 pub fn new() -> ExternalBackends {
96 ExternalBackends {
97 backends: Default::default(),
98 libraries: Default::default(),
99 }
100 }
101
102 pub fn from_dir<P>(dir_path: P) -> Result<ExternalBackends, BackendError>
103 where
104 P: AsRef<Path>,
105 {
106 let mut ext_backends = ExternalBackends::new();
107
108 for lib_so in glob::glob(&format!("{}/*.so", dir_path.as_ref().display())).unwrap() {
109 unsafe {
110 ext_backends.load(lib_so?)?;
111 }
112 }
113 Ok(ext_backends)
114 }
115
116 pub unsafe fn load<P: AsRef<OsStr>>(&mut self, lib_path: P) -> Result<(), BackendError> {
117 let library = Rc::new(Library::new(lib_path)?);
118
119 let decl = library
120 .get::<*mut BackendDeclaration>(b"backend_declaration\0")?
121 .read();
122
123 if decl.rustc_version != crate::RUSTC_VERSION || decl.core_version != crate::CORE_VERSION {
124 return Err(BackendError::VersionMismatch);
125 }
126
127 let mut registrar = BackendRegistrar::new(Rc::clone(&library));
128
129 (decl.register)(&mut registrar);
130
131 self.backends.extend(registrar.backends);
132 self.libraries.push(library);
133
134 Ok(())
135 }
136
137 pub fn trace(&self, backend: &str, args: BackendArgs) -> Result<(), TraceError> {
138 self.backends
139 .get(backend)
140 .ok_or_else(|| BackendError::NotFound {
141 backend_str: backend.to_string(),
142 })?
143 .trace(args)
144 .into()
145 }
146}