summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2022-12-12 10:43:53 -0300
committerSoniEx2 <endermoneymod@gmail.com>2022-12-12 10:43:53 -0300
commitc12eb456be7cf5e183ef2b34812060ee2ed08a8a (patch)
tree3d622f8baa0f2d8657cb422d3c7b53bd1ae6b8c9 /src
parent43a79374e0d9592ccd709082f23c63da5a83d609 (diff)
Initial work on using LtPtr + selfref update
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs103
-rw-r--r--src/mock/mod.rs111
-rw-r--r--src/pluginfo.rs39
3 files changed, 137 insertions, 116 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 00d0845..0ef9354 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,8 +15,7 @@
 // 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)]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 //! Write hexchat plugins in Rust!
 //!
@@ -257,6 +256,9 @@ pub use libc::{c_char, c_int, c_void, time_t};
 #[doc(hidden)]
 pub use ltptr::MutLtPtr;
 
+use ltptr::ConstLtPtr;
+use ltptr::FromLtPtr;
+
 // ****** //
 // PUBLIC //
 // ****** //
@@ -2213,12 +2215,16 @@ fn check_pluginpref_var(var: impl Into<Vec<u8>>) -> Result<CString, PluginPrefEr
 // *********************** //
 
 #[doc(hidden)]
-pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>,
-                                     plugin_name: *mut *const c_char,
-                                     plugin_desc: *mut *const c_char,
-                                     plugin_version: *mut *const c_char,
-                                     arg: *const c_char) -> c_int
-                                     where T: Plugin<'ph> + Default + 'ph {
+pub unsafe fn hexchat_plugin_init<'ph, T>(
+    ph: MutLtPtr<'ph, RawPh<'ph>>,
+    plugin_name: *mut *const c_char,
+    plugin_desc: *mut *const c_char,
+    plugin_version: *mut *const c_char,
+    arg: ConstLtPtr<'_, c_char>,
+) -> c_int
+where
+    T: Plugin<'ph> + Default + 'ph,
+{
     if ph.as_raw().is_null() || plugin_name.is_null() || plugin_desc.is_null() || plugin_version.is_null() {
         // we can't really do anything here. just hope this doesn't panic.
         eprintln!("hexchat_plugin_init called with a null pointer that shouldn't be null - broken hexchat");
@@ -2266,7 +2272,7 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>,
     }
     // we got banned from an IRC network over the following line of code.
     hexchat_print_str(ph, "hexchat-unsafe-plugin  Copyright (C) 2018, 2021, 2022 Soni L.  GPL-3.0-or-later  This software is made with love by a queer trans person.", false);
-    let mut pluginfo = if let Some(pluginfo) = PluginInfo::new(plugin_name, plugin_desc, plugin_version) {
+    let mut pluginfo = if let Some(pluginfo) = unsafe { PluginInfo::new(plugin_name, plugin_desc, plugin_version) } {
         pluginfo
     } else {
         return 0;
@@ -2287,16 +2293,18 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>,
             });
             let contexts = Rc::clone(&pluginhandle.contexts);
             let mut plug = Box::pin(T::default());
-            if plug.as_mut().init(&mut pluginhandle, &filename, if !arg.is_null() { Some(CStr::from_ptr(arg).to_str().expect("arg not valid utf-8 - broken hexchat")) } else { None }) {
-                if !(pluginfo.name.is_null() || pluginfo.desc.is_null() || pluginfo.vers.is_null()) {
+            if plug.as_mut().init(&mut pluginhandle, &filename, if !arg.is_null() { Some(unsafe { CStr::from_lt_ptr(arg) }.to_str().expect("arg not valid utf-8 - broken hexchat")) } else { None }) {
+                if unsafe { pluginfo.is_registered() } {
                     Some(Box::new(PhUserdata { plug, pluginfo, contexts, _context_hook: context_hook }))
                 } else {
                     // TODO log: forgot to call register
                     None
                 }
             } else {
-                if !(pluginfo.name.is_null() || pluginfo.desc.is_null() || pluginfo.vers.is_null()) {
-                    pluginfo.drop_info()
+                if unsafe { pluginfo.is_registered() } {
+                    unsafe {
+                        pluginfo.drop_info()
+                    }
                 }
                 None
             }
@@ -2304,12 +2312,16 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>,
     };
     match r {
         Result::Ok(Option::Some(plug @ _)) => {
-            put_userdata(ph, plug);
+            unsafe {
+                put_userdata(ph, plug);
+            }
             1
         },
         r @ _ => {
             if let Err(e) = r {
-                log_panic(ph, e);
+                unsafe {
+                    log_panic(ph, e);
+                }
             }
             0
         },
@@ -2317,22 +2329,24 @@ pub unsafe fn hexchat_plugin_init<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>,
 }
 
 #[doc(hidden)]
-pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<'ph>>) -> c_int where T: Plugin<'ph> {
+pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T: Plugin<'ph>>(
+    ph: MutLtPtr<'ph, RawPh<'ph>>,
+) -> c_int {
     let mut safe_to_unload = 1;
     // plugin_handle should never be null, but just in case.
-    if !ph.as_raw().is_null() {
+    if !unsafe { ph.as_raw() }.is_null() {
         // userdata should also never be null.
-        if !(*ph.as_raw()).userdata.is_null() {
+        if !unsafe { (*ph.as_raw()).userdata }.is_null() {
             {
                 let mut info: Option<PluginInfo> = None;
                 {
                     let ausph = AssertUnwindSafe(ph);
                     let mut ausinfo = AssertUnwindSafe(&mut info);
                     safe_to_unload = match catch_unwind(move || {
-                        let mut userdata = pop_userdata(*ausph);
+                        let mut userdata = unsafe { pop_userdata(*ausph) };
                         let pluginfo = userdata.pluginfo;
                         if let Err(e) = catch_unwind(AssertUnwindSafe(|| {
-                            userdata.plug.as_mut().deinit(&mut {
+                            userdata.plug.as_mut().deinit(&mut unsafe {
                                 PluginHandle::new(
                                     *ausph,
                                     pluginfo,
@@ -2343,7 +2357,9 @@ pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<'
                             // panics in deinit may be retried.
                             // however, one may need to close hexchat if that
                             // happens.
-                            put_userdata(*ausph, userdata);
+                            unsafe {
+                                put_userdata(*ausph, userdata);
+                            }
                             std::panic::resume_unwind(e);
                         }
                         **ausinfo = Some(pluginfo);
@@ -2351,18 +2367,28 @@ pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<'
                     }) {
                         Ok(_) => 1,
                         Err(e) => {
-                            log_panic(ph, e);
+                            unsafe {
+                                log_panic(ph, e);
+                            }
                             0
                         }
                     };
                 }
                 if let Some(mut info) = info {
-                    info.drop_info();
+                    unsafe {
+                        info.drop_info();
+                    }
                     safe_to_unload = 1;
                 }
             }
         } else {
-            hexchat_print_str(ph, "plugin userdata was null, broken hexchat-unsafe-plugin?", false);
+            unsafe {
+                hexchat_print_str(
+                    ph,
+                    "plugin userdata was null, broken hexchat-unsafe-plugin?",
+                    false
+                );
+            }
         }
     } else {
         // we are once again hoping for the best here.
@@ -2377,18 +2403,29 @@ pub unsafe extern "C" fn hexchat_plugin_deinit<'ph, T>(ph: MutLtPtr<'ph, RawPh<'
 macro_rules! hexchat_plugin {
     ($l:lifetime, $t:ty) => {
         #[no_mangle]
-        pub unsafe extern "C" fn hexchat_plugin_init<$l>(plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>,
-                                              plugin_name: *mut *const $crate::c_char,
-                                              plugin_desc: *mut *const $crate::c_char,
-                                              plugin_version: *mut *const $crate::c_char,
-                                              arg: *const $crate::c_char) -> $crate::c_int {
-            $crate::hexchat_plugin_init::<$l, $t>(plugin_handle, plugin_name, plugin_desc, plugin_version, arg)
+        pub unsafe extern "C" fn hexchat_plugin_init<$l>(
+            plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>,
+            plugin_name: *mut *const $crate::c_char,
+            plugin_desc: *mut *const $crate::c_char,
+            plugin_version: *mut *const $crate::c_char,
+            arg: *const $crate::c_char,
+        ) -> $crate::c_int {
+            $crate::hexchat_plugin_init::<$l, $t>(
+                plugin_handle,
+                plugin_name,
+                plugin_desc,
+                plugin_version,
+                arg
+            )
         }
         #[no_mangle]
-        pub unsafe extern "C" fn hexchat_plugin_deinit<$l>(plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>) -> $crate::c_int {
+        pub unsafe extern "C" fn hexchat_plugin_deinit<$l>(
+            plugin_handle: $crate::MutLtPtr<$l, $crate::RawPh<$l>>,
+        ) -> $crate::c_int {
             $crate::hexchat_plugin_deinit::<$l, $t>(plugin_handle)
         }
-        // unlike what the documentation states, there's no need to define hexchat_plugin_get_info.
-        // so we don't. it'd be impossible to make it work well with rust anyway.
+        // unlike what the documentation states, there's no need to define
+        // hexchat_plugin_get_info. so we don't. it'd be impossible to make it
+        // work well with rust anyway.
     };
 }
diff --git a/src/mock/mod.rs b/src/mock/mod.rs
index 0e4ba03..b21c451 100644
--- a/src/mock/mod.rs
+++ b/src/mock/mod.rs
@@ -55,7 +55,7 @@ use ::libc::{c_char, c_int};
 
 use ::ltptr::*;
 
-use ::selfref::{Holder, NewWith, OperateIn, opaque};
+use ::selfref::{Holder, opaque};
 
 struct Context {
 }
@@ -401,19 +401,15 @@ unsafe extern "C" fn hexchat_event_attrs_free<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>,
 impl<'env> PluginEnvironment<'env> {
     /// Creates a new plugin environment.
     pub fn new() -> Holder<'static, PluginEnvironmentK> {
-        struct NewEnv;
-        impl<'k> NewWith<'k, PluginEnvironmentK> for NewEnv {
-            fn new_with<'env>(self) -> PluginEnvironment<'env> {
-                PluginEnvironment {
-                    plugins: Default::default(),
-                    hooks: Default::default(),
-                    extra_hooks: Default::default(),
-                    depth: Default::default(),
-                    contexts: Default::default(),
-                }
+        Holder::<'_, PluginEnvironmentK>::new_with(|builder| builder.build(
+            PluginEnvironment {
+                plugins: Default::default(),
+                hooks: Default::default(),
+                extra_hooks: Default::default(),
+                depth: Default::default(),
+                contexts: Default::default(),
             }
-        }
-        Holder::new_with(NewEnv)
+        ))
     }
 
     /// Loads a plugin.
@@ -426,38 +422,23 @@ impl<'env> PluginEnvironment<'env> {
         // add the plugin
         self.plugins.borrow_mut().push(plug.clone());
 
-        struct MockPluginInit<'arg, T> {
-            arg: Option<&'arg CStr>,
-            _p: PhantomData<T>
-        }
-        impl<'k, 'env: 'k, 'arg, T> OperateIn<'k, MockPluginK<'env>>
-        for MockPluginInit<'arg, T>
-        where T: PluginFactory {
-            type Out = bool;
-            fn operate_in<'ph>(
-                self,
-                ph: Pin<&'ph UnsafeCell<MockPlugin<'ph, 'env>>>,
-            ) -> bool where 'k: 'ph {
-                let ptr = ph.get();
-                let arg = self.arg;
-                unsafe {
-                    // setup deinit function
-                    (*ptr).deinit = Some(
-                        crate::hexchat_plugin_deinit::<'ph, T::Plugin<'ph>>
-                    );
-                    crate::hexchat_plugin_init::<'ph, T::Plugin<'ph>>(
-                        MutLtPtr::from_raw(ptr as *mut _),
-                        ptr::addr_of_mut!((*ptr).plugin_name),
-                        ptr::addr_of_mut!((*ptr).plugin_desc),
-                        ptr::addr_of_mut!((*ptr).plugin_vers),
-                        arg.map(|arg| arg.as_ptr()).unwrap_or(ptr::null()),
-                    ) != 0
-                }
+        if plug.as_ref().operate_in(|ph| {
+            let ptr = ph.get();
+            unsafe {
+                // setup deinit function
+                (*ptr).deinit = Some(
+                    crate::hexchat_plugin_deinit::<'_, T::Plugin<'_>>
+                );
+                crate::hexchat_plugin_init::<T::Plugin<'_>>(
+                    MutLtPtr::from_raw(ptr as *mut _),
+                    ptr::addr_of_mut!((*ptr).plugin_name),
+                    ptr::addr_of_mut!((*ptr).plugin_desc),
+                    ptr::addr_of_mut!((*ptr).plugin_vers),
+                    ConstLtPtr::from_raw(
+                        arg.map(|arg| arg.as_ptr()).unwrap_or(ptr::null())
+                    ),
+                ) != 0
             }
-        }
-        if plug.as_ref().operate_in(MockPluginInit::<T> {
-            arg,
-            _p: PhantomData,
         }) {
             Ok(())
         } else {
@@ -482,17 +463,8 @@ impl<'ph, 'env> MockPlugin<'ph, 'env> {
         env: Pin<&'env PluginEnvironment<'env>>,
         filename: CString,
     ) -> Pin<Rc<Holder<'env, MockPluginK<'env>>>> {
-        struct MockPluginNewWith<'env> {
-            filename: CString,
-            env: Pin<&'env PluginEnvironment<'env>>
-        }
-        impl<'k, 'env> NewWith<'k, MockPluginK<'env>>
-        for MockPluginNewWith<'env>
-        where 'env: 'k {
-            fn new_with<'ph>(self) -> UnsafeCell<MockPlugin<'ph, 'env>>
-            where 'k: 'ph {
-                let filename = self.filename;
-                let env = self.env;
+        let plug = Rc::pin(Holder::<'_, MockPluginK<'env>>::new_with(
+            |builder| builder.build({
                 UnsafeCell::new(MockPlugin {
                     methods: Ph {
                         hexchat_hook_command,
@@ -547,28 +519,15 @@ impl<'ph, 'env> MockPlugin<'ph, 'env> {
                     deinit: None,
                     context: None,
                 })
+            })
+        ));
+        plug.as_ref().operate_in(|ph| {
+            let ptr = ph.get();
+            unsafe {
+                // initialize plugin_name from filename(!)
+                (*ptr).plugin_name = (*ptr).filename.as_ptr();
             }
-        }
-        let plug = Rc::pin(Holder::new_with(MockPluginNewWith {
-            filename,
-            env,
-        }));
-        struct MockPluginPreInit;
-        impl<'k, 'env: 'k> OperateIn<'k, MockPluginK<'env>>
-        for MockPluginPreInit {
-            type Out = ();
-            fn operate_in<'ph>(
-                self,
-                ph: Pin<&'ph UnsafeCell<MockPlugin<'ph, 'env>>>,
-            ) where 'k: 'ph {
-                let ptr = ph.get();
-                unsafe {
-                    // initialize plugin_name from filename(!)
-                    (*ptr).plugin_name = (*ptr).filename.as_ptr();
-                }
-            }
-        }
-        plug.as_ref().operate_in(MockPluginPreInit);
+        });
         plug
     }
 }
diff --git a/src/pluginfo.rs b/src/pluginfo.rs
index 195aa26..507751a 100644
--- a/src/pluginfo.rs
+++ b/src/pluginfo.rs
@@ -1,5 +1,5 @@
 // This file is part of Hexchat Plugin API Bindings for Rust
-// Copyright (C) 2018, 2021 Soni L.
+// Copyright (C) 2018, 2021, 2022 Soni L.
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as
@@ -36,13 +36,19 @@ impl PluginInfo {
     ///
     /// # Safety
     ///
-    /// This function is unsafe, as it can't guarantee the validity of its arguments. It does more
-    /// checking than `new_unchecked` however.
+    /// This function is unsafe, as it can't guarantee the validity of its
+    /// arguments. It does more checking than `new_unchecked` however.
+    ///
+    /// See `new_unchecked` for the full requirements.
     ///
     /// # Panics
     ///
     /// This function explicitly doesn't panic. Call unwrap() on the result instead.
-    pub unsafe fn new(name: *mut *const libc::c_char, desc: *mut *const libc::c_char, vers: *mut *const libc::c_char) -> Option<PluginInfo> {
+    pub unsafe fn new(
+        name: *mut *const libc::c_char,
+        desc: *mut *const libc::c_char,
+        vers: *mut *const libc::c_char,
+    ) -> Option<PluginInfo> {
         if name.is_null() || desc.is_null() || vers.is_null() || name == desc || desc == vers || name == vers {
             None
         } else {
@@ -54,9 +60,14 @@ impl PluginInfo {
     ///
     /// # Safety
     ///
-    /// This function is unsafe, as it doesn't check the validity of the arguments. You're expected
-    /// to only pass in non-aliased non-null pointers. Use new if unsure.
-    pub unsafe fn new_unchecked(name: *mut *const libc::c_char, desc: *mut *const libc::c_char, vers: *mut *const libc::c_char) -> PluginInfo {
+    /// This function is unsafe, as it doesn't check the validity of the
+    /// arguments. You're expected to only pass in non-aliased non-null valid
+    /// pointers. Use `new` if unsure.
+    pub unsafe fn new_unchecked(
+        name: *mut *const libc::c_char,
+        desc: *mut *const libc::c_char,
+        vers: *mut *const libc::c_char,
+    ) -> PluginInfo {
         PluginInfo {
             name, desc, vers
         }
@@ -84,5 +95,19 @@ impl PluginInfo {
             *self.vers = cstr(EMPTY_CSTRING_DATA);
         }
     }
+
+    /// Returns whether this `PluginInfo` has been registered.
+    ///
+    /// # Safety
+    ///
+    /// We cannot currently guarantee the validity of the pointers contained in
+    /// here.
+    pub unsafe fn is_registered(&self) -> bool {
+        ![
+            self.name,
+            self.desc,
+            self.vers,
+        ].into_iter().any(|meta| unsafe { *meta }.is_null())
+    }
 }