1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use libloading::{Error, Library, Symbol};
use std::collections::HashMap;
use std::path::Path;
use std::rc::Rc;
use crate::code::{CallProtocol, CallableRef, CodeObject};
use crate::error::*;
use crate::module::{Module, Slots};
use crate::var::Variable;
use crate::vm::Vm;
pub const EXTERN_LOVM2_INITIALIZER: &str = "lovm2_module_initialize";
pub type ExternFunction = unsafe extern "C" fn(&mut Vm) -> Lovm2Result<()>;
pub type ExternInitializer = extern "C" fn(lib: Rc<Library>, &mut HashMap<Variable, CallableRef>);
fn load_slots(_name: &str, lib: Library) -> Lovm2Result<Slots> {
unsafe {
let lib = Rc::new(lib);
let lookup: Result<Symbol<ExternInitializer>, Error> =
lib.get(EXTERN_LOVM2_INITIALIZER.as_bytes());
match lookup {
Ok(initializer) => {
let mut slots = HashMap::new();
initializer(lib.clone(), &mut slots);
Ok(Slots::from(slots))
}
Err(_) => Err(Lovm2ErrorTy::Basic.into()),
}
}
}
pub fn load_library_from_file<T>(path: T) -> Lovm2Result<Library>
where
T: AsRef<Path>,
{
#[cfg(target_os = "linux")]
let library: Result<Library, libloading::Error> = {
::libloading::os::unix::Library::open(Some(path.as_ref()), 0x2 | 0x1000).map(Library::from)
};
#[cfg(not(target_os = "linux"))]
let library = Library::new(path.as_ref());
library.or_else(err_from_string)
}
pub fn module_from_library<T>(path: T, lib: Library) -> Lovm2Result<Module>
where
T: AsRef<Path>,
{
let name = path.as_ref().file_stem().unwrap().to_str().unwrap();
let code_object = CodeObject {
name: name.to_string(),
loc: Some(path.as_ref().display().to_string()),
..CodeObject::default()
};
Ok(Module {
code_object: Rc::new(code_object),
slots: load_slots(name, lib)?,
})
}
pub struct SharedObjectSlot(
Rc<Library>,
#[cfg(unix)] ::libloading::os::unix::Symbol<ExternFunction>,
#[cfg(windows)] ::libloading::os::windows::Symbol<ExternFunction>,
);
impl SharedObjectSlot {
pub fn new<T>(lib: Rc<Library>, name: T) -> Lovm2Result<Self>
where
T: AsRef<str>,
{
let name = name.as_ref();
unsafe {
let lookup: Result<Symbol<ExternFunction>, Error> = lib.get(name.as_bytes());
match lookup {
Ok(symbol) => Ok(Self(lib.clone(), symbol.into_raw())),
Err(_) => err_symbol_not_found(name),
}
}
}
}
impl CallProtocol for SharedObjectSlot {
fn run(&self, vm: &mut Vm) -> Lovm2Result<()> {
unsafe { self.1(vm) }
}
}
impl std::fmt::Debug for SharedObjectSlot {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "<extern function>")
}
}