dlopen/wrapper/optional.rs
1use super::super::raw::Library;
2use super::super::Error;
3use std::ops::{Deref, DerefMut};
4use super::api::WrapperApi;
5use std::ffi::OsStr;
6
7/**
8Container for a library handle and both obligatory and optional APIs inside one structure.
9
10A common problem with dynamic link libraries is that they often have different versions and some
11of those versions have broader API than others. This structure allows you to use two APIs at the
12same time - one obligatory and one optional. If symbols of the optional API are found in the
13library, the optional API gets loaded. Otherwise the `optional()` method will return `None`.
14
15#Example
16
17```no_run
18#[macro_use]
19extern crate dlopen_derive;
20extern crate dlopen;
21use dlopen::wrapper::{OptionalContainer, WrapperApi};
22
23#[derive(WrapperApi)]
24struct Obligatory<'a> {
25 do_something: extern "C" fn(),
26 global_count: &'a mut u32,
27}
28
29#[derive(WrapperApi)]
30struct Optional{
31 add_one: unsafe extern "C" fn (arg: i32) -> i32,
32 c_string: * const u8
33}
34
35fn main () {
36 let mut container: OptionalContainer<Obligatory, Optional> = unsafe {
37 OptionalContainer::load("libexample.dylib")
38 }.unwrap();
39 container.do_something();
40 *container.global_count_mut() += 1;
41
42 match container.optional(){
43 &Some(ref opt) => {
44 let _result = unsafe { opt.add_one(5) };
45 println!("First byte of C string is {}", unsafe{*opt.c_string});
46 },
47 &None => println!("The optional API was not loaded!")
48 }
49}
50```
51
52**Note:** For more complex cases (multiple versions of API) you can use
53[`WrapperMultiApi`](./trait.WrapperMultiApi.html).
54*/
55pub struct OptionalContainer<Api, Optional>
56where
57 Api: WrapperApi,
58 Optional: WrapperApi,
59{
60 #[allow(dead_code)]
61 //this is not dead code because destructor of Library deallocates the library
62 lib: Library,
63 api: Api,
64 optional: Option<Optional>,
65}
66
67impl<Api, Optional> OptionalContainer<Api, Optional>
68where
69 Api: WrapperApi,
70 Optional: WrapperApi,
71{
72 ///Opens the library using provided file name or path and loads all symbols (including optional
73 ///if it is possible).
74 pub unsafe fn load<S>(name: S) -> Result<OptionalContainer<Api, Optional>, Error>
75 where
76 S: AsRef<OsStr>,
77 {
78 let lib = Library::open(name)?;
79 let api = Api::load(&lib)?;
80 let optional = Optional::load(&lib).ok();
81 Ok(Self { lib, api, optional })
82 }
83
84 ///Load all symbols (including optional if it is possible) from the
85 ///program itself.
86 ///
87 /// This allows a shared library to load symbols of the program it was
88 /// loaded into.
89 pub unsafe fn load_self() -> Result<OptionalContainer<Api, Optional>, Error> {
90 let lib = Library::open_self()?;
91 let api = Api::load(&lib)?;
92 let optional = Optional::load(&lib).ok();
93 Ok(Self { lib, api, optional })
94 }
95
96 ///Gives access to the optional API - constant version.
97 pub fn optional(&self) -> &Option<Optional> {
98 return &self.optional;
99 }
100
101 ///Gives access to the optional API - constant version.
102 pub fn optional_mut(&mut self) -> &Option<Optional> {
103 return &mut self.optional;
104 }
105}
106
107impl<Api, Optional> Deref for OptionalContainer<Api, Optional>
108where
109 Api: WrapperApi,
110 Optional: WrapperApi,
111{
112 type Target = Api;
113 fn deref(&self) -> &Api {
114 &self.api
115 }
116}
117
118impl<Api, Optional> DerefMut for OptionalContainer<Api, Optional>
119where
120 Api: WrapperApi,
121 Optional: WrapperApi,
122{
123 fn deref_mut(&mut self) -> &mut Api {
124 &mut self.api
125 }
126}