From 342d0b3ba53512c98cc5540313f874fe543d4b9b Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Mon, 20 Jun 2022 00:19:56 -0300 Subject: Begin the great refactoring --- src/mock/mod.rs | 465 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 298 insertions(+), 167 deletions(-) (limited to 'src/mock/mod.rs') diff --git a/src/mock/mod.rs b/src/mock/mod.rs index 92de66c..0e4ba03 100644 --- a/src/mock/mod.rs +++ b/src/mock/mod.rs @@ -38,8 +38,11 @@ //! //! This API is not stable. Do not rely on this API to be stable. +use crate::internals::Ph; + use std::cell::Cell; use std::cell::RefCell; +use std::cell::UnsafeCell; use std::ffi::CStr; use std::ffi::CString; use std::marker::PhantomData; @@ -48,24 +51,40 @@ use std::pin::Pin; use std::ptr; use std::rc::Rc; -use libc::c_char; +use ::libc::{c_char, c_int}; use ::ltptr::*; -use ::selfref::{Holder, Opaque, SelfRef, opaque}; +use ::selfref::{Holder, NewWith, OperateIn, opaque}; + +struct Context { +} -// MUST be repr(C) +// MUST be repr(C), despite having repr(Rust) types inside it. +/// A loaded plugin/complete plugin handle, including private fields. #[repr(C)] -struct MockPlugin<'dangling, 'env> { +struct MockPlugin<'ph, 'env: 'ph> { // NOTE: MUST be first thing in the struct. - methods: crate::internals::Ph, - filename: *const c_char, - plugin_name: Cell<*const c_char>, - plugin_desc: Cell<*const c_char>, - plugin_vers: Cell<*const c_char>, + // we actually pass the whole MockPlugin to the plugin, but we pretend it's + // just the Ph. + methods: Ph<'ph>, + filename: CString, + plugin_name: *const c_char, + plugin_desc: *const c_char, + plugin_vers: *const c_char, free_strings: bool, - env: &'env PluginEnvironment<'dangling, 'env>, - _pin: PhantomPinned, + env: Pin<&'env PluginEnvironment<'env>>, + deinit: Option>) -> c_int>, + context: Option>, +} + +struct MockPluginK<'env> { + _p: PhantomData<&'env PluginEnvironment<'env>>, +} +opaque! { + impl['env] Opaque for MockPluginK<'env> { + type Kind<'ph> = UnsafeCell>; + } } enum MockCallback { @@ -96,9 +115,9 @@ enum MockCallback { HookDeleted, } -struct MockHook<'dangling, 'env> { - //pl: Rc>>, - pl: Rc>, +struct MockHook<'env> { + pl: Rc>>, + //pl: Rc>, cb: RefCell, name: Option>, pri_or_fd: libc::c_int, @@ -106,32 +125,39 @@ struct MockHook<'dangling, 'env> { _pin: PhantomPinned, } -pub struct PluginEnvironment<'dangling, 'env> { - //plugins: RefCell>>>>>, - plugins: RefCell>>>>, - // priority-based hooks - //hooks: RefCell>>>>>, - hooks: RefCell>>>>, - // fd/timer hooks - //extra_hooks: RefCell>>>>>, - extra_hooks: RefCell>>>>, - depth: Cell, +struct MockHookK<'env> { + _p: PhantomData<&'env PluginEnvironment<'env>>, +} +opaque! { + impl['env] Opaque for MockHookK<'env> { + type Kind<'ph> = MockHook<'env>; + } } -impl<'dangling, 'env> SelfRef<'env> for PluginEnvironment<'dangling, 'env> {} -pub struct PluginEnvironmentK<'dangling> { - _p: PhantomData<&'dangling ()>, +/// A plugin environment. An emulated hexchat instance. +// TODO: maybe make this a full plugin host, with <'app>? +pub struct PluginEnvironment<'env> { + /// The loaded plugins. + plugins: RefCell>>>>>, + /// Priority-based hooks. + hooks: RefCell>>>>>, + /// Timer and fd hooks. + extra_hooks: RefCell>>>>>, + /// Hook recursion depth. + depth: Cell, + /// Contexts. + contexts: RefCell>>, } + +pub struct PluginEnvironmentK; opaque! { - impl['dangling] Opaque for PluginEnvironmentK<'dangling> { - type Kind<'env> = PluginEnvironment<'dangling, 'env>; + impl Opaque for PluginEnvironmentK { + type Kind<'env> = PluginEnvironment<'env>; } } -pub type GlobalPluginEnvironment<'dangling> = Holder<'dangling, PluginEnvironmentK<'dangling>>; - -unsafe extern "C" fn hexchat_hook_command( - ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_hook_command<'ph>( + ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char, pri: libc::c_int, /* CALLBACK */ @@ -139,10 +165,10 @@ unsafe extern "C" fn hexchat_hook_command( help_text: *const libc::c_char, userdata: *mut libc::c_void ) -> *const crate::internals::HexchatHook { - let ph = ph as *mut MockPlugin; + let ph = MutLtPtr::from_raw(ph.as_raw() as *mut MockPlugin<'ph, '_>); todo!(); } -unsafe extern "C" fn hexchat_hook_server(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_hook_server<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char, pri: libc::c_int, /* CALLBACK */ @@ -150,7 +176,7 @@ unsafe extern "C" fn hexchat_hook_server(ph: *mut crate::internals::HexchatPlugi userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook { todo!(); } -unsafe extern "C" fn hexchat_hook_print(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_hook_print<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char, pri: libc::c_int, /* CALLBACK */ @@ -158,14 +184,14 @@ unsafe extern "C" fn hexchat_hook_print(ph: *mut crate::internals::HexchatPlugin userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook { todo!(); } -unsafe extern "C" fn hexchat_hook_timer(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_hook_timer<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, timeout: libc::c_int, /* CALLBACK */ callback: unsafe extern "C" fn(user_data: *mut libc::c_void) -> libc::c_int, userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook { todo!(); } -unsafe extern "C" fn hexchat_hook_fd(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_hook_fd<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, fd: libc::c_int, flags: libc::c_int, /* CALLBACK */ @@ -173,80 +199,102 @@ unsafe extern "C" fn hexchat_hook_fd(ph: *mut crate::internals::HexchatPlugin, userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook { todo!(); } -unsafe extern "C" fn hexchat_unhook(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_unhook<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, hook: *const crate::internals::HexchatHook) -> *const libc::c_void { todo!(); } -unsafe extern "C" fn hexchat_print(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_print<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, text: *const libc::c_char) { todo!(); } -pub unsafe extern "C" fn hexchat_printf(ph: *mut crate::internals::HexchatPlugin, +pub unsafe extern "C" fn hexchat_printf<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, format: *const libc::c_char, ...) { unimplemented!(); } -unsafe extern "C" fn hexchat_command(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_command<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, command: *const libc::c_char) { todo!(); } -unsafe extern "C" fn hexchat_commandf(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_commandf<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, format: *const libc::c_char, ...) { unimplemented!(); } -unsafe extern "C" fn hexchat_nickcmp(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_nickcmp<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_set_context(ph: *mut crate::internals::HexchatPlugin, - ctx: *const crate::internals::HexchatContext) -> libc::c_int { - todo!(); +unsafe extern "C" fn hexchat_set_context<'ph>( + ph: MutLtPtr<'ph, Ph<'ph>>, + ctx: *const crate::internals::HexchatContext, +) -> libc::c_int { + let ctx = ctx as *const Context; + let ph: *mut MockPlugin<'_, '_> = ph.as_raw() as *mut _; + if ctx.is_null() { return 0; } + // in C, ctx must NOT be dangling, so we let miri catch it + let _ = &*ctx; + // in addition to that we also panic if ctx isn't on the list, + // because you're supposed to use "Close Context" for cleanup. + // if your plugin makes it this far, you're literally passing in garbage. + let env: Pin<&PluginEnvironment<'_>> = (*ph).env; + if env.contexts.borrow().iter().any(|e| ptr::eq(&**e, ctx)) { + (*ph).context = Some(crate::rc_clone_from_raw(ctx)); + return 1; + } else { + panic!("garbage in hexchat_set_context - broken plugin") + } } -unsafe extern "C" fn hexchat_find_context(ph: *mut crate::internals::HexchatPlugin, - servname: *const libc::c_char, - channel: *const libc::c_char) -> *const crate::internals::HexchatContext { +unsafe extern "C" fn hexchat_find_context<'ph>( + ph: MutLtPtr<'ph, Ph<'ph>>, + servname: *const libc::c_char, + channel: *const libc::c_char, +) -> *const crate::internals::HexchatContext { todo!(); } -unsafe extern "C" fn hexchat_get_context(ph: *mut crate::internals::HexchatPlugin) -> *const crate::internals::HexchatContext { - todo!(); +unsafe extern "C" fn hexchat_get_context<'ph>( + ph: MutLtPtr<'ph, Ph<'ph>>, +) -> *const crate::internals::HexchatContext { + let ph: *mut MockPlugin<'_, '_> = ph.as_raw() as *mut _; + let ctx = (*ph).context.as_ref().map(|rc| Rc::as_ptr(rc)); + ctx.unwrap_or(ptr::null()) as *const _ } -unsafe extern "C" fn hexchat_get_info(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_get_info<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, id: *const libc::c_char) -> *const libc::c_char { todo!(); } -unsafe extern "C" fn hexchat_get_prefs(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_get_prefs<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char, string: *mut *const libc::c_char, integer: *mut libc::c_int) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_list_get(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_list_get<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char) -> *mut crate::internals::HexchatList { todo!(); } -unsafe extern "C" fn hexchat_list_free(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_list_free<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, xlist: *const crate::internals::HexchatList) { todo!(); } -unsafe extern "C" fn hexchat_list_fields(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_list_fields<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char) -> *const *const libc::c_char { todo!(); } -unsafe extern "C" fn hexchat_list_next(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_list_next<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, xlist: *const crate::internals::HexchatList) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_list_str(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_list_str<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, xlist: *const crate::internals::HexchatList, name: *const libc::c_char) -> *const libc::c_char { todo!(); } -unsafe extern "C" fn hexchat_list_int(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_list_int<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, xlist: *const crate::internals::HexchatList, name: *const libc::c_char) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_plugingui_add(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_plugingui_add<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, filename: *const libc::c_char, name: *const libc::c_char, desc: *const libc::c_char, @@ -254,30 +302,30 @@ unsafe extern "C" fn hexchat_plugingui_add(ph: *mut crate::internals::HexchatPlu reserved: *mut char) -> *const crate::internals::PluginGuiHandle { todo!(); } -unsafe extern "C" fn hexchat_plugingui_remove(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_plugingui_remove<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, handle: *const crate::internals::PluginGuiHandle) { todo!(); } -unsafe extern "C" fn hexchat_emit_print(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_emit_print<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, event_name: *const libc::c_char, ...) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_read_fd(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_read_fd<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, src: *const libc::c_void, buf: *mut char, len: *mut libc::c_int) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_list_time(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_list_time<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, xlist: *const crate::internals::HexchatList, name: *const libc::c_char) -> libc::time_t { todo!(); } -unsafe extern "C" fn hexchat_gettext(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_gettext<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, msgid: *const libc::c_char) -> *const libc::c_char { todo!(); } -unsafe extern "C" fn hexchat_send_modes(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_send_modes<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, targets: *mut *const libc::c_char, ntargets: libc::c_int, modes_per_line: libc::c_int, @@ -285,44 +333,44 @@ unsafe extern "C" fn hexchat_send_modes(ph: *mut crate::internals::HexchatPlugin mode: libc::c_char) { todo!(); } -unsafe extern "C" fn hexchat_strip(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_strip<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, string: *const libc::c_char, len: libc::c_int, flags: libc::c_int) -> *const libc::c_char { todo!(); } -unsafe extern "C" fn hexchat_free(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_free<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, ptr: *const libc::c_void) { todo!(); } -unsafe extern "C" fn hexchat_pluginpref_set_str(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_pluginpref_set_str<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, var: *const libc::c_char, value: *const libc::c_char) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_pluginpref_get_str(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_pluginpref_get_str<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, var: *const libc::c_char, dest: *mut char) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_pluginpref_set_int(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_pluginpref_set_int<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, var: *const libc::c_char, value: libc::c_int) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_pluginpref_get_int(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_pluginpref_get_int<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, var: *const libc::c_char) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_pluginpref_delete(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_pluginpref_delete<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, var: *const libc::c_char) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_pluginpref_list(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_pluginpref_list<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, dest: *mut char) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_hook_server_attrs(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_hook_server_attrs<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char, pri: libc::c_int, /* CALLBACK */ @@ -330,7 +378,7 @@ unsafe extern "C" fn hexchat_hook_server_attrs(ph: *mut crate::internals::Hexcha userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook { todo!(); } -unsafe extern "C" fn hexchat_hook_print_attrs(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_hook_print_attrs<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, name: *const libc::c_char, pri: libc::c_int, /* CALLBACK */ @@ -338,106 +386,189 @@ unsafe extern "C" fn hexchat_hook_print_attrs(ph: *mut crate::internals::Hexchat userdata: *mut libc::c_void) -> *const crate::internals::HexchatHook { todo!(); } -unsafe extern "C" fn hexchat_emit_print_attrs(ph: *mut crate::internals::HexchatPlugin, attrs: *const crate::internals::HexchatEventAttrs, +unsafe extern "C" fn hexchat_emit_print_attrs<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, attrs: *const crate::internals::HexchatEventAttrs, event_name: *const libc::c_char, ...) -> libc::c_int { todo!(); } -unsafe extern "C" fn hexchat_event_attrs_create(ph: *mut crate::internals::HexchatPlugin) -> *mut crate::internals::HexchatEventAttrs { +unsafe extern "C" fn hexchat_event_attrs_create<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>) -> *mut crate::internals::HexchatEventAttrs { todo!(); } -unsafe extern "C" fn hexchat_event_attrs_free(ph: *mut crate::internals::HexchatPlugin, +unsafe extern "C" fn hexchat_event_attrs_free<'ph>(ph: MutLtPtr<'ph, Ph<'ph>>, attrs: *mut crate::internals::HexchatEventAttrs) { todo!(); } -impl<'dangling, 'env> PluginEnvironment<'dangling, 'env> { - pub fn new() -> Self { - Self { - plugins: Default::default(), - hooks: Default::default(), - extra_hooks: Default::default(), - depth: Default::default(), +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::new_with(NewEnv) + } + + /// Loads a plugin. + pub fn load_plugin( + self: Pin<&'env Self>, + filename: CString, + arg: Option<&CStr>, + ) -> Result<(), ()> { + let plug = MockPlugin::new(self, filename); + // add the plugin + self.plugins.borrow_mut().push(plug.clone()); + + struct MockPluginInit<'arg, T> { + arg: Option<&'arg CStr>, + _p: PhantomData + } + 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>>, + ) -> 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(MockPluginInit:: { + arg, + _p: PhantomData, + }) { + Ok(()) + } else { + // remove the plugin - aka retain every plugin that isn't this one + self.plugins.borrow_mut().retain(|e| { + !ptr::eq::>(&**e, &*plug) + }); + Err(()) } } } -// -//impl MockPlugin { -// pub fn new crate::Plugin<'ph> + Default>( -// env: Pin<&PluginEnvironment>, -// filename: CString, -// arg: Option<&CStr>, -// ) -> Option>> { -// let filename = filename.into_raw(); -// let mut plug = Box::pin(MockPlugin { -// methods: crate::internals::Ph { -// hexchat_hook_command, -// hexchat_hook_server, -// hexchat_hook_print, -// hexchat_hook_timer, -// hexchat_hook_fd, -// hexchat_unhook, -// hexchat_print, -// userdata: hexchat_printf as *mut libc::c_void, -// hexchat_command, -// hexchat_commandf_do_not_use: hexchat_commandf, -// hexchat_nickcmp, -// hexchat_set_context, -// hexchat_find_context, -// hexchat_get_context, -// hexchat_get_info, -// hexchat_get_prefs, -// hexchat_list_get, -// hexchat_list_free, -// hexchat_list_fields, -// hexchat_list_next, -// hexchat_list_str, -// hexchat_list_int, -// hexchat_plugingui_add, -// hexchat_plugingui_remove, -// hexchat_emit_print, -// hexchat_read_fd, -// hexchat_list_time, -// hexchat_gettext, -// hexchat_send_modes, -// hexchat_strip, -// hexchat_free, -// hexchat_pluginpref_set_str, -// hexchat_pluginpref_get_str, -// hexchat_pluginpref_set_int, -// hexchat_pluginpref_get_int, -// hexchat_pluginpref_delete, -// hexchat_pluginpref_list, -// hexchat_hook_server_attrs, -// hexchat_hook_print_attrs, -// hexchat_emit_print_attrs, -// hexchat_event_attrs_create, -// hexchat_event_attrs_free, -// }, -// filename: filename, -// plugin_name: filename, -// plugin_desc: ptr::null(), -// plugin_vers: ptr::null(), -// free_strings: false, -// env: &*env, -// _pin: PhantomPinned, -// }); -// if unsafe { -// let ptr: *mut MockPlugin = &mut *plug; -// crate::hexchat_plugin_init::<'_, T>( -// crate::LtPhPtr { -// ph: ptr as *mut crate::internals::Ph, -// _lt: PhantomData, -// }, -// 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 -// } { -// Some(plug) -// } else { -// None -// } -// } -//} +/// Helper for making [`MockPlugin`]s from [`crate::Plugin`]s. +pub trait PluginFactory: 'static { + /// The plugin type. + type Plugin<'a>: crate::Plugin<'a> + Default; +} + +impl<'ph, 'env> MockPlugin<'ph, 'env> { + /// Creates a MockPlugin, but does not load it (yet). + fn new( + env: Pin<&'env PluginEnvironment<'env>>, + filename: CString, + ) -> Pin>>> { + 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> + where 'k: 'ph { + let filename = self.filename; + let env = self.env; + UnsafeCell::new(MockPlugin { + methods: Ph { + hexchat_hook_command, + hexchat_hook_server, + hexchat_hook_print, + hexchat_hook_timer, + hexchat_hook_fd, + hexchat_unhook, + hexchat_print, + userdata: hexchat_printf as *mut _, + hexchat_command, + hexchat_commandf_do_not_use: hexchat_commandf, + hexchat_nickcmp, + hexchat_set_context, + hexchat_find_context, + hexchat_get_context, + hexchat_get_info, + hexchat_get_prefs, + hexchat_list_get, + hexchat_list_free, + hexchat_list_fields, + hexchat_list_next, + hexchat_list_str, + hexchat_list_int, + hexchat_plugingui_add, + hexchat_plugingui_remove, + hexchat_emit_print, + hexchat_read_fd, + hexchat_list_time, + hexchat_gettext, + hexchat_send_modes, + hexchat_strip, + hexchat_free, + hexchat_pluginpref_set_str, + hexchat_pluginpref_get_str, + hexchat_pluginpref_set_int, + hexchat_pluginpref_get_int, + hexchat_pluginpref_delete, + hexchat_pluginpref_list, + hexchat_hook_server_attrs, + hexchat_hook_print_attrs, + hexchat_emit_print_attrs, + hexchat_event_attrs_create, + hexchat_event_attrs_free, + }, + filename: filename, + plugin_name: ptr::null(), // not initialized yet! + plugin_desc: ptr::null(), + plugin_vers: ptr::null(), + free_strings: false, + env: env, + deinit: None, + context: None, + }) + } + } + 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>>, + ) 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 + } +} -- cgit 1.4.1