summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs111
1 files changed, 54 insertions, 57 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 51b4459..00d0845 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,6 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
+#![cfg_attr(feature="nightly_tests", feature(c_variadic))]
+#![cfg_attr(feature="nightly_tests", feature(generic_associated_types))]
+//#![deny(unsafe_op_in_unsafe_fn)]
+
 //! Write hexchat plugins in Rust!
 //!
 //! This library provides safe API bindings for hexchat, but doesn't attempt to fix hexchat's own
@@ -189,9 +193,6 @@
  * -[ ] ???
  */
 
-#![cfg_attr(feature="nightly_tests", feature(c_variadic))]
-#![cfg_attr(feature="nightly_tests", feature(generic_associated_types))]
-
 #[macro_use]
 extern crate impl_trait;
 #[doc(hidden)]
@@ -574,41 +575,45 @@ impl_trait! {
     }
 }
 
-impl<'ph, 'f> HookHandle<'ph, 'f> where 'f: 'ph {
-    /// If this is a timer hook, returns whether the hook has expired.
-    ///
-    /// Otherwise, returns false.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use hexchat_unsafe_plugin::{HookHandle};
-    ///
-    /// /// Remove timers that have expired.
-    /// fn clean_up_timers(timers: &mut Vec<HookHandle<'_, '_>>) {
-    ///     timers.retain(|timer| {
-    ///         !timer.expired()
-    ///     });
-    /// }
-    /// ```
-    pub fn expired(&self) -> bool {
-        self.freed.get()
-    }
-}
-
-impl<'ph, 'f> Drop for HookHandle<'ph, 'f> where 'f: 'ph {
-    fn drop(&mut self) {
-        if self.freed.get() {
-            // already free'd.
-            return;
-        }
-        self.freed.set(true);
-        unsafe {
-            let b = ((*self.ph.as_raw()).hexchat_unhook)(self.ph, self.hh) as *mut HookUd<'f>;
-            // we assume b is not null. this should be safe.
-            // just drop it
-            drop(Rc::from_raw(b));
+impl_trait! {
+    impl<'ph, 'f> HookHandle<'ph, 'f> where 'f: 'ph {
+        /// If this is a timer hook, returns whether the hook has expired.
+        ///
+        /// Otherwise, returns false.
+        ///
+        /// # Examples
+        ///
+        /// ```no_run
+        /// use hexchat_unsafe_plugin::{HookHandle};
+        ///
+        /// /// Remove timers that have expired.
+        /// fn clean_up_timers(timers: &mut Vec<HookHandle<'_, '_>>) {
+        ///     timers.retain(|timer| {
+        ///         !timer.expired()
+        ///     });
+        /// }
+        /// ```
+        pub fn expired(&self) -> bool {
+            self.freed.get()
+        }
+        
+        impl trait Drop {
+            fn drop(&mut self) {
+                if self.freed.get() {
+                    // already free'd.
+                    return;
+                }
+                self.freed.set(true);
+                unsafe {
+                    let b = ((*self.ph.as_raw()).hexchat_unhook)(self.ph, self.hh) as *mut HookUd<'f>;
+                    // we assume b is not null. this should be safe.
+                    // just drop it
+                    drop(Rc::from_raw(b));
+                }
+            }
         }
+
+        impl trait RefUnwindSafe {}
     }
 }
 
@@ -676,7 +681,7 @@ unsafe fn call_hook_protected<'ph, F>(
     ph: MutLtPtr<'ph, RawPh<'ph>>,
     f: F
 ) -> Eat
-where F: FnOnce() -> Eat + UnwindSafe{
+where F: FnOnce() -> Eat + UnwindSafe {
     match catch_unwind(f) {
         Result::Ok(v @ _) => v,
         Result::Err(e @ _) => {
@@ -919,7 +924,7 @@ impl<'ph> PluginHandle<'ph> {
     ///     ]
     /// }
     /// ```
-    pub fn hook_command<'f, F>(&self, cmd: &str, pri: i32, help: Option<&str>, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, WordEol) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_command<'f, F>(&self, cmd: &str, pri: i32, help: Option<&str>, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, WordEol<'_>) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         assert!(self.guiplugin.is_null(), "PluginEntryHandle can't have hooks");
         unsafe extern "C" fn callback(word: *const *const c_char, word_eol: *const *const c_char, ud: *mut c_void) -> c_int {
             let f: Rc<HookUd> = rc_clone_from_raw(ud as *const HookUd);
@@ -970,12 +975,12 @@ impl<'ph> PluginHandle<'ph> {
     ///     ]
     /// }
     /// ```
-    pub fn hook_server<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, WordEol) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_server<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, WordEol<'_>) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         assert!(self.guiplugin.is_null(), "PluginEntryHandle can't have hooks");
         self.hook_server_attrs(cmd, pri, move |ph, w, we, _| cb(ph, w, we))
     }
     /// Sets a server hook, with attributes.
-    pub fn hook_server_attrs<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, WordEol, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_server_attrs<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, WordEol<'_>, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         assert!(self.guiplugin.is_null(), "PluginEntryHandle can't have hooks");
         unsafe extern "C" fn callback(word: *const *const c_char, word_eol: *const *const c_char, attrs: *const RawAttrs, ud: *mut c_void) -> c_int {
             let f: Rc<HookUd> = rc_clone_from_raw(ud as *const HookUd);
@@ -1028,7 +1033,7 @@ impl<'ph> PluginHandle<'ph> {
     ///     ]
     /// }
     /// ```
-    pub fn hook_print<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_print<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         assert!(self.guiplugin.is_null(), "PluginEntryHandle can't have hooks");
         // hmm, is there any way to avoid this code duplication?
         // hook_print is special because dummy prints (keypresses, Close Context) are handled
@@ -1092,7 +1097,7 @@ impl<'ph> PluginHandle<'ph> {
     ///     ]
     /// }
     /// ```
-    pub fn hook_print_attrs<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_print_attrs<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         assert!(self.guiplugin.is_null(), "PluginEntryHandle can't have hooks");
         unsafe extern "C" fn callback(word: *const *const c_char, attrs: *const RawAttrs, ud: *mut c_void) -> c_int {
             let f: Rc<HookUd> = rc_clone_from_raw(ud as *const HookUd);
@@ -1938,31 +1943,31 @@ impl<'a, 'ph: 'a> ValidContext<'a, 'ph> {
     /// Sets a command hook.
     ///
     /// See [`PluginHandle::hook_command`].
-    pub fn hook_command<'f, F>(&self, cmd: &str, pri: i32, help: Option<&str>, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, WordEol) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_command<'f, F>(&self, cmd: &str, pri: i32, help: Option<&str>, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, WordEol<'_>) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         self.ph.hook_command(cmd, pri, help, cb)
     }
     /// Sets a server hook.
     ///
     /// See [`PluginHandle::hook_server`].
-    pub fn hook_server<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, WordEol) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_server<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, WordEol<'_>) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         self.ph.hook_server(cmd, pri, cb)
     }
     /// Sets a server hook with attributes.
     ///
     /// See [`PluginHandle::hook_server_attrs`].
-    pub fn hook_server_attrs<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, WordEol, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_server_attrs<'f, F>(&self, cmd: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, WordEol<'_>, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         self.ph.hook_server_attrs(cmd, pri, cb)
     }
     /// Sets a print hook.
     ///
     /// See [`PluginHandle::hook_print`].
-    pub fn hook_print<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_print<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         self.ph.hook_print(name, pri, cb)
     }
     /// Sets a print hook with attributes.
     ///
     /// See [`PluginHandle::hook_print_attrs`].
-    pub fn hook_print_attrs<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
+    pub fn hook_print_attrs<'f, F>(&self, name: &str, pri: i32, cb: F) -> HookHandle<'ph, 'f> where F: Fn(&mut PluginHandle<'ph>, Word<'_>, EventAttrs) -> Eat + 'f + RefUnwindSafe, 'f: 'ph {
         self.ph.hook_print_attrs(name, pri, cb)
     }
     /// Sets a timer hook.
@@ -2027,20 +2032,12 @@ impl<'a, 'ph: 'a> ValidContext<'a, 'ph> {
 // ******* //
 
 // Type aliases, used for safety type checking.
-// /// Userdata type used by a command hook.
+/// Userdata type used by a hook
 // We actually do want RefUnwindSafe. This function may be called multiple times, and it's not
 // automatically invalidated if it panics, so it may be called again after it panics. If you need
 // mutable state, std provides std::sync::Mutex which has poisoning. Other interior mutability with
 // poisoning could also be used. std doesn't have anything for single-threaded performance (yet),
 // but hexchat isn't particularly performance-critical.
-// type CommandHookUd = Box<dyn Fn(Word, WordEol) -> Eat + std::panic::RefUnwindSafe>;
-// /// Userdata type used by a server hook.
-// type ServerHookUd = Box<dyn Fn(Word, WordEol, EventAttrs) -> Eat + std::panic::RefUnwindSafe>;
-// /// Userdata type used by a print hook.
-// type PrintHookUd = Box<dyn Fn(Word, EventAttrs) -> Eat + std::panic::RefUnwindSafe>;
-// /// Userdata type used by a timer hook.
-// type TimerHookUd = Box<dyn Fn() -> bool + std::panic::RefUnwindSafe>;
-/// Userdata type used by a hook
 type HookUd<'f> = Box<dyn Fn(*const *const c_char, *const *const c_char, *const RawAttrs) -> Eat + RefUnwindSafe + 'f>;
 /// Contexts
 type Contexts = Rc<AssertUnwindSafe<RefCell<HashSet<Rc<*const internals::HexchatContext>>>>>;