     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

    use std::ffi::CString;
    use std::marker;
    use std::mem;
    use std::sync::atomic::{AtomicUsize, Ordering};

    use libc::{self, c_char, c_void};

    pub struct Dylib {
        pub init: AtomicUsize,
    }

    pub struct Symbol<T> {
        pub name: &'static str,
        pub addr: AtomicUsize,
        pub _marker: marker::PhantomData<T>,
    }

    impl Dylib {
        pub unsafe fn get<'a, T>(&self, sym: &'a Symbol<T>) -> Option<&'a T> {
            self.load().and_then(|handle| {
                sym.get(handle)
            })
        }

        pub unsafe fn init(&self, path: &str) -> bool {
            if self.init.load(Ordering::SeqCst) != 0 {
                return true
            }
            let name = CString::new(path).unwrap();
            let ptr = libc::dlopen(name.as_ptr() as *const c_char, libc::RTLD_LAZY);
            if ptr.is_null() {
                return false
            }
            match self.init.compare_and_swap(0, ptr as usize, Ordering::SeqCst) {
                0 => {}
                _ => { libc::dlclose(ptr); }
            }
            return true
        }

        unsafe fn load(&self) -> Option<*mut c_void> {
            match self.init.load(Ordering::SeqCst) {
                0 => None,
                n => Some(n as *mut c_void),
            }
        }
    }

    impl<T> Symbol<T> {
        unsafe fn get(&self, handle: *mut c_void) -> Option<&T> {
            assert_eq!(mem::size_of::<T>(), mem::size_of_val(&self.addr));
            if self.addr.load(Ordering::SeqCst) == 0 {
                self.addr.store(fetch(handle, self.name.as_ptr()), Ordering::SeqCst)
            }
            if self.addr.load(Ordering::SeqCst) == 1 {
                None
            } else {
                mem::transmute::<&AtomicUsize, Option<&T>>(&self.addr)
            }
        }
    }

    unsafe fn fetch(handle: *mut c_void, name: *const u8) -> usize {
        let ptr = libc::dlsym(handle, name as *const _);
        if ptr.is_null() {
            1
        } else {
            ptr as usize
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)