1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/// Macro to generate the API struct.
///
/// ```no_run
/// // Shared object: either "libmylibrary.so.1", "mylibrary-1.dll" or "libMyLibrary.dylib"
/// dl_api::link!(MyApi, "libmylibrary.so.1", {
/// 	fn cFunction(param_name: *mut u32) -> u32;
/// });
///
/// fn main() {
/// 	let api = MyApi::new().unwrap(); // unwrap the `Result`.
///
/// 	let rtn: u32 = unsafe {
/// 		(api.cFunction)(std::ptr::null_mut())
/// 	};
/// }
/// ```
#[macro_export]
macro_rules! link(
	($sname: ident, $l: expr, { $(fn $fname: ident($($sarg: ident: $farg: ty),* $(,)?) -> $fret:ty);* $(;)? }) =>
	(
		#[allow(non_snake_case)]
		pub struct $sname {
			#[allow(dead_code)]
			// this is not dead code because destructor of Library
			// deallocates the library
			__lib: $crate::Library,
			$(
				$fname: unsafe extern "system" fn($($farg),*)
					-> $fret,
			)*
		}

		impl $sname {
			fn new() -> ::std::result::Result<Self, $crate::Error> {
				unsafe {
				let __lib = $crate::Library::new($l)?;
				Ok(Self{
					$($fname: {
						match __lib.symbol(stringify!($fname)) {
							Ok(s) => s,
							Err(e) => return Err(e),
						}
					},
					)*
					__lib,
				})
				}
			}
		}
	)
);