use std::ffi::CStr;
use std::marker::PhantomData;
use std::os::raw::{c_char, c_int};
use std::ptr::NonNull;
use time::OffsetDateTime;
use crate::str::HexStr;
#[allow(missing_debug_implementations, missing_docs, unreachable_pub)]
mod binding;
mod handle;
pub(crate) use binding::{
HEXCHAT_EAT_ALL, HEXCHAT_EAT_HEXCHAT, HEXCHAT_EAT_NONE, HEXCHAT_EAT_PLUGIN, HEXCHAT_PRI_HIGH,
HEXCHAT_PRI_HIGHEST, HEXCHAT_PRI_LOW, HEXCHAT_PRI_LOWEST, HEXCHAT_PRI_NORM,
};
pub(crate) use binding::{hexchat_context, hexchat_event_attrs, hexchat_hook, hexchat_list};
pub use binding::hexchat_plugin;
pub(crate) use handle::RawPluginHandle;
const SUCCESS: c_int = 1;
const FAILURE: c_int = 0;
pub(crate) fn int_to_result(ret_code: c_int) -> Result<(), ()> {
match ret_code {
SUCCESS => Ok(()),
_ => Err(()),
}
}
pub(crate) fn result_to_int(res: Result<(), ()>) -> c_int {
match res {
Ok(()) => SUCCESS,
Err(_) => FAILURE,
}
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub(crate) unsafe fn word_to_iter<'a>(
word: &'a *mut *mut c_char,
) -> impl Iterator<Item = &'a HexStr> {
let word: *mut *mut c_char = *word;
let word = unsafe { word.add(1) };
struct WordIter<'a> {
word: *mut *mut c_char,
_lifetime: PhantomData<&'a *mut c_char>,
}
impl<'a> Iterator for WordIter<'a> {
type Item = &'a HexStr;
fn next(&mut self) -> Option<Self::Item> {
let elem = unsafe { *self.word };
if elem.is_null() {
None
} else {
self.word = unsafe { self.word.add(1) };
let str = unsafe { CStr::from_ptr::<'a>(elem) };
let str = HexStr::from_cstr(str)
.unwrap_or_else(|e| panic!("Invalid UTF8 in {:?}: {}", str, e));
Some(str)
}
}
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
while n > 0 {
let elem = unsafe { *self.word };
if elem.is_null() {
break;
} else {
self.word = unsafe { self.word.add(1) };
}
n -= 1;
}
self.next()
}
}
WordIter::<'a> {
word,
_lifetime: PhantomData,
}
}
#[allow(unreachable_pub)]
#[derive(Debug)]
pub struct ListElem<'a> {
raw: RawPluginHandle<'a>,
list_ptr: NonNull<hexchat_list>,
}
impl<'a> ListElem<'a> {
pub(crate) unsafe fn new(raw: RawPluginHandle<'a>, list_ptr: NonNull<hexchat_list>) -> Self {
Self { raw, list_ptr }
}
pub(crate) fn string<'elem>(&'elem self, name: &CStr) -> Option<&'elem HexStr> {
let ptr = unsafe {
self.raw
.hexchat_list_str(self.list_ptr.as_ptr(), name.as_ptr())
};
if ptr.is_null() {
return None;
}
let str = unsafe { CStr::from_ptr(ptr) };
let str = HexStr::from_cstr(str)
.unwrap_or_else(|e| panic!("Invalid UTF8 from `hexchat_list_str` in {:?}: {}", str, e));
Some(str)
}
pub(crate) fn int(&self, name: &CStr) -> i32 {
unsafe {
self.raw
.hexchat_list_int(self.list_ptr.as_ptr(), name.as_ptr())
}
}
pub(crate) fn time(&self, name: &CStr) -> OffsetDateTime {
let time = unsafe {
self.raw
.hexchat_list_time(self.list_ptr.as_ptr(), name.as_ptr())
};
OffsetDateTime::from_unix_timestamp(time)
.unwrap_or_else(|e| panic!("Invalid timestamp from `hexchat_list_time`: {}", e))
}
}