// x11-rs: Rust bindings for X11 libraries
// The X11 libraries are available under the MIT license.
// These bindings are public domain.
use std::path::Path;
use dylib::DynamicLibrary;
use x11_dl::error::{
OpenError,
OpenErrorKind,
};
//
// x11_link!
//
macro_rules! x11_link {
{ $struct_name:ident, [$($lib_name:expr),*],
$(pub fn $fn_name:ident ($($param_name:ident : $param_type:ty),*) -> $ret_type:ty,)*
variadic:
$(pub fn $vfn_name:ident ($($vparam_name: ident : $vparam_type:ty),+) -> $vret_type:ty,)*
globals:
$(pub static $var_name:ident : $var_type:ty,)*
} => {
pub struct $struct_name {
#[allow(dead_code)]
lib: ::dylib::DynamicLibrary,
$(pub $fn_name: unsafe extern "C" fn ($($param_type),*) -> $ret_type,)*
$(pub $vfn_name: unsafe extern "C" fn ($($vparam_type),+, ...) -> $vret_type,)*
$(pub $var_name: *mut $var_type,)*
}
impl $struct_name {
pub fn open () -> Result<$struct_name, ::x11_dl::error::OpenError> {
unsafe {
let lib = try!(::link::open_lib(&[$($lib_name),*]));
$(let $fn_name = try!(::link::get_sym(&lib, stringify!($fn_name)));)*
$(let $vfn_name = try!(::link::get_sym(&lib, stringify!($vfn_name)));)*
$(let $var_name = try!(::link::get_sym(&lib, stringify!($var_name)));)*
return Ok($struct_name {
lib: lib,
$($fn_name: ::std::mem::transmute($fn_name),)*
$($vfn_name: ::std::mem::transmute($vfn_name),)*
$($var_name: $var_name as *mut $var_type,)*
});
}
}
}
}
}
//
// public functions
//
pub fn get_sym (lib: &DynamicLibrary, name: &str) -> Result<*mut (), OpenError> {
unsafe {
match lib.symbol(name) {
Ok(sym) => Ok(sym),
Err(msg) => Err(OpenError::new(OpenErrorKind::Symbol, msg)),
}
}
}
pub fn open_lib (names: &[&'static str]) -> Result<DynamicLibrary, OpenError> {
assert!(!names.is_empty());
let mut msgs = Vec::new();
for name in names.iter() {
match DynamicLibrary::open(Some(Path::new(*name))) {
Ok(lib) => { return Ok(lib); },
Err(err) => { msgs.push(err); },
}
}
let mut detail = String::new();
for i in 0..msgs.len() {
if i != 0 {
detail.push_str(", ");
}
detail.push_str("\"");
detail.push_str(msgs[i].as_ref());
detail.push_str("\"");
}
return Err(OpenError::new(OpenErrorKind::Library, detail));
}