cr/
lib.rs

1extern crate cr_sys;
2
3use cr_sys::*;
4
5pub use cr_sys::cr_failure;
6pub use cr_sys::cr_op;
7
8#[derive(Debug)]
9pub struct Plugin<State> {
10    ctx: cr_plugin,
11    state: State,
12    bad_versions: std::collections::HashSet<u32>,
13}
14
15impl<State> Plugin<State> {
16    #[cfg(not(feature = "guest"))]
17    pub fn new(state: State, fullpath: &str) -> Box<Plugin<State>> {
18        let mut plugin = Box::new(Plugin {
19            ctx: cr_plugin::new(),
20            state: state,
21            bad_versions: std::collections::HashSet::new(),
22        });
23        // Store pointer to `Plugin` struct in `userdata` to be passed to the guest's `cr_main`
24        plugin.ctx.userdata = &mut (*plugin) as *mut _ as *mut ::std::os::raw::c_void;
25
26        let s_fullpath = std::ffi::CString::new(fullpath).unwrap();
27        unsafe { cr_plugin_load(&mut plugin.ctx, s_fullpath.as_ptr()) };
28
29        plugin
30    }
31
32    pub fn from_ctx(ctx: &mut cr_plugin) -> &mut Plugin<State> {
33        unsafe { &mut *(ctx.userdata as *mut Plugin<State>) }
34    }
35
36    #[cfg(not(feature = "guest"))]
37    pub fn set_temporary_path(&mut self, path: &str) {
38        let s_path = std::ffi::CString::new(path).unwrap();
39        unsafe { wrap_cr_set_temporary_path(&mut self.ctx, s_path.as_ptr()) };
40    }
41
42    #[cfg(not(feature = "guest"))]
43    pub fn update(&mut self, reload_check: bool) -> i32 {
44        // update plugin
45        let rc = unsafe { cr_plugin_update(&mut self.ctx, reload_check) };
46        // handle failures
47        match self.ctx.failure {
48            cr_failure::CR_NONE | cr_failure::CR_USER => (rc),
49            _ => {
50                let mut version = self.ctx.version;
51                // mark version as bad.
52                self.bad_versions.insert(version);
53                // rollback
54                while version > 0 && self.bad_versions.contains(&version) {
55                    version -= 1;
56                }
57                self.ctx.version = version;
58
59                -2
60            }
61        }
62    }
63
64    pub fn get_version(&self) -> u32 {
65        self.ctx.version
66    }
67
68    pub fn get_failure(&self) -> cr_failure {
69        self.ctx.failure
70    }
71
72    pub fn state(&self) -> &State {
73        &self.state
74    }
75
76    pub fn state_mut(&mut self) -> &mut State {
77        &mut self.state
78    }
79}
80
81#[cfg(not(feature = "guest"))]
82impl<State> Drop for Plugin<State> {
83    fn drop(&mut self) {
84        unsafe { cr_plugin_close(&mut self.ctx) }
85    }
86}
87
88#[macro_export]
89macro_rules! cr_main {
90    ($rust_cr_main:ident) => {
91        #[no_mangle]
92        pub fn cr_main(ctx: &mut ::cr_sys::cr_plugin, cr_op: cr::cr_op) -> ::std::os::raw::c_int {
93            // Must catch rust unwind from plugin.
94            match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
95                $rust_cr_main(::cr::Plugin::from_ctx(ctx), cr_op)
96            })) {
97                Ok(rc) => rc,
98                Err(_) => {
99                    // signal failure, host will rollback.
100                    ctx.failure = ::cr_sys::cr_failure::CR_SEGFAULT;
101                    -1
102                }
103            }
104        }
105    };
106}