From 75527deec8016b4aa77ce67b7988b905da68c37c Mon Sep 17 00:00:00 2001 From: Sven Lechner Date: Mon, 17 Aug 2020 20:10:58 +0200 Subject: [PATCH] feat: add name resolving library open function The newly added method does resolve the library name passed to it by adhering to platform-specific naming schemes using Rust provided constants. Closes #62 --- src/lib.rs | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 4b522f0..6d6476d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,9 +46,11 @@ #![cfg_attr(docsrs, feature(doc_cfg))] +use std::borrow::Cow; +use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::ffi::OsStr; use std::fmt; -use std::ops; +use std::ops::{self, Deref}; use std::marker; #[cfg(unix)] @@ -128,6 +130,35 @@ impl Library { imp::Library::new(filename).map(From::from) } + fn resolve_name<'a>(name: &'a str) -> Cow<'a, str> { + match (name.starts_with(DLL_PREFIX), name.ends_with(DLL_SUFFIX)) { + (true, true) => Cow::Borrowed(name), + (true, false) => Cow::Owned(format!("{}{}", name, DLL_SUFFIX)), + (false, true) => Cow::Owned(format!("{}{}", DLL_PREFIX, name)), + (false, false) => Cow::Owned(format!("{}{}{}", DLL_PREFIX, name, DLL_SUFFIX)), + } + } + + /// Loads a library and does resolve it's name to match platform-specific + /// naming schemes. + /// + /// For a given library called `engine`, this method will resolve the name + /// to the following: + /// - `Linux`: `libengine.so` + /// - `macOS`: `libengine.dylib` + /// - `Windows`: `engine.dll` + /// + /// # Note + /// + /// This function does only work with library names and does not work when + /// supplying a path to a library. The function assumes that the library is + /// already present inside a path that is detectable and searchable by the + /// OS during runtime. + pub fn with_name_resolve>(libname: T) -> Result { + let resolved_name = Self::resolve_name(libname.as_ref()); + Self::new(resolved_name.deref()) + } + /// 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 @@ -337,3 +368,110 @@ impl<'lib, T> fmt::Debug for Symbol<'lib, T> { unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {} unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {} + +#[cfg(test)] +mod tests { + use super::Library; + + #[cfg(target_os = "windows")] + #[test] + fn test_resolve_name_none() { + let name = "audioengine"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "audioengine.dll"); + } + + #[cfg(target_os = "linux")] + #[test] + fn test_resolve_name_none() { + let name = "audioengine"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.so"); + } + + #[cfg(target_os = "macos")] + #[test] + fn test_resolve_name_none() { + let name = "audioengine"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.dylib"); + } + + // prefix only + + #[cfg(target_os = "windows")] + #[test] + fn test_resolve_name_prefix() { + let name = "audioengine"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "audioengine.dll"); + } + + #[cfg(target_os = "linux")] + #[test] + fn test_resolve_name_prefix() { + let name = "libaudioengine"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.so"); + } + + #[cfg(target_os = "macos")] + #[test] + fn test_resolve_name_prefix() { + let name = "libaudioengine"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.dylib"); + } + + // suffix only + + #[cfg(target_os = "windows")] + #[test] + fn test_resolve_name_suffix() { + let name = "audioengine.dll"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "audioengine.dll"); + } + + #[cfg(target_os = "linux")] + #[test] + fn test_resolve_name_suffix() { + let name = "audioengine.so"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.so"); + } + + #[cfg(target_os = "macos")] + #[test] + fn test_resolve_name_suffix() { + let name = "audioengine.dylib"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.dylib"); + } + + // both + + #[cfg(target_os = "windows")] + #[test] + fn test_resolve_name_prefix_and_suffix() { + let name = "audioengine.dll"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "audioengine.dll"); + } + + #[cfg(target_os = "linux")] + #[test] + fn test_resolve_name_prefix_and_suffix() { + let name = "libaudioengine.so"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.so"); + } + + #[cfg(target_os = "macos")] + #[test] + fn test_resolve_name_prefix_and_suffix() { + let name = "libaudioengine.dylib"; + let resolved = Library::resolve_name(name); + assert_eq!(&resolved, "libaudioengine.dylib"); + } +}