| extern crate libc; |
| |
| #[macro_use] |
| extern crate lazy_static; |
| |
| pub mod dynamic_library; |
| |
| /// Error that can happen while loading the shared library. |
| #[derive(Debug, Clone)] |
| pub enum LoadingError { |
| /// |
| LibraryNotFound { |
| descr: String, |
| }, |
| |
| /// One of the symbols could not be found in the library. |
| SymbolNotFound { |
| /// The symbol. |
| symbol: &'static str, |
| } |
| } |
| |
| #[macro_export] |
| macro_rules! shared_library { |
| ($struct_name:ident, pub $($rest:tt)+) => { |
| shared_library!(__impl $struct_name [] [] [] pub $($rest)+); |
| }; |
| |
| ($struct_name:ident, fn $($rest:tt)+) => { |
| shared_library!(__impl $struct_name [] [] [] fn $($rest)+); |
| }; |
| |
| ($struct_name:ident, static $($rest:tt)+) => { |
| shared_library!(__impl $struct_name [] [] [] static $($rest)+); |
| }; |
| |
| ($struct_name:ident, $def_path:expr, $($rest:tt)+) => { |
| shared_library!(__impl $struct_name [] [$def_path] [] $($rest)+); |
| }; |
| |
| (__impl $struct_name:ident |
| [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*] |
| , $($rest:tt)* |
| ) => { |
| shared_library!(__impl $struct_name [$($p1)*] [$($p2)*] [$($p3)*] $($rest)*); |
| }; |
| |
| (__impl $struct_name:ident |
| [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*] |
| pub $($rest:tt)* |
| ) => { |
| shared_library!(__impl $struct_name |
| [$($p1)*] [$($p2)*] [$($p3)* pub] $($rest)*); |
| }; |
| |
| (__impl $struct_name:ident |
| [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*] |
| fn $name:ident($($p:ident:$ty:ty),*) -> $ret:ty, $($rest:tt)* |
| ) => { |
| shared_library!(__impl $struct_name |
| [$($p1)*, $name:unsafe extern fn($($p:$ty),*) -> $ret] |
| [$($p2)*] |
| [$($p3)* |
| unsafe fn $name($($p:$ty),*) -> $ret { |
| #![allow(dead_code)] |
| ($struct_name::get_static_ref().$name)($($p),*) |
| } |
| ] $($rest)*); |
| }; |
| |
| (__impl $struct_name:ident |
| [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*] |
| static $name:ident:$ty:ty, $($rest:tt)* |
| ) => { |
| shared_library!(__impl $struct_name |
| [$($p1)*, $name: $ty] |
| [$($p2)*] |
| [$($p3)*] $($rest)*); |
| }; |
| |
| (__impl $struct_name:ident |
| [$($p1:tt)*] [$($p2:tt)*] [$($p3:tt)*] |
| fn $name:ident($($p:ident:$ty:ty),*), $($rest:tt)* |
| ) => { |
| shared_library!(__impl $struct_name |
| [$($p1)*] [$($p2)*] [$($p3)*] |
| fn $name($($p:$ty),*) -> (), $($rest)*); |
| }; |
| |
| (__impl $struct_name:ident [$(,$mem_n:ident:$mem_t:ty)+] [$($p2:tt)*] [$($p3:tt)*]) => { |
| /// Symbols loaded from a shared library. |
| #[allow(non_snake_case)] |
| pub struct $struct_name { |
| _library_guard: $crate::dynamic_library::DynamicLibrary, |
| $( |
| pub $mem_n: $mem_t, |
| )+ |
| } |
| |
| impl $struct_name { |
| /// Tries to open the dynamic library. |
| #[allow(non_snake_case)] |
| pub fn open(path: &::std::path::Path) -> Result<$struct_name, $crate::LoadingError> { |
| use std::mem; |
| |
| let dylib = match $crate::dynamic_library::DynamicLibrary::open(Some(path)) { |
| Ok(l) => l, |
| Err(reason) => return Err($crate::LoadingError::LibraryNotFound { descr: reason }) |
| }; |
| |
| $( |
| let $mem_n: *mut () = match unsafe { dylib.symbol(stringify!($mem_n)) } { |
| Ok(s) => s, |
| Err(_) => return Err($crate::LoadingError::SymbolNotFound { symbol: stringify!($mem_n) }), |
| }; |
| )+ |
| |
| Ok($struct_name { |
| _library_guard: dylib, |
| $( |
| $mem_n: unsafe { mem::transmute($mem_n) }, |
| )+ |
| }) |
| } |
| } |
| |
| shared_library!(__write_static_fns $struct_name [] [$($p2)*] [$($p3)*]); |
| }; |
| |
| (__write_static_fns $struct_name:ident [$($p1:tt)*] [] [$($p3:tt)*]) => { |
| }; |
| |
| (__write_static_fns $struct_name:ident [$($p1:tt)*] [$defpath:expr] [$($standalones:item)+]) => { |
| impl $struct_name { |
| /// This function is used by the regular functions. |
| fn get_static_ref() -> &'static $struct_name { |
| $struct_name::try_loading().ok() |
| .expect(concat!("Could not open dynamic \ |
| library `", stringify!($struct_name), |
| "`")) |
| } |
| |
| /// Try loading the static symbols linked to this library. |
| pub fn try_loading() -> Result<&'static $struct_name, $crate::LoadingError> { |
| use std::sync::{Mutex, Once, ONCE_INIT}; |
| use std::mem; |
| |
| unsafe { |
| static mut DATA: *const Mutex<Option<$struct_name>> = 0 as *const _; |
| |
| static mut INIT: Once = ONCE_INIT; |
| INIT.call_once(|| { |
| let data = Box::new(Mutex::new(None)); |
| DATA = &*data; |
| mem::forget(data); |
| }); |
| |
| let data: &Mutex<Option<$struct_name>> = &*DATA; |
| let mut data = data.lock().unwrap(); |
| |
| if let Some(ref data) = *data { |
| return Ok(mem::transmute(data)); |
| } |
| |
| let path = ::std::path::Path::new($defpath); |
| let result = try!($struct_name::open(path)); |
| *data = Some(result); |
| Ok(mem::transmute(data.as_ref().unwrap())) |
| } |
| } |
| } |
| |
| $($standalones)+ |
| }; |
| } |