diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2022-04-26 09:14:09 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2022-04-26 09:14:09 -0300 |
commit | 25d5d6f4e9ed901d284633691941c52c8556d17c (patch) | |
tree | c353158113eba06e67e37a77caf337a8bf1c270e | |
parent | 83db3d819b7402b4f3c6ca023ddfea6204fae4b4 (diff) |
Project ValidContext to Fields<'_, '_, Contexts>
-rw-r--r-- | src/extra_tests.rs | 20 | ||||
-rw-r--r-- | src/lib.rs | 63 | ||||
-rw-r--r-- | src/list.rs | 18 |
3 files changed, 76 insertions, 25 deletions
diff --git a/src/extra_tests.rs b/src/extra_tests.rs index 8aed5a9..b64cc22 100644 --- a/src/extra_tests.rs +++ b/src/extra_tests.rs @@ -4,7 +4,7 @@ //! use std::mem; //! use hexchat_unsafe_plugin::PluginHandle; //! -//! fn prepoop_your_pants_pluginhandle<'ph>(ph: &mut PluginHandle<'ph>) { +//! fn prepoop_your_pants_pluginhandle(ph: &mut PluginHandle<'_>) { //! let temporary: String = "Hello, world!".to_string(); //! let hook = ph.hook_timer(0, |_| { //! println!("{}", temporary); @@ -12,3 +12,21 @@ //! }); //! } //! ``` +//! +//! ```compile_fail +//! use hexchat_unsafe_plugin::list::Contexts; +//! use hexchat_unsafe_plugin::PluginHandle; +//! +//! fn unsound(ph: &mut PluginHandle<'_>) { +//! ph.ensure_valid_context(|mut ph| { +//! let mut list = ph.list(&Contexts); +//! let context = list.next().unwrap(); +//! write!(ph, "{}", context.name().unwrap()); +//! std::mem::forget(list); +//! write!(ph, "{}", context.name().unwrap()); +//! let ctx = context.context(); +//! ph.set_context(&ctx); +//! write!(ph, "{}", context.name().unwrap()); +//! }) +//! } +//! ``` diff --git a/src/lib.rs b/src/lib.rs index f0ee389..52d3d23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -150,7 +150,7 @@ * -[ ] win_ptr * -[x] hexchat_get_prefs * -[x] hexchat_list_get - * -[ ] hexchat_list_fields + * -[x] ~~hexchat_list_fields~~ not available. no alternative provided. * -[x] hexchat_list_next * -[x] hexchat_list_str * -[x] hexchat_list_int @@ -338,16 +338,21 @@ pub enum PrefValue { } mod valid_context { + use std::ptr; + + use crate::list; use crate::PluginHandle; - /// A PluginHandle operating on a valid context. + /// A `PluginHandle` operating on a valid context. /// - /// This mechanism attempts to reduce the likelihood of segfaults in - /// hexchat code. + /// Methods that require a valid plugin context are only available through + /// this. Methods that may invalidate the plugin context also consume this. /// /// See also [`PluginHandle::ensure_valid_context`]. pub struct ValidContext<'a, 'ph: 'a> { - pub(crate) ph: &'a mut PluginHandle<'ph>, + // NOTE: NOT mut(!) + pub(crate) ph: &'a PluginHandle<'ph>, + fields: list::Fields<'a, 'ph, list::Contexts>, _hidden: (), } @@ -358,7 +363,29 @@ mod valid_context { /// /// The PluginHandle's context must be valid. pub(crate) unsafe fn new(ph: &'a mut PluginHandle<'ph>) -> Self { - Self { ph, _hidden: () } + static CONTEXTS: list::Contexts = list::Contexts; + Self { + ph: &*ph, + fields: list::Fields { + context: &*ph, + // this isn't actually documented but hexchat explicitly + // supports passing in NULL for the current context. + // this gives access to some properties that aren't + // available through get_info. + list: ptr::null_mut(), + _t: &CONTEXTS, + id: 0, + valid: Default::default(), + }, + _hidden: (), + } + } + } + + impl<'a, 'ph: 'a> std::ops::Deref for ValidContext<'a, 'ph> { + type Target = list::Fields<'a, 'ph, list::Contexts>; + fn deref(&self) -> &Self::Target { + &self.fields } } } @@ -749,13 +776,8 @@ impl<'ph> PluginHandle<'ph> { /// /// Returns `true` if the context is valid, `false` otherwise. pub fn set_context(&mut self, ctx: &Context<'ph>) -> bool { - if let Some(ctx) = ctx.ctx.upgrade() { - unsafe { - ph_call!(hexchat_set_context(self, *ctx)) != 0 - } - } else { - false - } + // we could've made this &self but we didn't. avoid breaking API. + self.set_context_internal(ctx) } /// Do something in a valid context. @@ -1278,6 +1300,17 @@ impl<'ph> PluginHandle<'ph> { ctx.map(|ctx| wrap_context(self, ctx)) } } + + /// Same as `set_context` but it takes `&self`. + fn set_context_internal(&self, ctx: &Context<'ph>) -> bool { + if let Some(ctx) = ctx.ctx.upgrade() { + unsafe { + ph_call!(hexchat_set_context(self, *ctx)) != 0 + } + } else { + false + } + } } impl<'a> EventAttrs<'a> { @@ -1544,7 +1577,7 @@ impl<'a, 'ph: 'a> ValidContext<'a, 'ph> { ph_call!(hexchat_list_get(ph, list.as_ptr())) }; list::Entries { - context: self, + context: self.ph, list: list, t: t, valid: Default::default(), @@ -1575,7 +1608,7 @@ impl<'a, 'ph: 'a> ValidContext<'a, 'ph> { // context. // So either way we're still in a valid context when this returns. pub fn set_context(&mut self, ctx: &Context<'ph>) -> bool { - self.ph.set_context(ctx) + self.ph.set_context_internal(ctx) } /// Prints to the hexchat buffer. diff --git a/src/list.rs b/src/list.rs index 04af87a..891fdd6 100644 --- a/src/list.rs +++ b/src/list.rs @@ -53,7 +53,7 @@ pub struct Users; /// Entries. pub struct Entries<'a, 'ph, T> { - pub(crate) context: &'a crate::ValidContext<'a, 'ph>, + pub(crate) context: &'a crate::PluginHandle<'ph>, pub(crate) list: *mut crate::internals::HexchatList, pub(crate) t: &'a T, pub(crate) valid: Rc<Cell<usize>>, @@ -61,11 +61,11 @@ pub struct Entries<'a, 'ph, T> { /// Fields. pub struct Fields<'a, 'ph, T> { - context: &'a crate::ValidContext<'a, 'ph>, - list: *mut crate::internals::HexchatList, - _t: &'a T, - id: usize, - valid: Rc<Cell<usize>>, + pub context: &'a crate::PluginHandle<'ph>, + pub list: *mut crate::internals::HexchatList, + pub _t: &'a T, + pub id: usize, + pub valid: Rc<Cell<usize>>, } // impls @@ -98,7 +98,7 @@ impl List for Users { impl<'a, 'ph, T> Drop for Entries<'a, 'ph, T> { fn drop(&mut self) { - let ph = &self.context.ph; + let ph = &self.context; self.valid.set(usize::MAX); unsafe { ph_call!(hexchat_list_free(ph, self.list)); @@ -110,7 +110,7 @@ impl<'a, 'ph, T> Iterator for Entries<'a, 'ph, T> { type Item = Fields<'a, 'ph, T>; fn next(&mut self) -> Option<Self::Item> { - let ph = &self.context.ph; + let ph = &self.context; let id = self.valid.get(); if unsafe { ph_call!(hexchat_list_next(ph, self.list)) @@ -138,7 +138,7 @@ macro_rules! field { self.id, self.valid.get(), "instances of Fields are invalidated by next()", ); - let $ph = &self.context.ph; + let $ph = &self.context; const NAME: &'static CStr = unsafe { CStr::from_bytes_with_nul_unchecked( $n.as_bytes() |