1extern crate libc;
2
3#[macro_use]
4extern crate lazy_static;
5
6pub mod dynamic_library;
7
8#[derive(Debug, Clone)]
10pub enum LoadingError {
11 LibraryNotFound {
13 descr: String,
14 },
15
16 SymbolNotFound {
18 symbol: &'static str,
20 }
21}
22
23#[macro_export]
24macro_rules! shared_library {
25 ($struct_name:ident, pub $($rest:tt)+) => {
26 shared_library!(__impl $struct_name [] [] [] pub $($rest)+);
27 };
28
29 ($struct_name:ident, fn $($rest:tt)+) => {
30 shared_library!(__impl $struct_name [] [] [] fn $($rest)+);
31 };
32
33 ($struct_name:ident, static $($rest:tt)+) => {
34 shared_library!(__impl $struct_name [] [] [] static $($rest)+);
35 };
36
37 ($struct_name:ident, $def_path:expr, $($rest:tt)+) => {
38 shared_library!(__impl $struct_name [] [$def_path] [] $($rest)+);
39 };
40
41 (__impl $struct_name:ident
42 [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*]
43 , $($rest:tt)*
44 ) => {
45 shared_library!(__impl $struct_name [$($p1)*] [$($p2)*] [$($p3)*] $($rest)*);
46 };
47
48 (__impl $struct_name:ident
49 [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*]
50 pub $($rest:tt)*
51 ) => {
52 shared_library!(__impl $struct_name
53 [$($p1)*] [$($p2)*] [$($p3)* pub] $($rest)*);
54 };
55
56 (__impl $struct_name:ident
57 [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*]
58 fn $name:ident($($p:ident:$ty:ty),*) -> $ret:ty, $($rest:tt)*
59 ) => {
60 shared_library!(__impl $struct_name
61 [$($p1)*, $name:unsafe extern fn($($p:$ty),*) -> $ret]
62 [$($p2)*]
63 [$($p3)*
64 unsafe fn $name($($p:$ty),*) -> $ret {
65 #![allow(dead_code)]
66 ($struct_name::get_static_ref().$name)($($p),*)
67 }
68 ] $($rest)*);
69 };
70
71 (__impl $struct_name:ident
72 [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*]
73 static $name:ident:$ty:ty, $($rest:tt)*
74 ) => {
75 shared_library!(__impl $struct_name
76 [$($p1)*, $name: $ty]
77 [$($p2)*]
78 [$($p3)*] $($rest)*);
79 };
80
81 (__impl $struct_name:ident
82 [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*]
83 fn $name:ident($($p:ident:$ty:ty),*), $($rest:tt)*
84 ) => {
85 shared_library!(__impl $struct_name
86 [$($p1)*] [$($p2)*] [$($p3)*]
87 fn $name($($p:$ty),*) -> (), $($rest)*);
88 };
89
90 (__impl $struct_name:ident [$(,$mem_n:ident:$mem_t:ty)+] [$($p2:tt)*] [$($p3:tt)*]) => {
91 #[allow(non_snake_case)]
93 pub struct $struct_name {
94 _library_guard: $crate::dynamic_library::DynamicLibrary,
95 $(
96 pub $mem_n: $mem_t,
97 )+
98 }
99
100 impl $struct_name {
101 #[allow(non_snake_case)]
103 pub fn open(path: &::std::path::Path) -> Result<$struct_name, $crate::LoadingError> {
104 use std::mem;
105
106 let dylib = match $crate::dynamic_library::DynamicLibrary::open(Some(path)) {
107 Ok(l) => l,
108 Err(reason) => return Err($crate::LoadingError::LibraryNotFound { descr: reason })
109 };
110
111 $(
112 let $mem_n: *mut () = match unsafe { dylib.symbol(stringify!($mem_n)) } {
113 Ok(s) => s,
114 Err(_) => return Err($crate::LoadingError::SymbolNotFound { symbol: stringify!($mem_n) }),
115 };
116 )+
117
118 Ok($struct_name {
119 _library_guard: dylib,
120 $(
121 $mem_n: unsafe { mem::transmute($mem_n) },
122 )+
123 })
124 }
125 }
126
127 shared_library!(__write_static_fns $struct_name [] [$($p2)*] [$($p3)*]);
128 };
129
130 (__write_static_fns $struct_name:ident [$($p1:tt)*] [] [$($p3:tt)*]) => {
131 };
132
133 (__write_static_fns $struct_name:ident [$($p1:tt)*] [$defpath:expr] [$($standalones:item)+]) => {
134 impl $struct_name {
135 fn get_static_ref() -> &'static $struct_name {
137 $struct_name::try_loading().ok()
138 .expect(concat!("Could not open dynamic \
139 library `", stringify!($struct_name),
140 "`"))
141 }
142
143 pub fn try_loading() -> Result<&'static $struct_name, $crate::LoadingError> {
145 use std::sync::{Mutex, Once, ONCE_INIT};
146 use std::mem;
147
148 unsafe {
149 static mut DATA: *const Mutex<Option<$struct_name>> = 0 as *const _;
150
151 static mut INIT: Once = ONCE_INIT;
152 INIT.call_once(|| {
153 let data = Box::new(Mutex::new(None));
154 DATA = &*data;
155 mem::forget(data);
156 });
157
158 let data: &Mutex<Option<$struct_name>> = &*DATA;
159 let mut data = data.lock().unwrap();
160
161 if let Some(ref data) = *data {
162 return Ok(mem::transmute(data));
163 }
164
165 let path = ::std::path::Path::new($defpath);
166 let result = try!($struct_name::open(path));
167 *data = Some(result);
168 Ok(mem::transmute(data.as_ref().unwrap()))
169 }
170 }
171 }
172
173 $($standalones)+
174 };
175}