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
//! Provides shared library access for Unix like systems.
use crate::{core::optional::NSTDOptional, NSTDAny, NSTDAnyMut, NSTDChar};
use libc::{dlclose, dlopen, dlsym, RTLD_LAZY, RTLD_LOCAL};

/// Represents an owned handle to a dynamically loaded library.
#[repr(C)]
pub struct NSTDUnixSharedLib {
    /// A raw handle to the shared library.
    handle: NSTDAnyMut,
}
impl Drop for NSTDUnixSharedLib {
    /// [NSTDUnixSharedLib]'s destructor.
    #[inline]
    fn drop(&mut self) {
        // SAFETY: `self.handle` is never null.
        unsafe { dlclose(self.handle) };
    }
}

/// Represents an optional `NSTDUnixSharedLib`.
pub type NSTDUnixOptionalSharedLib = NSTDOptional<NSTDUnixSharedLib>;

/// Loads a dynamically loaded shared library.
///
/// # Parameters:
///
/// - `const NSTDChar *path` - A path to the shared library to load.
///
/// # Returns
///
/// `NSTDUnixOptionalSharedLib lib` - A handle to the loaded library.
///
/// # Safety
///
/// See <https://man7.org/linux/man-pages/man3/dlopen.3.html>.
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_os_unix_shared_lib_load(
    path: *const NSTDChar,
) -> NSTDUnixOptionalSharedLib {
    let handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
    if handle.is_null() {
        return NSTDOptional::None;
    }
    NSTDOptional::Some(NSTDUnixSharedLib { handle })
}

/// Returns an immutable opaque pointer to a symbol in a loaded library.
///
/// # Parameters:
///
/// - `const NSTDUnixSharedLib *lib` - The shared library.
///
/// - `const NSTDChar *symbol` - The symbol to retrieve a pointer to.
///
/// # Returns
///
/// `NSTDAny ptr` - A pointer to the loaded symbol, null on error.
///
/// # Safety
///
/// See <https://man7.org/linux/man-pages/man3/dlsym.3.html>.
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_os_unix_shared_lib_get(
    lib: &NSTDUnixSharedLib,
    symbol: *const NSTDChar,
) -> NSTDAny {
    dlsym(lib.handle, symbol)
}

/// Returns a mutable opaque pointer to a symbol in a loaded library.
///
/// # Parameters:
///
/// - `NSTDUnixSharedLib *lib` - The shared library.
///
/// - `const NSTDChar *symbol` - The symbol to retrieve a pointer to.
///
/// # Returns
///
/// `NSTDAnyMut ptr` - A pointer to the loaded symbol, null on error.
///
/// # Safety
///
/// See <https://man7.org/linux/man-pages/man3/dlsym.3.html>.
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
pub unsafe extern "C" fn nstd_os_unix_shared_lib_get_mut(
    lib: &mut NSTDUnixSharedLib,
    symbol: *const NSTDChar,
) -> NSTDAnyMut {
    dlsym(lib.handle, symbol)
}

/// Closes and frees a loaded shared library.
///
/// # Parameters:
///
/// - `NSTDUnixSharedLib lib` - A handle to the loaded library to unload.
///
/// # Safety
///
/// See <https://man7.org/linux/man-pages/man3/dlclose.3p.html>.
#[inline]
#[cfg_attr(feature = "clib", no_mangle)]
#[allow(unused_variables)]
pub unsafe extern "C" fn nstd_os_unix_shared_lib_free(lib: NSTDUnixSharedLib) {}