hexchat_api/
threadsafe_context.rs1#![cfg(feature = "threadsafe")]
2
3use std::sync::Arc;
8use std::fmt;
9use std::sync::RwLock;
10
11use send_wrapper::SendWrapper;
12
13use crate::HexchatError;
14use crate::context::*;
15use crate::thread_facilities::*;
16use crate::threadsafe_list_iterator::*;
17
18use HexchatError::*;
19
20const DROPPED_ERR: &str = "Context dropped from threadsafe context.";
21
22#[derive(Clone)]
32pub struct ThreadSafeContext {
33 ctx : Arc<RwLock<Option<SendWrapper<Context>>>>,
34}
35
36unsafe impl Send for ThreadSafeContext {}
37unsafe impl Sync for ThreadSafeContext {}
38
39impl ThreadSafeContext {
40 pub (crate)
44 fn new(ctx: Context) -> Self {
45 Self { ctx: Arc::new(RwLock::new(Some(SendWrapper::new(ctx)))) }
46 }
47
48 pub fn get() -> Result<Self, HexchatError> {
52 main_thread(|_| Context::get().map(Self::new)).get()
53 .and_then(|r| r.ok_or_else(|| ContextAcquisitionFailed("?, ?".into())))
54 }
55
56 pub fn find(network: &str, channel: &str) -> Result<Self, HexchatError> {
64 let data = (network.to_string(), channel.to_string());
65 main_thread(move |_| Context::find(&data.0, &data.1).map(Self::new))
66 .get()
67 .and_then(|r| r.ok_or_else(|| {
68 let msg = format!("{}, {}", network, channel);
69 ContextAcquisitionFailed(msg)
70 }))
71 }
72
73 pub fn print(&self, message: &str) -> Result<(), HexchatError> {
78 let message = message.to_string();
79 let me = self.clone();
80 main_thread(move |_| {
81 me.ctx.read().unwrap().as_ref()
82 .ok_or_else(|| ContextDropped(DROPPED_ERR.into()))?
83 .print(&message)
84 }).get().and_then(|r| r)
85 }
86
87 pub fn aprint(&self, message: &str) {
94 let message = message.to_string();
95 let me = self.clone();
96 main_thread(move |hc| {
97 if let Err(err)
98 = me.ctx.read().unwrap().as_ref().unwrap().print(&message) {
99 hc.print(&format!("\x0313Context.aprint() failed to acquire \
100 context: {}", err));
101 hc.print(&format!("\x0313{}", message));
102 }
103 });
104 }
105
106 pub fn command(&self, command: &str) -> Result<(), HexchatError> {
109 let command = command.to_string();
110 let me = self.clone();
111 main_thread(move |_| {
112 me.ctx.read().unwrap().as_ref()
113 .ok_or_else(|| ContextDropped(DROPPED_ERR.into()))?
114 .command(&command)
115 }).get().and_then(|r| r)
116 }
117
118 pub fn get_info(&self, info: &str) -> Result<String, HexchatError> {
122 let info = info.to_string();
123 let me = self.clone();
124 main_thread(move |_| {
125 me.ctx.read().unwrap().as_ref()
126 .ok_or_else(|| ContextDropped(DROPPED_ERR.into()))?
127 .get_info(&info)
128 }).get().and_then(|r| r)
129 }
130
131 pub fn emit_print(&self, event_name: &str, var_args: &[&str])
135 -> Result<(), HexchatError>
136 {
137 let var_args: Vec<String> = var_args.iter()
138 .map(|s| s.to_string())
139 .collect();
140 let data = (event_name.to_string(), var_args);
141 let me = self.clone();
142 main_thread(move |_| {
143 let var_args: Vec<&str> = data.1.iter()
144 .map(|s| s.as_str())
145 .collect();
146 me.ctx.read().unwrap().as_ref()
147 .ok_or_else(|| ContextDropped(DROPPED_ERR.into()))?
148 .emit_print(&data.0, var_args.as_slice())
149 }).get().and_then(|r| r)
150 }
151
152 pub fn list_get(&self,
156 name: &str)
157 -> Result<ThreadSafeListIterator, HexchatError>
158 {
159 let name = name.to_string();
160 let me = self.clone();
161 main_thread(move |_| {
162 if let Some(ctx) = me.ctx.read().unwrap().as_ref() {
163 match ctx.list_get(&name) {
164 Ok(list) => {
165 Ok(ThreadSafeListIterator::create(list))
166 },
167 Err(err) => Err(err),
168 }
169 } else {
170 Err(ContextDropped(DROPPED_ERR.into()))
171 }
172 }).get().and_then(|r| r)
173 }
174 pub fn network(&self) -> Result<String, HexchatError> {
177 let me = self.clone();
178 main_thread(move |_| {
179 if let Some(ctx) = me.ctx.read().unwrap().as_ref() {
180 Ok(ctx.network())
181 } else {
182 Err(ContextDropped(DROPPED_ERR.into()))
183 }
184 }).get().and_then(|r| r)
185 }
186
187 pub fn channel(&self) -> Result<String, HexchatError> {
190 let me = self.clone();
191 main_thread(move |_| {
192 if let Some(ctx) = me.ctx.read().unwrap().as_ref() {
193 Ok(ctx.channel())
194 } else {
195 Err(ContextDropped(DROPPED_ERR.into()))
196 }
197 }).get().and_then(|r| r)
198 }
199}
200
201impl fmt::Display for ThreadSafeContext {
202 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 write!(f, "{:?}", self.ctx)
204 }
205}
206
207impl Drop for ThreadSafeContext {
208 fn drop(&mut self) {
209 if Arc::strong_count(&self.ctx) <= 1
210 && self.ctx.read().unwrap().is_some() {
211 let me = self.clone();
212 main_thread(move |_| {
213 me.ctx.write().unwrap().take();
214 });
215 }
216 }
217}
218
219impl fmt::Debug for ThreadSafeContext {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 let me = self.clone();
224 let s = main_thread(move |_| {
225 if let Ok(guard) = me.ctx.read() {
226 if let Some(ctx) = guard.as_ref() {
227 format!("Context({:?}, {:?})", ctx.network(), ctx.channel())
228 } else {
229 "Context(Error getting info)".to_string()
230 }
231 } else {
232 "Context(Error getting info)".to_string()
233 }
234 }).get().unwrap();
235 write!(f, "{}", s)
236 }
237}