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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
use std::ffi::CStr; use super::symbol::Symbol; use super::ptr_or_null::PtrOrNull; use super::ptr_or_null_mut::PtrOrNullMut; use super::super::raw::Library as RawLib; use std::ffi::{CString, OsStr}; use std::ptr::{null, null_mut}; use super::super::err::Error; /** Safe wrapper around dynamic link library handle. Methods of `Library` return only types that make the library borrowed. Therefore the problem with dangling symbols is prevented. **Note:**: It is recommended that you use certain methods in certain situations: * `symbol()` - for obtaining functions and pointers (but only if you can't use references instead of pointers and you do not accept null value of a pointer). * `reference()` and `reference_mut()` - for obtaining access to statically allocated objects - either constant or mutable. * `ptr_or_null()` and `ptr_or_null_mut()` - for obtaining pointers if you accept null values of pointers (in 99% of cases you should rather use previously mentioned methods). #Example ```no_run extern crate dlopen; use dlopen::symbor::Library; fn main(){ let lib = Library::open("libexample.dylib").unwrap(); let fun = unsafe{lib.symbol::<unsafe extern "C" fn()>("function")}.unwrap(); unsafe{fun()}; let glob_val: &mut u32 = unsafe{lib.reference_mut("glob_val")}.unwrap(); *glob_val = 42; let ptr_or_null = unsafe{lib.ptr_or_null::<()>("void_ptr")}.unwrap(); println!("Pointer is null: {}", ptr_or_null.is_null()); } ``` */ pub struct Library { lib: RawLib, } impl Library { ///Open dynamic link library using provided file name or path. pub fn open<S>(name: S) -> Result<Library, Error> where S: AsRef<OsStr>, { Ok(Library { lib: RawLib::open(name)?, }) } /// Open the program itself as library. /// /// This allows a shared library to load symbols of the program it was /// loaded into. pub fn open_self() -> Result<Library, Error> { Ok(Library { lib: RawLib::open_self()?, }) } /// Obtain a symbol from library. /// /// This method is the most general one and allows obtaining basically everything assuming /// that the value of the given symbol cannot be null (use `ptr_or_null()` for this case). /// However the `reference()` and `reference_mut()` methods return a native reference and they /// are more programmer friendly when you try accessing statically allocated data in /// the library. pub unsafe fn symbol<T>(&self, name: &str) -> Result<Symbol<T>, Error> { Ok(Symbol::new(self.lib.symbol(name)?)) } ///Equivalent of the `symbol()` method but takes `CStr` as a argument. pub unsafe fn symbol_cstr<T>(&self, name: &CStr) -> Result<Symbol<T>, Error> { Ok(Symbol::new(self.lib.symbol_cstr(name)?)) } ///Obtain a const pointer from library. /// /// **Note:** This method is only recommended for data /// that can't be accessed as a reference and that can have a null pointer value /// (so not in 99% of cases). pub unsafe fn ptr_or_null<T>(&self, name: &str) -> Result<PtrOrNull<T>, Error> { let cname = CString::new(name)?; self.ptr_or_null_cstr(cname.as_ref()) } ///Equivalent of the `pointer()` method but takes `CStr` as a argument. pub unsafe fn ptr_or_null_cstr<T>(&self, name: &CStr) -> Result<PtrOrNull<T>, Error> { let raw_ptr = match self.lib.symbol_cstr(name) { Ok(val) => val, Err(err) => match err { Error::NullSymbol => null(), _ => return Err(err), }, }; Ok(PtrOrNull::new(raw_ptr)) } ///Obtain a mutable pointer from library. /// /// **Note:** This method is only recommended for data /// that can't be accessed as a reference and that can have a null pointer value /// (so not in 99% of cases). pub unsafe fn ptr_or_null_mut<T>(&self, name: &str) -> Result<PtrOrNullMut<T>, Error> { let cname = CString::new(name)?; self.ptr_or_null_mut_cstr(cname.as_ref()) } ///Equivalent of the `pointer_mut()` method but takes `CStr` as a argument. pub unsafe fn ptr_or_null_mut_cstr<T>(&self, name: &CStr) -> Result<PtrOrNullMut<T>, Error> { let raw_ptr = match self.lib.symbol_cstr(name) { Ok(val) => val, Err(err) => match err { Error::NullSymbol => null_mut(), _ => return Err(err), }, }; Ok(PtrOrNullMut::new(raw_ptr)) } ///Obtain const reference to statically allocated data in the library. pub unsafe fn reference<T>(&self, name: &str) -> Result<&T, Error> { self.lib.symbol(name) } ///Equivalent of the `reference()` method but takes `CStr` as a argument. pub unsafe fn reference_cstr<T>(&self, name: &CStr) -> Result<&T, Error> { self.lib.symbol_cstr(name) } ///Obtain mutable reference to statically allocated data in the library. pub unsafe fn reference_mut<T>(&self, name: &str) -> Result<&mut T, Error> { self.lib.symbol(name) } ///Equivalent of the `reference_mut()` method but takes `CStr` as a argument. pub unsafe fn reference_mut_cstr<T>(&self, name: &CStr) -> Result<&mut T, Error> { self.lib.symbol_cstr(name) } } unsafe impl Send for Library {} unsafe impl Sync for Library {}