shared_library/
lib.rs

1extern crate libc;
2
3#[macro_use]
4extern crate lazy_static;
5
6pub mod dynamic_library;
7
8/// Error that can happen while loading the shared library.
9#[derive(Debug, Clone)]
10pub 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]
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        /// 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}