1 extern crate libc; 2 3 #[macro_use] 4 extern crate lazy_static; 5 6 pub mod dynamic_library; 7 8 /// Error that can happen while loading the shared library. 9 #[derive(Debug, Clone)] 10 pub enum LoadingError { 11 /// 12 LibraryNotFound { 13 descr: String, 14 }, 15 16 /// One of the symbols could not be found in the library. 17 SymbolNotFound { 18 /// The symbol. 19 symbol: &'static str, 20 } 21 } 22 23 #[macro_export] 24 macro_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 /// Symbols loaded from a shared library. 92 #[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 /// Tries to open the dynamic library. 102 #[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 /// This function is used by the regular functions. 136 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 /// Try loading the static symbols linked to this library. 144 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 } 176