|
46 | 46 | #![cfg_attr(docsrs, feature(doc_cfg))] |
47 | 47 |
|
48 | 48 |
|
| 49 | +use std::borrow::Cow; |
| 50 | +use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; |
49 | 51 | use std::ffi::OsStr; |
50 | 52 | use std::fmt; |
51 | | -use std::ops; |
| 53 | +use std::ops::{self, Deref}; |
52 | 54 | use std::marker; |
53 | 55 |
|
54 | 56 | #[cfg(unix)] |
@@ -128,6 +130,35 @@ impl Library { |
128 | 130 | imp::Library::new(filename).map(From::from) |
129 | 131 | } |
130 | 132 |
|
| 133 | + fn resolve_name<'a>(name: &'a str) -> Cow<'a, str> { |
| 134 | + match (name.starts_with(DLL_PREFIX), name.ends_with(DLL_SUFFIX)) { |
| 135 | + (true, true) => Cow::Borrowed(name), |
| 136 | + (true, false) => Cow::Owned(format!("{}{}", name, DLL_SUFFIX)), |
| 137 | + (false, true) => Cow::Owned(format!("{}{}", DLL_PREFIX, name)), |
| 138 | + (false, false) => Cow::Owned(format!("{}{}{}", DLL_PREFIX, name, DLL_SUFFIX)), |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + /// Loads a library and does resolve it's name to match platform-specific |
| 143 | + /// naming schemes. |
| 144 | + /// |
| 145 | + /// For a given library called `engine`, this method will resolve the name |
| 146 | + /// to the following: |
| 147 | + /// - `Linux`: `libengine.so` |
| 148 | + /// - `macOS`: `libengine.dylib` |
| 149 | + /// - `Windows`: `engine.dll` |
| 150 | + /// |
| 151 | + /// # Note |
| 152 | + /// |
| 153 | + /// This function does only work with library names and does not work when |
| 154 | + /// supplying a path to a library. The function assumes that the library is |
| 155 | + /// already present inside a path that is detectable and searchable by the |
| 156 | + /// OS during runtime. |
| 157 | + pub fn with_name_resolve<T: AsRef<str>>(libname: T) -> Result<Library, Error> { |
| 158 | + let resolved_name = Self::resolve_name(libname.as_ref()); |
| 159 | + Self::new(resolved_name.deref()) |
| 160 | + } |
| 161 | + |
131 | 162 | /// Get a pointer to function or static variable by symbol name. |
132 | 163 | /// |
133 | 164 | /// 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> { |
337 | 368 |
|
338 | 369 | unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {} |
339 | 370 | unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {} |
| 371 | + |
| 372 | +#[cfg(test)] |
| 373 | +mod tests { |
| 374 | + use super::Library; |
| 375 | + |
| 376 | + #[cfg(target_os = "windows")] |
| 377 | + #[test] |
| 378 | + fn test_resolve_name_none() { |
| 379 | + let name = "audioengine"; |
| 380 | + let resolved = Library::resolve_name(name); |
| 381 | + assert_eq!(&resolved, "audioengine.dll"); |
| 382 | + } |
| 383 | + |
| 384 | + #[cfg(target_os = "linux")] |
| 385 | + #[test] |
| 386 | + fn test_resolve_name_none() { |
| 387 | + let name = "audioengine"; |
| 388 | + let resolved = Library::resolve_name(name); |
| 389 | + assert_eq!(&resolved, "libaudioengine.so"); |
| 390 | + } |
| 391 | + |
| 392 | + #[cfg(target_os = "macos")] |
| 393 | + #[test] |
| 394 | + fn test_resolve_name_none() { |
| 395 | + let name = "audioengine"; |
| 396 | + let resolved = Library::resolve_name(name); |
| 397 | + assert_eq!(&resolved, "libaudioengine.dylib"); |
| 398 | + } |
| 399 | + |
| 400 | + // prefix only |
| 401 | + |
| 402 | + #[cfg(target_os = "windows")] |
| 403 | + #[test] |
| 404 | + fn test_resolve_name_prefix() { |
| 405 | + let name = "audioengine"; |
| 406 | + let resolved = Library::resolve_name(name); |
| 407 | + assert_eq!(&resolved, "audioengine.dll"); |
| 408 | + } |
| 409 | + |
| 410 | + #[cfg(target_os = "linux")] |
| 411 | + #[test] |
| 412 | + fn test_resolve_name_prefix() { |
| 413 | + let name = "libaudioengine"; |
| 414 | + let resolved = Library::resolve_name(name); |
| 415 | + assert_eq!(&resolved, "libaudioengine.so"); |
| 416 | + } |
| 417 | + |
| 418 | + #[cfg(target_os = "macos")] |
| 419 | + #[test] |
| 420 | + fn test_resolve_name_prefix() { |
| 421 | + let name = "libaudioengine"; |
| 422 | + let resolved = Library::resolve_name(name); |
| 423 | + assert_eq!(&resolved, "libaudioengine.dylib"); |
| 424 | + } |
| 425 | + |
| 426 | + // suffix only |
| 427 | + |
| 428 | + #[cfg(target_os = "windows")] |
| 429 | + #[test] |
| 430 | + fn test_resolve_name_suffix() { |
| 431 | + let name = "audioengine.dll"; |
| 432 | + let resolved = Library::resolve_name(name); |
| 433 | + assert_eq!(&resolved, "audioengine.dll"); |
| 434 | + } |
| 435 | + |
| 436 | + #[cfg(target_os = "linux")] |
| 437 | + #[test] |
| 438 | + fn test_resolve_name_suffix() { |
| 439 | + let name = "audioengine.so"; |
| 440 | + let resolved = Library::resolve_name(name); |
| 441 | + assert_eq!(&resolved, "libaudioengine.so"); |
| 442 | + } |
| 443 | + |
| 444 | + #[cfg(target_os = "macos")] |
| 445 | + #[test] |
| 446 | + fn test_resolve_name_suffix() { |
| 447 | + let name = "audioengine.dylib"; |
| 448 | + let resolved = Library::resolve_name(name); |
| 449 | + assert_eq!(&resolved, "libaudioengine.dylib"); |
| 450 | + } |
| 451 | + |
| 452 | + // both |
| 453 | + |
| 454 | + #[cfg(target_os = "windows")] |
| 455 | + #[test] |
| 456 | + fn test_resolve_name_prefix_and_suffix() { |
| 457 | + let name = "audioengine.dll"; |
| 458 | + let resolved = Library::resolve_name(name); |
| 459 | + assert_eq!(&resolved, "audioengine.dll"); |
| 460 | + } |
| 461 | + |
| 462 | + #[cfg(target_os = "linux")] |
| 463 | + #[test] |
| 464 | + fn test_resolve_name_prefix_and_suffix() { |
| 465 | + let name = "libaudioengine.so"; |
| 466 | + let resolved = Library::resolve_name(name); |
| 467 | + assert_eq!(&resolved, "libaudioengine.so"); |
| 468 | + } |
| 469 | + |
| 470 | + #[cfg(target_os = "macos")] |
| 471 | + #[test] |
| 472 | + fn test_resolve_name_prefix_and_suffix() { |
| 473 | + let name = "libaudioengine.dylib"; |
| 474 | + let resolved = Library::resolve_name(name); |
| 475 | + assert_eq!(&resolved, "libaudioengine.dylib"); |
| 476 | + } |
| 477 | +} |
0 commit comments