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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use DataTracked;
use error::*;
use FuncTracked;
use LibUnsafe;
use std::path::Path;

/// A shared library which which allows a user-provided ref-counting implementation to track its [Symbols](trait.Symbol.html).
/// The inner library will not be droped until all of teh ref-counts are dropped.
#[derive(Clone, Debug)]
pub struct LibTracked<TLib> {
    inner: TLib,
}

impl <TLib> LibTracked<TLib>
    where TLib: AsRef<LibUnsafe> + Clone + From<LibUnsafe> {
    /// Opens a shared library at the specified path.
    /// The path is used in conjunction with platform specific shared library search paths to determine which shared library will be opened. Search paths vary across environments and are not discussed in this documentation. The behavior of this function when it is called on the same path multiple times is platform specific. If you wish to obtain multiple copies of a library within the same code base in a platform generic way, you should load the symbol once in a [LibTracked](struct.LibTracked.html) like [LibArc](struct.LibArc.html), or [LibRc](struct.LibRc.html), and pass around copies of the [LibTracked](struct.LibTracked.html).
    ///
    /// # Errors
    /// A `LibraryOpen` error will be returned as a [SharedlibError](enum.SharedlibError.html) variant if there is a problem opening the shared library. For instance, this may happen if the shared library is not at the path specified.
    ///
    /// # Safety
    /// Opening a shared library may execute code within the shared library. Since it is impossible to guarantee that the code witin the shared library is safe, the call to new is unsafe.
    ///
    /// # Examples
    /// ``` no_run
    /// # use sharedlib::error::*;
    /// # use sharedlib::LibTracked;
    /// # use sharedlib::LibUnsafe;
    /// # use std::rc::Rc;
    /// type LibRc = LibTracked<Rc<LibUnsafe>>;
    /// # fn test() -> Result<()> {
    /// let lib = try!(unsafe { LibRc::new("examplelib.dll") });
    /// # Ok(())
    /// # }
    /// ```
    pub unsafe fn new<TPath>(path_to_lib: TPath) -> Result<Self>
        where TPath: AsRef<Path> {
        let lib_unsafe = try!(LibUnsafe::new(path_to_lib));
        let inner = TLib::from(lib_unsafe);
        let result =
            LibTracked {
                inner: inner
            };
        Ok(result)
    }

    /// Finds and returns a data symbol within the shared library.
    /// By passing in a null terminated string, an extra allocation may be avoided.
    ///
    /// # Errors
    /// A `LibraryFindSymbol` error will be returned as a [SharedlibError](enum.SharedlibError.html) variant if there is a problem finding the symbol. For instance, this may happen if the shared library does not contain the requested symbol.
    ///
    /// # Safety
    /// This function is not type safe so there is no guarntee that `T` is really the type of the symbol. Using a symbol as a `T` when the symbol is not really of type `T` causes undefined behavior.
    ///
    /// # Examples
    /// Finding data convieniently:
    ///
    /// ``` no_run
    /// # use sharedlib::DataTracked;
    /// # use sharedlib::error::*;
    /// # use sharedlib::LibTracked;
    /// # use sharedlib::LibUnsafe;
    /// # use sharedlib::Symbol;
    /// # use std::rc::Rc;
    /// type DataRc<T> = DataTracked<T, Rc<LibUnsafe>>;
    /// # type LibRc = LibTracked<Rc<LibUnsafe>>;
    /// # fn test() -> Result<()> {
    /// # let lib = try!(unsafe { LibRc::new("examplelib.dll") });
    /// let some_usize: DataRc<usize> = try!(unsafe { lib.find_data("some_usize") });
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// Finding data with maximum performance:
    ///
    /// ``` no_run
    /// # use sharedlib::DataTracked;
    /// # use sharedlib::error::*;
    /// # use sharedlib::LibTracked;
    /// # use sharedlib::LibUnsafe;
    /// # use sharedlib::Symbol;
    /// # use std::rc::Rc;
    /// type DataRc<T> = DataTracked<T, Rc<LibUnsafe>>;
    /// # type LibRc = LibTracked<Rc<LibUnsafe>>;
    /// # fn test() -> Result<()> {
    /// # let lib = try!(unsafe { LibRc::new("examplelib.dll") });
    /// let some_usize: DataRc<usize> = try!(unsafe { lib.find_data("some_usize\0") });
    /// # Ok(())
    /// # }
    /// ```
    pub unsafe fn find_data<T, TStr>(&self, symbol: TStr) -> Result<DataTracked<T, TLib>>
        where TStr: AsRef<str> {
        let lib = self.inner.as_ref();
        let symbol_ptr = try!(lib.find_data::<T, TStr>(symbol));
        let result = DataTracked::new(symbol_ptr, self.inner.clone());
        Ok(result)
    }

    /// Finds and returns a function symbol within the shared library.
    /// By passing in a null terminated string, an extra allocation may be avoided.
    ///
    /// # Errors
    /// A `LibraryFindSymbol` error will be returned as a [SharedlibError](enum.SharedlibError.html) variant if there is a problem finding the symbol. For instance, this may happen if the shared library does not contain the requested symbol.
    ///
    /// # Safety
    /// This function is not type safe so there is no guarntee that `T` is really the type of the symbol. Using a symbol as a `T` when the symbol is not really of type `T` causes undefined behavior.
    ///
    /// # Examples
    /// Finding a function convieniently:
    ///
    /// ``` no_run
    /// # use sharedlib::error::*;
    /// # use sharedlib::FuncTracked;
    /// # use sharedlib::LibTracked;
    /// # use sharedlib::LibUnsafe;
    /// # use sharedlib::Symbol;
    /// # use std::rc::Rc;
    /// type FuncRc<T> = FuncTracked<T, Rc<LibUnsafe>>;
    /// # type LibRc = LibTracked<Rc<LibUnsafe>>;
    /// # fn test() -> Result<()> {
    /// # let lib = try!(unsafe { LibRc::new("examplelib.dll") });
    /// let some_func: FuncRc<fn()> = try!(unsafe { lib.find_func("some_func") });
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// Finding a function with maximum performance:
    ///
    /// ``` no_run
    /// # use sharedlib::error::*;
    /// # use sharedlib::FuncTracked;
    /// # use sharedlib::LibTracked;
    /// # use sharedlib::LibUnsafe;
    /// # use sharedlib::Symbol;
    /// # use std::rc::Rc;
    /// type FuncRc<T> = FuncTracked<T, Rc<LibUnsafe>>;
    /// # type LibRc = LibTracked<Rc<LibUnsafe>>;
    /// # fn test() -> Result<()> {
    /// # let lib = try!(unsafe { LibRc::new("examplelib.dll") });
    /// let some_func: FuncRc<fn()> = try!(unsafe { lib.find_func("some_func\0") });
    /// # Ok(())
    /// # }
    /// ```
    pub unsafe fn find_func<T, TStr>(&self, symbol: TStr) -> Result<FuncTracked<T, TLib>>
        where T: Copy,
              TStr: AsRef<str> {
        let lib = self.inner.as_ref();
        let func = try!(lib.find_func::<T, TStr>(symbol));
        let result = FuncTracked::new(func, self.inner.clone());
        Ok(result)
    }
}