1use std::ffi::CStr;
2use std::marker::PhantomData;
3use std::os::raw::{c_char, c_int};
4use std::ptr::NonNull;
5
6use time::OffsetDateTime;
7
8use crate::str::HexStr;
9
10#[allow(missing_debug_implementations, missing_docs, unreachable_pub)]
11mod binding;
12
13mod handle;
14
15pub(crate) use binding::{
17 HEXCHAT_EAT_ALL, HEXCHAT_EAT_HEXCHAT, HEXCHAT_EAT_NONE, HEXCHAT_EAT_PLUGIN, HEXCHAT_PRI_HIGH,
18 HEXCHAT_PRI_HIGHEST, HEXCHAT_PRI_LOW, HEXCHAT_PRI_LOWEST, HEXCHAT_PRI_NORM,
19};
20
21pub(crate) use binding::{hexchat_context, hexchat_event_attrs, hexchat_hook, hexchat_list};
23pub use binding::hexchat_plugin;
25
26pub(crate) use handle::RawPluginHandle;
27
28const SUCCESS: c_int = 1;
30const FAILURE: c_int = 0;
31
32pub(crate) fn int_to_result(ret_code: c_int) -> Result<(), ()> {
33 match ret_code {
34 SUCCESS => Ok(()),
35 _ => Err(()),
36 }
37}
38
39pub(crate) fn result_to_int(res: Result<(), ()>) -> c_int {
40 match res {
41 Ok(()) => SUCCESS,
42 Err(_) => FAILURE,
43 }
44}
45
46#[allow(clippy::trivially_copy_pass_by_ref)]
54pub(crate) unsafe fn word_to_iter<'a>(
55 word: &'a *mut *mut c_char,
56) -> impl Iterator<Item = &'a HexStr> {
57 let word: *mut *mut c_char = *word;
59
60 let word = unsafe { word.add(1) };
63
64 struct WordIter<'a> {
65 word: *mut *mut c_char,
66 _lifetime: PhantomData<&'a *mut c_char>,
67 }
68
69 impl<'a> Iterator for WordIter<'a> {
70 type Item = &'a HexStr;
71
72 fn next(&mut self) -> Option<Self::Item> {
73 let elem = unsafe { *self.word };
75 if elem.is_null() {
76 None
77 } else {
78 self.word = unsafe { self.word.add(1) };
80 let str = unsafe { CStr::from_ptr::<'a>(elem) };
82
83 let str = HexStr::from_cstr(str)
84 .unwrap_or_else(|e| panic!("Invalid UTF8 in {:?}: {}", str, e));
85
86 Some(str)
87 }
88 }
89
90 fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
91 while n > 0 {
92 let elem = unsafe { *self.word };
93 if elem.is_null() {
94 break;
95 } else {
96 self.word = unsafe { self.word.add(1) };
98 }
99 n -= 1;
100 }
101
102 self.next()
103 }
104 }
105
106 WordIter::<'a> {
107 word,
108 _lifetime: PhantomData,
109 }
110}
111
112#[allow(unreachable_pub)]
113#[derive(Debug)]
114pub struct ListElem<'a> {
115 raw: RawPluginHandle<'a>,
116 list_ptr: NonNull<hexchat_list>,
118}
119
120impl<'a> ListElem<'a> {
121 pub(crate) unsafe fn new(raw: RawPluginHandle<'a>, list_ptr: NonNull<hexchat_list>) -> Self {
133 Self { raw, list_ptr }
134 }
135
136 pub(crate) fn string<'elem>(&'elem self, name: &CStr) -> Option<&'elem HexStr> {
137 let ptr = unsafe {
139 self.raw
140 .hexchat_list_str(self.list_ptr.as_ptr(), name.as_ptr())
141 };
142
143 if ptr.is_null() {
144 return None;
145 }
146
147 let str = unsafe { CStr::from_ptr(ptr) };
149
150 let str = HexStr::from_cstr(str)
151 .unwrap_or_else(|e| panic!("Invalid UTF8 from `hexchat_list_str` in {:?}: {}", str, e));
152
153 Some(str)
154 }
155
156 pub(crate) fn int(&self, name: &CStr) -> i32 {
157 unsafe {
159 self.raw
160 .hexchat_list_int(self.list_ptr.as_ptr(), name.as_ptr())
161 }
162 }
163
164 pub(crate) fn time(&self, name: &CStr) -> OffsetDateTime {
165 let time = unsafe {
167 self.raw
168 .hexchat_list_time(self.list_ptr.as_ptr(), name.as_ptr())
169 };
170
171 OffsetDateTime::from_unix_timestamp(time)
172 .unwrap_or_else(|e| panic!("Invalid timestamp from `hexchat_list_time`: {}", e))
173 }
174}