summaryrefslogtreecommitdiffstats
path: root/third_party/rust/libloading/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/libloading/src/lib.rs')
-rw-r--r--third_party/rust/libloading/src/lib.rs328
1 files changed, 328 insertions, 0 deletions
diff --git a/third_party/rust/libloading/src/lib.rs b/third_party/rust/libloading/src/lib.rs
new file mode 100644
index 0000000000..fad7d63396
--- /dev/null
+++ b/third_party/rust/libloading/src/lib.rs
@@ -0,0 +1,328 @@
+//! A memory-safer wrapper around system dynamic library loading primitives.
+//!
+//! Using this library allows loading [dynamic libraries](struct.Library.html) (also known as
+//! shared libraries) as well as use functions and static variables these libraries contain.
+//!
+//! While the library does expose a cross-platform interface to load a library and find stuff
+//! inside it, little is done to paper over the platform differences, especially where library
+//! loading is involved. The documentation for each function will attempt to document such
+//! differences on the best-effort basis.
+//!
+//! Less safe, platform specific bindings are also available. See the
+//! [`os::platform`](os/index.html) module for details.
+//!
+//! # Usage
+//!
+//! Add a dependency on this library to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! libloading = "0.5"
+//! ```
+//!
+//! Then inside your project
+//!
+//! ```no_run
+//! extern crate libloading as lib;
+//!
+//! fn call_dynamic() -> Result<u32, Box<dyn std::error::Error>> {
+//! let lib = lib::Library::new("/path/to/liblibrary.so")?;
+//! unsafe {
+//! let func: lib::Symbol<unsafe extern fn() -> u32> = lib.get(b"my_func")?;
+//! Ok(func())
+//! }
+//! }
+//! ```
+//!
+//! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes
+//! from, preventing a common cause of undefined behaviour and memory safety problems.
+use std::ffi::OsStr;
+use std::fmt;
+use std::ops;
+use std::marker;
+
+#[cfg(unix)]
+use self::os::unix as imp;
+#[cfg(windows)]
+use self::os::windows as imp;
+pub use self::error::Error;
+
+pub mod os;
+pub mod changelog;
+mod util;
+mod error;
+
+/// A loaded dynamic library.
+pub struct Library(imp::Library);
+
+impl Library {
+ /// Find and load a dynamic library.
+ ///
+ /// The `filename` argument may be any of:
+ ///
+ /// * A library filename;
+ /// * Absolute path to the library;
+ /// * Relative (to the current working directory) path to the library.
+ ///
+ /// ## Thread-safety
+ ///
+ /// The implementation strives to be as MT-safe as sanely possible, however due to certain
+ /// error-handling related resources not always being safe, this library is not MT-safe either.
+ ///
+ /// * On Windows Vista and earlier error handling falls back to [`SetErrorMode`], which is not
+ /// MT-safe. MT-scenarios involving this function may cause a traditional data race;
+ /// * On some UNIX targets `dlerror` might not be MT-safe, resulting in garbage error messages
+ /// in certain MT-scenarios.
+ ///
+ /// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
+ ///
+ /// Calling this function from multiple threads is not safe if used in conjunction with
+ /// path-less filename and 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, locations where library is searched for is
+ /// platform specific and cannot be adjusted in a portable manner.
+ ///
+ /// ### Windows
+ ///
+ /// If the `filename` specifies a library filename without path and with extension omitted,
+ /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
+ /// trailing `.` to the `filename`.
+ ///
+ /// If the library contains thread local variables (MSVC’s `_declspec(thread)`, Rust’s
+ /// `#[thread_local]` attributes), loading the library will fail on versions prior to Windows
+ /// Vista.
+ ///
+ /// ## Tips
+ ///
+ /// Distributing your dynamic libraries under a filename common to all platforms (e.g.
+ /// `awesome.module`) allows to avoid code which has to account for platform’s conventional
+ /// library filenames.
+ ///
+ /// Strive to specify absolute or 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 flaky code.
+ ///
+ /// ## Examples
+ ///
+ /// ```no_run
+ /// # use ::libloading::Library;
+ /// // Any of the following are valid.
+ /// let _ = Library::new("/path/to/awesome.module").unwrap();
+ /// let _ = Library::new("../awesome.module").unwrap();
+ /// let _ = Library::new("libsomelib.so.1").unwrap();
+ /// ```
+ pub fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> {
+ imp::Library::new(filename).map(From::from)
+ }
+
+ /// Get a pointer to function or static variable by symbol name.
+ ///
+ /// The `symbol` may not contain any null bytes, with an exception of last byte. A null
+ /// terminated `symbol` may avoid a string allocation in some cases.
+ ///
+ /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
+ /// most likely invalid.
+ ///
+ /// ## Unsafety
+ ///
+ /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
+ /// undefined.
+ ///
+ /// ## Platform-specific behaviour
+ ///
+ /// On Linux and Windows, a TLS variable acts just like any regular global variable. OS X uses
+ /// some sort of lazy initialization scheme, which makes loading TLS variables this way
+ /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
+ ///
+ /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
+ /// as FreeBSD), this function will unconditionally return an error 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 = Library::new("/path/to/awesome.module").unwrap();
+ /// ```
+ ///
+ /// Loading and using a function looks like this:
+ ///
+ /// ```no_run
+ /// # use ::libloading::{Library, Symbol};
+ /// # let lib = 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 = 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.
+ 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. Primary method to create an instance of a `Symbol` is via `Library::get`.
+///
+/// Due to implementation of the `Deref` trait, an instance of `Symbol` may be used as if it was a
+/// function or variable directly, without taking care to “extract” function or variable manually
+/// most of the time.
+///
+/// See [`Library::get`] for details.
+///
+/// [`Library::get`]: ./struct.Library.html#method.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`.
+ ///
+ /// ## Unsafety
+ /// Using this function relinquishes all the lifetime guarantees. It is up to programmer 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};
+ /// let lib = Library::new("/path/to/awesome.module").unwrap();
+ /// unsafe {
+ /// 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 reference to the library provided.
+ ///
+ /// ## Unsafety
+ ///
+ /// It is invalid to provide a reference to any other value other than the library the `sym`
+ /// was loaded from. Doing so invalidates any lifetime guarantees.
+ ///
+ /// ## Examples
+ ///
+ /// ```no_run
+ /// # use ::libloading::{Library, Symbol};
+ /// let lib = Library::new("/path/to/awesome.module").unwrap();
+ /// unsafe {
+ /// 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>, _: &'lib L) -> Symbol<'lib, T> {
+ 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};
+ /// let lib = Library::new("/path/to/awesome.module").unwrap();
+ /// unsafe {
+ /// 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> {}