Library & Symbol exist on supported platforms only
This makes the error messages and use of this library on targets such as wasm32-unknown-unknown much more straightforward.
This commit is contained in:
parent
e38bb29824
commit
4ece71daad
|
@ -192,7 +192,6 @@ pub mod r0_6_1 {}
|
|||
/// [`Error`]: crate::Error
|
||||
pub mod r0_6_0 {}
|
||||
|
||||
|
||||
/// Release 0.5.2 (2019-07-07)
|
||||
///
|
||||
/// * Added API to convert OS-specific `Library` and `Symbol` conversion to underlying resources.
|
||||
|
@ -223,7 +222,6 @@ pub mod r0_5_0 {}
|
|||
/// * `cargo test --release` now works when testing libloading.
|
||||
pub mod r0_4_3 {}
|
||||
|
||||
|
||||
/// Release 0.4.2 (2017-09-24)
|
||||
///
|
||||
/// * Improved error and race-condition handling on Windows;
|
||||
|
@ -231,7 +229,6 @@ pub mod r0_4_3 {}
|
|||
/// * Added `Symbol::<Option<T>::lift_option() -> Option<Symbol<T>>` convenience method.
|
||||
pub mod r0_4_2 {}
|
||||
|
||||
|
||||
/// Release 0.4.1 (2017-08-29)
|
||||
///
|
||||
/// * Solaris support
|
||||
|
|
301
src/lib.rs
301
src/lib.rs
|
@ -35,307 +35,24 @@
|
|||
//!
|
||||
//! The compiler will ensure that the loaded function will not outlive the `Library` from which it comes,
|
||||
//! preventing the most common memory-safety issues.
|
||||
#![deny(missing_docs, clippy::all, unreachable_pub, unused)]
|
||||
#![cfg_attr(any(unix, windows), deny(missing_docs, clippy::all, unreachable_pub, unused))]
|
||||
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fmt;
|
||||
use std::marker;
|
||||
use std::ops;
|
||||
|
||||
pub use self::error::Error;
|
||||
#[cfg(unix)]
|
||||
use self::os::unix as imp;
|
||||
#[cfg(windows)]
|
||||
use self::os::windows as imp;
|
||||
|
||||
pub mod changelog;
|
||||
mod error;
|
||||
pub mod os;
|
||||
mod util;
|
||||
|
||||
/// A loaded dynamic library.
|
||||
pub struct Library(imp::Library);
|
||||
mod error;
|
||||
pub use self::error::Error;
|
||||
|
||||
impl Library {
|
||||
/// Find and load a dynamic library.
|
||||
///
|
||||
/// The `filename` argument may be either:
|
||||
///
|
||||
/// * A library filename;
|
||||
/// * The absolute path to the library;
|
||||
/// * A relative (to the current working directory) path to the library.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded, initialisation routines contained within it are executed.
|
||||
/// For the purposes of safety, the execution of these routines is conceptually the same calling an
|
||||
/// unknown foreign function and may impose arbitrary requirements on the caller for the call
|
||||
/// to be sound.
|
||||
///
|
||||
/// Additionally, the callers of this function must also ensure that execution of the
|
||||
/// termination routines contained within the library is safe as well. These routines may be
|
||||
/// executed when the library is unloaded.
|
||||
///
|
||||
/// # Thread-safety
|
||||
///
|
||||
/// The implementation strives to be as MT-safe as sanely possible, however on certain
|
||||
/// platforms the underlying error-handling related APIs not always MT-safe. This library
|
||||
/// shares these limitations on those platforms. In particular, on certain UNIX targets
|
||||
/// `dlerror` is not MT-safe, resulting in garbage error messages in certain MT-scenarios.
|
||||
///
|
||||
/// Calling this function from multiple threads is not MT-safe if used in conjunction with
|
||||
/// library filenames and the library search path is modified (`SetDllDirectory` function on
|
||||
/// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
///
|
||||
/// When a plain library filename is supplied, the locations in which the library is searched are
|
||||
/// platform specific and cannot be adjusted in a portable manner. See the documentation for
|
||||
/// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
|
||||
/// for further information on library lookup behaviour.
|
||||
///
|
||||
/// If the `filename` specifies a library filename without a path and with the extension omitted,
|
||||
/// the `.dll` extension is implicitly added on Windows.
|
||||
///
|
||||
/// # Tips
|
||||
///
|
||||
/// Distributing your dynamic libraries under a filename common to all platforms (e.g.
|
||||
/// `awesome.module`) allows you to avoid code which has to account for platform’s conventional
|
||||
/// library filenames.
|
||||
///
|
||||
/// Strive to specify an absolute or at least a relative path to your library, unless
|
||||
/// system-wide libraries are being loaded. Platform-dependent library search locations
|
||||
/// combined with various quirks related to path-less filenames may cause flakiness in
|
||||
/// programs.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::Library;
|
||||
/// // Any of the following are valid.
|
||||
/// unsafe {
|
||||
/// let _ = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let _ = Library::new("../awesome.module").unwrap();
|
||||
/// let _ = Library::new("libsomelib.so.1").unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> {
|
||||
imp::Library::new(filename).map(From::from)
|
||||
}
|
||||
#[cfg(any(unix, windows, docsrs))]
|
||||
mod safe;
|
||||
#[cfg(any(unix, windows, docsrs))]
|
||||
pub use self::safe::{Library, Symbol};
|
||||
|
||||
/// Get a pointer to a function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
|
||||
/// null-terminated `symbol` may help to avoid an allocation.
|
||||
///
|
||||
/// The symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
|
||||
/// most likely invalid.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users of this API must specify the correct type of the function or variable loaded.
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
///
|
||||
/// The implementation of thread-local variables is extremely platform specific and uses of such
|
||||
/// variables that work on e.g. Linux may have unintended behaviour on other targets.
|
||||
///
|
||||
/// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
|
||||
/// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym`
|
||||
/// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null
|
||||
/// pointer without it being an error. If loading a null pointer is something you care about,
|
||||
/// consider using the [`os::unix::Library::get_singlethreaded`] call.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Given a loaded library:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::Library;
|
||||
/// let lib = unsafe {
|
||||
/// Library::new("/path/to/awesome.module").unwrap()
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Loading and using a function looks like this:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// # let lib = unsafe {
|
||||
/// # Library::new("/path/to/awesome.module").unwrap()
|
||||
/// # };
|
||||
/// unsafe {
|
||||
/// let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
|
||||
/// lib.get(b"awesome_function\0").unwrap();
|
||||
/// awesome_function(0.42);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A static variable may also be loaded and inspected:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// # let lib = unsafe { Library::new("/path/to/awesome.module").unwrap() };
|
||||
/// unsafe {
|
||||
/// let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
|
||||
/// **awesome_variable = 42.0;
|
||||
/// };
|
||||
/// ```
|
||||
pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error> {
|
||||
self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
|
||||
}
|
||||
|
||||
/// Unload the library.
|
||||
///
|
||||
/// This method might be a no-op, depending on the flags with which the `Library` was opened,
|
||||
/// what library was opened or other platform specifics.
|
||||
///
|
||||
/// You only need to call this if you are interested in handling any errors that may arise when
|
||||
/// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the
|
||||
/// library and ignore the errors were they arise.
|
||||
///
|
||||
/// The underlying data structures may still get leaked if an error does occur.
|
||||
pub fn close(self) -> Result<(), Error> {
|
||||
self.0.close()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Library {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<imp::Library> for Library {
|
||||
fn from(lib: imp::Library) -> Library {
|
||||
Library(lib)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Library> for imp::Library {
|
||||
fn from(lib: Library) -> imp::Library {
|
||||
lib.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Library {}
|
||||
unsafe impl Sync for Library {}
|
||||
|
||||
/// Symbol from a library.
|
||||
///
|
||||
/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
|
||||
/// unloaded. The primary method to create an instance of a `Symbol` is via [`Library::get`].
|
||||
///
|
||||
/// The `Deref` trait implementation allows the use of `Symbol` as if it was a function or variable
|
||||
/// itself, without taking care to “extract” the function or variable manually most of the time.
|
||||
///
|
||||
/// [`Library::get`]: Library::get
|
||||
pub struct Symbol<'lib, T: 'lib> {
|
||||
inner: imp::Symbol<T>,
|
||||
pd: marker::PhantomData<&'lib T>,
|
||||
}
|
||||
|
||||
impl<'lib, T> Symbol<'lib, T> {
|
||||
/// Extract the wrapped `os::platform::Symbol`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Using this function relinquishes all the lifetime guarantees. It is up to the developer to
|
||||
/// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
|
||||
/// was loaded from.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// unsafe {
|
||||
/// let lib = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
|
||||
/// let symbol = symbol.into_raw();
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn into_raw(self) -> imp::Symbol<T> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Wrap the `os::platform::Symbol` into this safe wrapper.
|
||||
///
|
||||
/// Note that, in order to create association between the symbol and the library this symbol
|
||||
/// came from, this function requires a reference to the library.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `library` reference must be exactly the library `sym` was loaded from.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// unsafe {
|
||||
/// let lib = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
|
||||
/// let symbol = symbol.into_raw();
|
||||
/// let symbol = Symbol::from_raw(symbol, &lib);
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, library: &'lib L) -> Symbol<'lib, T> {
|
||||
let _ = library; // ignore here for documentation purposes.
|
||||
Symbol {
|
||||
inner: sym,
|
||||
pd: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lib, T> Symbol<'lib, Option<T>> {
|
||||
/// Lift Option out of the symbol.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// unsafe {
|
||||
/// let lib = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
|
||||
/// let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lift_option(self) -> Option<Symbol<'lib, T>> {
|
||||
self.inner.lift_option().map(|is| Symbol {
|
||||
inner: is,
|
||||
pd: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lib, T> Clone for Symbol<'lib, T> {
|
||||
fn clone(&self) -> Symbol<'lib, T> {
|
||||
Symbol {
|
||||
inner: self.inner.clone(),
|
||||
pd: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: implement FnOnce for callable stuff instead.
|
||||
impl<'lib, T> ops::Deref for Symbol<'lib, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
ops::Deref::deref(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
|
||||
unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
|
||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
/// Converts a library name to a filename generally appropriate for use on the system.
|
||||
///
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
// A hack for docs.rs to build documentation that has both windows and linux documentation in the
|
||||
// same rustdoc build visible.
|
||||
#[cfg(all(docsrs, not(unix)))]
|
||||
mod unix_imports {
|
||||
}
|
||||
mod unix_imports {}
|
||||
#[cfg(any(not(docsrs), unix))]
|
||||
mod unix_imports {
|
||||
pub(super) use std::os::unix::ffi::OsStrExt;
|
||||
}
|
||||
|
||||
use self::unix_imports::*;
|
||||
use util::{ensure_compatible_types, cstr_cow_from_bytes};
|
||||
use std::ffi::{CStr, OsStr};
|
||||
use std::{fmt, marker, mem, ptr};
|
||||
use std::os::raw;
|
||||
pub use self::consts::*;
|
||||
use self::unix_imports::*;
|
||||
use std::ffi::{CStr, OsStr};
|
||||
use std::os::raw;
|
||||
use std::{fmt, marker, mem, ptr};
|
||||
use util::{cstr_cow_from_bytes, ensure_compatible_types};
|
||||
|
||||
mod consts;
|
||||
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
use super::Error;
|
||||
#[cfg(any(unix, docsrs))]
|
||||
use super::os::unix as imp;
|
||||
#[cfg(windows)]
|
||||
use super::os::windows as imp;
|
||||
use super::Error;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
use std::marker;
|
||||
use std::ops;
|
||||
|
||||
/// A loaded dynamic library.
|
||||
#[cfg_attr(docsrs, doc(cfg(any(unix, windows))))]
|
||||
pub struct Library(imp::Library);
|
||||
|
||||
impl Library {
|
||||
/// Find and load a dynamic library.
|
||||
///
|
||||
/// The `filename` argument may be either:
|
||||
///
|
||||
/// * A library filename;
|
||||
/// * The absolute path to the library;
|
||||
/// * A relative (to the current working directory) path to the library.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When a library is loaded, initialisation routines contained within it are executed.
|
||||
/// For the purposes of safety, the execution of these routines is conceptually the same calling an
|
||||
/// unknown foreign function and may impose arbitrary requirements on the caller for the call
|
||||
/// to be sound.
|
||||
///
|
||||
/// Additionally, the callers of this function must also ensure that execution of the
|
||||
/// termination routines contained within the library is safe as well. These routines may be
|
||||
/// executed when the library is unloaded.
|
||||
///
|
||||
/// # Thread-safety
|
||||
///
|
||||
/// The implementation strives to be as MT-safe as sanely possible, however on certain
|
||||
/// platforms the underlying error-handling related APIs not always MT-safe. This library
|
||||
/// shares these limitations on those platforms. In particular, on certain UNIX targets
|
||||
/// `dlerror` is not MT-safe, resulting in garbage error messages in certain MT-scenarios.
|
||||
///
|
||||
/// Calling this function from multiple threads is not MT-safe if used in conjunction with
|
||||
/// library filenames and the library search path is modified (`SetDllDirectory` function on
|
||||
/// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
///
|
||||
/// When a plain library filename is supplied, the locations in which the library is searched are
|
||||
/// platform specific and cannot be adjusted in a portable manner. See the documentation for
|
||||
/// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
|
||||
/// for further information on library lookup behaviour.
|
||||
///
|
||||
/// If the `filename` specifies a library filename without a path and with the extension omitted,
|
||||
/// the `.dll` extension is implicitly added on Windows.
|
||||
///
|
||||
/// # Tips
|
||||
///
|
||||
/// Distributing your dynamic libraries under a filename common to all platforms (e.g.
|
||||
/// `awesome.module`) allows you to avoid code which has to account for platform’s conventional
|
||||
/// library filenames.
|
||||
///
|
||||
/// Strive to specify an absolute or at least a relative path to your library, unless
|
||||
/// system-wide libraries are being loaded. Platform-dependent library search locations
|
||||
/// combined with various quirks related to path-less filenames may cause flakiness in
|
||||
/// programs.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::Library;
|
||||
/// // Any of the following are valid.
|
||||
/// unsafe {
|
||||
/// let _ = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let _ = Library::new("../awesome.module").unwrap();
|
||||
/// let _ = Library::new("libsomelib.so.1").unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> {
|
||||
imp::Library::new(filename).map(From::from)
|
||||
}
|
||||
|
||||
/// Get a pointer to a function or static variable by symbol name.
|
||||
///
|
||||
/// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
|
||||
/// null-terminated `symbol` may help to avoid an allocation.
|
||||
///
|
||||
/// The symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
|
||||
/// most likely invalid.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users of this API must specify the correct type of the function or variable loaded.
|
||||
///
|
||||
/// # Platform-specific behaviour
|
||||
///
|
||||
/// The implementation of thread-local variables is extremely platform specific and uses of such
|
||||
/// variables that work on e.g. Linux may have unintended behaviour on other targets.
|
||||
///
|
||||
/// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
|
||||
/// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym`
|
||||
/// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null
|
||||
/// pointer without it being an error. If loading a null pointer is something you care about,
|
||||
/// consider using the [`os::unix::Library::get_singlethreaded`] call.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Given a loaded library:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::Library;
|
||||
/// let lib = unsafe {
|
||||
/// Library::new("/path/to/awesome.module").unwrap()
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Loading and using a function looks like this:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// # let lib = unsafe {
|
||||
/// # Library::new("/path/to/awesome.module").unwrap()
|
||||
/// # };
|
||||
/// unsafe {
|
||||
/// let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
|
||||
/// lib.get(b"awesome_function\0").unwrap();
|
||||
/// awesome_function(0.42);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A static variable may also be loaded and inspected:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// # let lib = unsafe { Library::new("/path/to/awesome.module").unwrap() };
|
||||
/// unsafe {
|
||||
/// let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
|
||||
/// **awesome_variable = 42.0;
|
||||
/// };
|
||||
/// ```
|
||||
pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error> {
|
||||
self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
|
||||
}
|
||||
|
||||
/// Unload the library.
|
||||
///
|
||||
/// This method might be a no-op, depending on the flags with which the `Library` was opened,
|
||||
/// what library was opened or other platform specifics.
|
||||
///
|
||||
/// You only need to call this if you are interested in handling any errors that may arise when
|
||||
/// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the
|
||||
/// library and ignore the errors were they arise.
|
||||
///
|
||||
/// The underlying data structures may still get leaked if an error does occur.
|
||||
pub fn close(self) -> Result<(), Error> {
|
||||
self.0.close()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Library {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<imp::Library> for Library {
|
||||
fn from(lib: imp::Library) -> Library {
|
||||
Library(lib)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Library> for imp::Library {
|
||||
fn from(lib: Library) -> imp::Library {
|
||||
lib.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Library {}
|
||||
unsafe impl Sync for Library {}
|
||||
|
||||
/// Symbol from a library.
|
||||
///
|
||||
/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
|
||||
/// unloaded. The primary method to create an instance of a `Symbol` is via [`Library::get`].
|
||||
///
|
||||
/// The `Deref` trait implementation allows the use of `Symbol` as if it was a function or variable
|
||||
/// itself, without taking care to “extract” the function or variable manually most of the time.
|
||||
///
|
||||
/// [`Library::get`]: Library::get
|
||||
#[cfg_attr(docsrs, doc(cfg(any(unix, windows))))]
|
||||
pub struct Symbol<'lib, T: 'lib> {
|
||||
inner: imp::Symbol<T>,
|
||||
pd: marker::PhantomData<&'lib T>,
|
||||
}
|
||||
|
||||
impl<'lib, T> Symbol<'lib, T> {
|
||||
/// Extract the wrapped `os::platform::Symbol`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Using this function relinquishes all the lifetime guarantees. It is up to the developer to
|
||||
/// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
|
||||
/// was loaded from.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// unsafe {
|
||||
/// let lib = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
|
||||
/// let symbol = symbol.into_raw();
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn into_raw(self) -> imp::Symbol<T> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Wrap the `os::platform::Symbol` into this safe wrapper.
|
||||
///
|
||||
/// Note that, in order to create association between the symbol and the library this symbol
|
||||
/// came from, this function requires a reference to the library.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `library` reference must be exactly the library `sym` was loaded from.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// unsafe {
|
||||
/// let lib = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
|
||||
/// let symbol = symbol.into_raw();
|
||||
/// let symbol = Symbol::from_raw(symbol, &lib);
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, library: &'lib L) -> Symbol<'lib, T> {
|
||||
let _ = library; // ignore here for documentation purposes.
|
||||
Symbol {
|
||||
inner: sym,
|
||||
pd: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lib, T> Symbol<'lib, Option<T>> {
|
||||
/// Lift Option out of the symbol.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use ::libloading::{Library, Symbol};
|
||||
/// unsafe {
|
||||
/// let lib = Library::new("/path/to/awesome.module").unwrap();
|
||||
/// let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
|
||||
/// let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn lift_option(self) -> Option<Symbol<'lib, T>> {
|
||||
self.inner.lift_option().map(|is| Symbol {
|
||||
inner: is,
|
||||
pd: marker::PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lib, T> Clone for Symbol<'lib, T> {
|
||||
fn clone(&self) -> Symbol<'lib, T> {
|
||||
Symbol {
|
||||
inner: self.inner.clone(),
|
||||
pd: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: implement FnOnce for callable stuff instead.
|
||||
impl<'lib, T> ops::Deref for Symbol<'lib, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
ops::Deref::deref(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
|
||||
unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
|
|
@ -1,5 +1,5 @@
|
|||
extern crate libloading;
|
||||
extern crate libc;
|
||||
extern crate libloading;
|
||||
extern crate static_assertions;
|
||||
|
||||
#[cfg(all(test, unix))]
|
||||
|
|
Loading…
Reference in New Issue