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
use std::sync::atomic::{AtomicUsize, Ordering}; use std::{marker, mem}; use std::ffi::CString; use std::os::raw::{c_char, c_void}; pub struct Weak<F> { name: &'static str, addr: AtomicUsize, _marker: marker::PhantomData<F>, } impl<F> Weak<F> { pub const fn new(name: &'static str) -> Weak<F> { Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData, } } pub fn get(&self) -> Option<&F> { assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); unsafe { if self.addr.load(Ordering::SeqCst) == 1 { self.addr.store(fetch(self.name), Ordering::SeqCst); } if self.addr.load(Ordering::SeqCst) == 0 { None } else { mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) } } } } unsafe fn fetch(name: &str) -> usize { let name = match CString::new(name) { Ok(cstr) => cstr, Err(..) => return 0, }; find_symbol(name.as_ptr()) } #[cfg(unix)] unsafe fn find_symbol(name: *const c_char) -> usize { extern "C" { pub fn dlsym( handle: *mut c_void, symbol: *const c_char, ) -> *mut c_void; } pub const RTLD_DEFAULT: *mut c_void = 0i64 as *mut c_void; dlsym(RTLD_DEFAULT, name) as usize } #[cfg(windows)] unsafe fn find_symbol(name: *const c_char) -> usize { use std::ptr::null; use kernel32::{GetModuleHandle, GetProcAddress}; GetProcAddress(GetModuleHandleA(null()), name) as usize }