1use std::sync::atomic::{AtomicUsize, Ordering};
2use std::{marker, mem};
3use std::ffi::CString;
4use std::os::raw::{c_char, c_void};
5
6pub struct Weak<F> {
7 name: &'static str,
8 addr: AtomicUsize,
9 _marker: marker::PhantomData<F>,
10}
11
12impl<F> Weak<F> {
13 pub const fn new(name: &'static str) -> Weak<F> {
14 Weak {
15 name,
16 addr: AtomicUsize::new(1),
17 _marker: marker::PhantomData,
18 }
19 }
20
21 pub fn get(&self) -> Option<&F> {
22 assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
23 unsafe {
24 if self.addr.load(Ordering::SeqCst) == 1 {
25 self.addr.store(fetch(self.name), Ordering::SeqCst);
26 }
27 if self.addr.load(Ordering::SeqCst) == 0 {
28 None
29 } else {
30 mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
31 }
32 }
33 }
34}
35
36unsafe fn fetch(name: &str) -> usize {
37 let name = match CString::new(name) {
38 Ok(cstr) => cstr,
39 Err(..) => return 0,
40 };
41 find_symbol(name.as_ptr())
42}
43
44#[cfg(unix)]
45unsafe fn find_symbol(name: *const c_char) -> usize {
46 extern "C" {
47 pub fn dlsym(
48 handle: *mut c_void,
49 symbol: *const c_char,
50 ) -> *mut c_void;
51 }
52 pub const RTLD_DEFAULT: *mut c_void = 0i64 as *mut c_void;
53
54 dlsym(RTLD_DEFAULT, name) as usize
55}
56
57#[cfg(windows)]
58unsafe fn find_symbol(name: *const c_char) -> usize {
59 use std::ptr::null;
60 use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
61 GetProcAddress(GetModuleHandleA(null()), name) as usize
62}