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> = 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> = &*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)+ }; }