hexchat_api/
threadsafe_list_iterator.rs1#![cfg(feature = "threadsafe")]
2
3use std::sync::Arc;
8use std::fmt;
9use std::sync::RwLock;
10
11use libc::time_t;
12use send_wrapper::SendWrapper;
13
14use crate::HexchatError;
15use crate::list_item::*;
16use crate::list_iterator::*;
17use crate::thread_facilities::*;
18use crate::threadsafe_context::*;
19
20use HexchatError::*;
21
22const DROPPED_ERR: &str = "ListIterator dropped from threadsafe context.";
23
24#[derive(Clone)]
38pub struct ThreadSafeListIterator {
39 list_iter: Arc<RwLock<Option<SendWrapper<ListIterator>>>>,
40}
41
42unsafe impl Send for ThreadSafeListIterator {}
43unsafe impl Sync for ThreadSafeListIterator {}
44
45impl ThreadSafeListIterator {
46 pub (crate)
51 fn create(list_iter: ListIterator) -> Self {
52 Self {
53 list_iter: Arc::new(RwLock::new(Some(SendWrapper::new(list_iter))))
54 }
55 }
56
57 pub fn new(name: &str) -> Result<Self, HexchatError> {
64 let cname = name.to_string();
65 main_thread(move |_| {
66 ListIterator::new(&cname).map(|list|
67 ThreadSafeListIterator {
68 list_iter:
69 Arc::new(RwLock::new(Some(SendWrapper::new(list))))
70 })}
71 ).get().and_then(|res| res.ok_or_else(|| ListNotFound(name.into())))
72 }
73
74 pub fn get_field_names(&self) -> Result<Vec<String>, HexchatError> {
78 let me = self.clone();
79 main_thread(move |_| {
80 Ok(me.list_iter.read().unwrap().as_ref()
81 .ok_or_else(|| ListIteratorDropped(DROPPED_ERR.into()))?
82 .get_field_names().to_vec())
83 }).get().and_then(|r| r)
84 }
85
86 pub fn to_vec(&self) -> Result<Vec<ListItem>, HexchatError> {
90 let me = self.clone();
91 main_thread(move |_| {
92 Ok(me.list_iter.read().unwrap().as_ref()
93 .ok_or_else(|| ListIteratorDropped(DROPPED_ERR.into()))?
94 .to_vec())
95 }).get().and_then(|r| r)
96 }
97
98 pub fn get_item(&self) -> Result<ListItem, HexchatError> {
102 let me = self.clone();
103 main_thread(move |_| {
104 Ok(me.list_iter.read().unwrap().as_ref()
105 .ok_or_else(|| ListIteratorDropped(DROPPED_ERR.into()))?
106 .get_item())
107 }).get().and_then(|r| r)
108 }
109
110 pub fn get_field(&self, name: &str)
122 -> Result<ThreadSafeFieldValue, HexchatError>
123 {
124 use FieldValue as FV;
125 use ThreadSafeFieldValue as TSFV;
126
127 let name = name.to_string();
128 let me = self.clone();
129 main_thread(move |_| {
130 if let Some(iter) = me.list_iter.read().unwrap().as_ref() {
131 match iter.get_field(&name) {
132 Ok(field_val) => {
133 match field_val {
134 FV::StringVal(s) => {
135 Ok(TSFV::StringVal(s))
136 },
137 FV::IntVal(i) => {
138 Ok(TSFV::IntVal(i))
139 },
140 FV::PointerVal(pv) => {
141 Ok(TSFV::PointerVal(pv))
142 },
143 FV::ContextVal(ctx) => {
144 Ok(TSFV::ContextVal(
145 ThreadSafeContext::new(ctx)
146 ))
147 },
148 FV::TimeVal(time) => {
149 Ok(TSFV::TimeVal(time))
150 }
151 }
152 },
153 Err(err) => {
154 Err(err)
155 },
156 }
157 } else {
158 Err(ListIteratorDropped(DROPPED_ERR.into()))
159 }
160 }).get().and_then(|r| r)
161 }
162}
163
164impl Iterator for ThreadSafeListIterator {
165 type Item = Self;
166 fn next(&mut self) -> Option<Self::Item> {
167 let me = self.clone();
168 main_thread(move |_| {
169 if let Some(iter) = me.list_iter.write().unwrap().as_mut() {
170 iter.next().map(|it| ThreadSafeListIterator::create(it.clone()))
171 } else {
172 None
173 }
174 }).get().unwrap_or(None)
175 }
176}
177
178impl Iterator for &ThreadSafeListIterator {
179 type Item = Self;
180 fn next(&mut self) -> Option<Self::Item> {
181 let me = self.clone();
182 let has_more = main_thread(move |_| {
183 me.list_iter.write().unwrap().as_mut()
184 .is_some_and(|it| it.next().is_some())
185 }).get().unwrap_or(false);
186 if has_more {
187 Some(self)
188 } else {
189 None
190 }
191 }
192}
193
194impl Drop for ThreadSafeListIterator {
195 fn drop(&mut self) {
196 if Arc::strong_count(&self.list_iter) <= 1
197 && self.list_iter.read().unwrap().is_some() {
198 let me = self.clone();
199 main_thread(move |_| {
200 me.list_iter.write().unwrap().take();
201 });
202 }
203 }
204}
205
206#[derive(Debug, Clone)]
218pub enum ThreadSafeFieldValue {
219 StringVal (String),
220 IntVal (i32),
221 PointerVal (u64),
222 ContextVal (ThreadSafeContext),
223 TimeVal (time_t),
224}
225
226unsafe impl Send for ThreadSafeFieldValue {}
227unsafe impl Sync for ThreadSafeFieldValue {}
228
229impl fmt::Display for ThreadSafeFieldValue {
230 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231 use ThreadSafeFieldValue::*;
232 match self {
233 StringVal(s) => { write!(f, "{}", s) },
234 IntVal(i) => { write!(f, "{:?}", i) },
235 PointerVal(p) => { write!(f, "{:?}", p) },
236 TimeVal(t) => { write!(f, "{:?}", t) },
237 ContextVal(c) => { write!(f, "ContextVal({})", c) },
238 }
239 }
240}
241
242use ThreadSafeFieldValue::*;
243
244impl ThreadSafeFieldValue {
245 pub fn str(self) -> String {
250 match self {
251 StringVal(s) => s,
252 _ => panic!("Can't convert {:?} to String.", self),
253 }
254 }
255 pub fn int(self) -> i32 {
260 match self {
261 IntVal(i) => i,
262 _ => panic!("Can't convert {:?} to i32.", self),
263 }
264 }
265 pub fn ptr(self) -> u64 {
270 match self {
271 PointerVal(p) => p,
272 _ => panic!("Can't convert {:?} to u64.", self),
273 }
274 }
275 pub fn time(self) -> time_t {
280 match self {
281 TimeVal(t) => t,
282 _ => panic!("Can't convert {:?} to time_t.", self),
283 }
284 }
285 pub fn ctx(self) -> ThreadSafeContext {
290 match self {
291 ContextVal(c) => c,
292 _ => panic!("Can't convert {:?} to Context.", self),
293 }
294 }
295}
296
297impl From<ThreadSafeFieldValue> for String {
298 fn from(v: ThreadSafeFieldValue) -> Self {
299 v.str()
300 }
301}
302
303impl From<ThreadSafeFieldValue> for i32 {
304 fn from(v: ThreadSafeFieldValue) -> Self {
305 v.int()
306 }
307}
308
309impl From<ThreadSafeFieldValue> for u64 {
310 fn from(v: ThreadSafeFieldValue) -> Self {
311 v.ptr()
312 }
313}
314
315impl From<ThreadSafeFieldValue> for i64 {
316 fn from(v: ThreadSafeFieldValue) -> Self {
317 v.time().into()
318 }
319}
320
321impl From<ThreadSafeFieldValue> for ThreadSafeContext {
322 fn from(v: ThreadSafeFieldValue) -> Self {
323 v.ctx()
324 }
325}
326