1use {ErrorCode, IndyHandle};
2
3use utils::sequence::SequenceUtils;
4
5use std::os::raw::c_char;
6
7use std::collections::HashMap;
8use std::slice;
9use std::ffi::CStr;
10use std::fmt::Display;
11use std::sync::Mutex;
12use std::sync::mpsc::{channel, Receiver};
13
14use native::{ResponseEmptyCB,
15 ResponseI32CB,
16 ResponseI32UsizeCB,
17 ResponseStringCB,
18 ResponseStringStringCB,
19 ResponseStringStringStringCB,
20 ResponseStringStringU64CB,
21 ResponseSliceCB,
22 ResponseStringSliceCB,
23 ResponseBoolCB};
24
25fn log_error<T: Display>(e: T) {
26 warn!("Unable to send through libindy callback: {}", e);
27}
28
29pub struct ClosureHandler {}
30
31impl ClosureHandler {
32 pub fn cb_ec() -> (Receiver<ErrorCode>, IndyHandle, Option<ResponseEmptyCB>) {
33 let (sender, receiver) = channel();
34
35 let closure = Box::new(move |err| {
36 sender.send(err).unwrap_or_else(log_error);
37 });
38
39 let (command_handle, cb) = ClosureHandler::convert_cb_ec(closure);
40
41 (receiver, command_handle, cb)
42 }
43
44 pub fn convert_cb_ec(closure: Box<FnMut(ErrorCode) + Send>) -> (IndyHandle, Option<ResponseEmptyCB>) {
45 lazy_static! {
46 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode) + Send>>> = Default::default();
47 }
48 extern "C" fn _callback(command_handle: IndyHandle, err: i32) {
49 let mut callbacks = CALLBACKS.lock().unwrap();
50 let mut cb = callbacks.remove(&command_handle).unwrap();
51 cb(ErrorCode::from(err))
52 }
53
54 let mut callbacks = CALLBACKS.lock().unwrap();
55 let command_handle = SequenceUtils::get_next_id();
56 callbacks.insert(command_handle, closure);
57
58 (command_handle, Some(_callback))
59 }
60
61 pub fn cb_ec_i32() -> (Receiver<(ErrorCode, IndyHandle)>, IndyHandle, Option<ResponseI32CB>) {
62 let (sender, receiver) = channel();
63
64 let closure = Box::new(move |err, val| {
65 sender.send((err, val)).unwrap_or_else(log_error);
66 });
67
68 let (command_handle, cb) = ClosureHandler::convert_cb_ec_i32(closure);
69
70 (receiver, command_handle, cb)
71 }
72
73 pub fn convert_cb_ec_i32(closure: Box<FnMut(ErrorCode, IndyHandle) + Send>) -> (IndyHandle, Option<ResponseI32CB>) {
74 lazy_static! {
75 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, IndyHandle) + Send>>> = Default::default();
76 }
77
78 extern "C" fn _callback(command_handle: IndyHandle, err: i32, val: i32) {
79 let mut callbacks = CALLBACKS.lock().unwrap();
80 let mut cb = callbacks.remove(&command_handle).unwrap();
81 cb(ErrorCode::from(err), val)
82 }
83
84 let mut callbacks = CALLBACKS.lock().unwrap();
85 let command_handle = SequenceUtils::get_next_id();
86 callbacks.insert(command_handle, closure);
87
88 (command_handle, Some(_callback))
89 }
90
91 pub fn cb_ec_i32_usize() -> (Receiver<(ErrorCode, IndyHandle, usize)>, IndyHandle, Option<ResponseI32UsizeCB>) {
92 let (sender, receiver) = channel();
93
94 let closure = Box::new(move |err, val1, val2| {
95 sender.send((err, val1, val2)).unwrap_or_else(log_error);
96 });
97
98 let (command_handle, cb) = ClosureHandler::convert_cb_ec_i32_usize(closure);
99
100 (receiver, command_handle, cb)
101 }
102
103 pub fn convert_cb_ec_i32_usize(closure: Box<FnMut(ErrorCode, IndyHandle, usize) + Send>) -> (IndyHandle, Option<ResponseI32UsizeCB>) {
104 lazy_static! {
105 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, IndyHandle, usize) + Send>>> = Default::default();
106 }
107
108 extern "C" fn _callback(command_handle: IndyHandle, err: i32, val1: i32, val2: usize) {
109 let mut callbacks = CALLBACKS.lock().unwrap();
110 let mut cb = callbacks.remove(&command_handle).unwrap();
111 cb(ErrorCode::from(err), val1, val2)
112 }
113
114 let mut callbacks = CALLBACKS.lock().unwrap();
115 let command_handle = SequenceUtils::get_next_id();
116 callbacks.insert(command_handle, closure);
117
118 (command_handle, Some(_callback))
119 }
120
121 pub fn cb_ec_string() -> (Receiver<(ErrorCode, String)>, IndyHandle, Option<ResponseStringCB>) {
122 let (sender, receiver) = channel();
123
124 let closure = Box::new(move |err, val| {
125 sender.send((err, val)).unwrap_or_else(log_error);
126 });
127
128 let (command_handle, cb) = ClosureHandler::convert_cb_ec_string(closure);
129
130 (receiver, command_handle, cb)
131 }
132
133 pub fn convert_cb_ec_string(closure: Box<FnMut(ErrorCode, String) + Send>) -> (IndyHandle, Option<ResponseStringCB>) {
134 lazy_static! {
135 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, String) + Send>>> = Default::default();
136 }
137
138 extern "C" fn _callback(command_handle: IndyHandle, err: i32, c_str: *const c_char) {
139 let mut callbacks = CALLBACKS.lock().unwrap();
140 let mut cb = callbacks.remove(&command_handle).unwrap();
141 let metadata = rust_str!(c_str);
142 cb(ErrorCode::from(err), metadata)
143 }
144
145 let mut callbacks = CALLBACKS.lock().unwrap();
146 let command_handle = SequenceUtils::get_next_id();
147 callbacks.insert(command_handle, closure);
148
149 (command_handle, Some(_callback))
150 }
151
152 pub fn cb_ec_string_string() -> (Receiver<(ErrorCode, String, String)>, IndyHandle, Option<ResponseStringStringCB>) {
153 let (sender, receiver) = channel();
154
155 let closure = Box::new(move |err, val1, val2| {
156 sender.send((err, val1, val2)).unwrap_or_else(log_error);
157 });
158
159 let (command_handle, cb) = ClosureHandler::convert_cb_ec_string_string(closure);
160
161 (receiver, command_handle, cb)
162 }
163
164 pub fn convert_cb_ec_string_string(closure: Box<FnMut(ErrorCode, String, String) + Send>) -> (IndyHandle, Option<ResponseStringStringCB>) {
165 lazy_static! {
166 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, String, String) + Send>>> = Default::default();
167 }
168
169 extern "C" fn _callback(command_handle: IndyHandle, err: i32, str1: *const c_char, str2: *const c_char) {
170 let mut callbacks = CALLBACKS.lock().unwrap();
171 let mut cb = callbacks.remove(&command_handle).unwrap();
172 let str1 = rust_str!(str1);
173 let str2 = rust_str!(str2);
174 cb(ErrorCode::from(err), str1, str2)
175 }
176
177 let mut callbacks = CALLBACKS.lock().unwrap();
178 let command_handle = SequenceUtils::get_next_id();
179 callbacks.insert(command_handle, closure);
180
181 (command_handle, Some(_callback))
182 }
183
184 pub fn cb_ec_string_opt_string() -> (Receiver<(ErrorCode, String, Option<String>)>, IndyHandle, Option<ResponseStringStringCB>) {
185 let (sender, receiver) = channel();
186
187 let closure = Box::new(move |err, val1, val2| {
188 sender.send((err, val1, val2)).unwrap_or_else(log_error);
189 });
190
191 let (command_handle, cb) = ClosureHandler::convert_cb_ec_string_opt_string(closure);
192
193 (receiver, command_handle, cb)
194 }
195
196 pub fn convert_cb_ec_string_opt_string(closure: Box<FnMut(ErrorCode, String, Option<String>) + Send>) -> (IndyHandle, Option<ResponseStringStringCB>) {
197 lazy_static! {
198 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, String, Option<String>) + Send>>> = Default::default();
199 }
200
201 extern "C" fn _callback(command_handle: IndyHandle, err: i32, str1: *const c_char, str2: *const c_char) {
202 let mut callbacks = CALLBACKS.lock().unwrap();
203 let mut cb = callbacks.remove(&command_handle).unwrap();
204 let str1 = rust_str!(str1);
205 let str2 = opt_rust_str!(str2);
206 cb(ErrorCode::from(err), str1, str2)
207 }
208
209 let mut callbacks = CALLBACKS.lock().unwrap();
210 let command_handle = SequenceUtils::get_next_id();
211 callbacks.insert(command_handle, closure);
212
213 (command_handle, Some(_callback))
214 }
215
216 pub fn cb_ec_string_string_string() -> (Receiver<(ErrorCode, String, String, String)>, IndyHandle, Option<ResponseStringStringStringCB>) {
217 let (sender, receiver) = channel();
218
219 let closure = Box::new(move |err, val1, val2, val3| {
220 sender.send((err, val1, val2, val3)).unwrap_or_else(log_error);
221 });
222 let (command_handle, cb) = ClosureHandler::convert_cb_ec_string_string_string(closure);
223
224 (receiver, command_handle, cb)
225 }
226
227 pub fn convert_cb_ec_string_string_string(closure: Box<FnMut(ErrorCode, String, String, String) + Send>) -> (IndyHandle, Option<ResponseStringStringStringCB>) {
228 lazy_static! {
229 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, String, String, String) + Send>>> = Default::default();
230 }
231
232 extern "C" fn _callback(command_handle: IndyHandle, err: i32, str1: *const c_char, str2: *const c_char, str3: *const c_char) {
233 let mut callbacks = CALLBACKS.lock().unwrap();
234 let mut cb = callbacks.remove(&command_handle).unwrap();
235 let str1 = rust_str!(str1);
236 let str2 = rust_str!(str2);
237 let str3 = rust_str!(str3);
238 cb(ErrorCode::from(err), str1, str2, str3)
239 }
240
241 let mut callbacks = CALLBACKS.lock().unwrap();
242 let command_handle = SequenceUtils::get_next_id();
243 callbacks.insert(command_handle, closure);
244
245 (command_handle, Some(_callback))
246 }
247
248 pub fn cb_ec_string_opt_string_opt_string() -> (Receiver<(ErrorCode, String, Option<String>, Option<String>)>, IndyHandle, Option<ResponseStringStringStringCB>) {
249 let (sender, receiver) = channel();
250
251 let closure = Box::new(move |err, val1, val2, val3| {
252 sender.send((err, val1, val2, val3)).unwrap_or_else(log_error);
253 });
254 let (command_handle, cb) = ClosureHandler::convert_cb_ec_string_opt_string_opt_string(closure);
255
256 (receiver, command_handle, cb)
257 }
258
259 pub fn convert_cb_ec_string_opt_string_opt_string(closure: Box<FnMut(ErrorCode, String, Option<String>, Option<String>) + Send>) -> (IndyHandle, Option<ResponseStringStringStringCB>) {
260 lazy_static! {
261 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, String, Option<String>, Option<String>) + Send>>> = Default::default();
262 }
263
264 extern "C" fn _callback(command_handle: IndyHandle, err: i32, str1: *const c_char, str2: *const c_char, str3: *const c_char) {
265 let mut callbacks = CALLBACKS.lock().unwrap();
266 let mut cb = callbacks.remove(&command_handle).unwrap();
267 let str1 = rust_str!(str1);
268 let str2 = opt_rust_str!(str2);
269 let str3 = opt_rust_str!(str3);
270 cb(ErrorCode::from(err), str1, str2, str3)
271 }
272
273 let mut callbacks = CALLBACKS.lock().unwrap();
274 let command_handle = SequenceUtils::get_next_id();
275 callbacks.insert(command_handle, closure);
276
277 (command_handle, Some(_callback))
278 }
279
280 pub fn cb_ec_string_string_u64() -> (Receiver<(ErrorCode, String, String, u64)>, IndyHandle, Option<ResponseStringStringU64CB>) {
281 let (sender, receiver) = channel();
282
283 let closure = Box::new(move |err, val1, val2, val3| {
284 sender.send((err, val1, val2, val3)).unwrap_or_else(log_error);
285 });
286
287 let (command_handle, cb) = ClosureHandler::convert_cb_ec_string_string_u64(closure);
288
289 (receiver, command_handle, cb)
290 }
291
292 pub fn convert_cb_ec_string_string_u64(closure: Box<FnMut(ErrorCode, String, String, u64) + Send>) -> (IndyHandle, Option<ResponseStringStringU64CB>) {
293 lazy_static! {
294 static ref CALLBACKS: Mutex <HashMap<i32, Box<FnMut(ErrorCode, String, String, u64) + Send>>> = Default::default();
295 }
296
297 extern "C" fn _callback(command_handle: IndyHandle, err: i32, str1: *const c_char, str2: *const c_char, arg1: u64) {
298 let mut callbacks = CALLBACKS.lock().unwrap();
299 let mut cb = callbacks.remove(&command_handle).unwrap();
300 let str1 = rust_str!(str1);
301 let str2 = rust_str!(str2);
302 cb(ErrorCode::from(err), str1, str2, arg1)
303 }
304
305 let mut callbacks = CALLBACKS.lock().unwrap();
306 let command_handle = SequenceUtils::get_next_id();
307 callbacks.insert(command_handle, closure);
308
309 (command_handle, Some(_callback))
310 }
311
312 pub fn cb_ec_slice() -> (Receiver<(ErrorCode, Vec<u8>)>, IndyHandle, Option<ResponseSliceCB>) {
313 let (sender, receiver) = channel();
314
315 let closure = Box::new(move |err, sig| {
316 sender.send((err, sig)).unwrap_or_else(log_error);
317 });
318
319 let (command_handle, cb) = ClosureHandler::convert_cb_ec_slice(closure);
320
321 (receiver, command_handle, cb)
322 }
323
324 pub fn convert_cb_ec_slice(closure: Box<FnMut(ErrorCode, Vec<u8>) + Send>) -> (IndyHandle, Option<ResponseSliceCB>) {
325 lazy_static! {
326 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, Vec<u8>) + Send>>> = Default::default();
327 }
328
329 extern "C" fn _callback(command_handle: IndyHandle, err: i32, raw: *const u8, len: u32) {
330 let mut callbacks = CALLBACKS.lock().unwrap();
331 let mut cb = callbacks.remove(&command_handle).unwrap();
332 let sig = rust_slice!(raw, len);
333 cb(ErrorCode::from(err), sig.to_vec())
334 }
335
336 let mut callbacks = CALLBACKS.lock().unwrap();
337 let command_handle = SequenceUtils::get_next_id();
338 callbacks.insert(command_handle, closure);
339
340 (command_handle, Some(_callback))
341 }
342
343 pub fn cb_ec_string_slice() -> (Receiver<(ErrorCode, String, Vec<u8>)>, IndyHandle, Option<ResponseStringSliceCB>) {
344 let (sender, receiver) = channel();
345
346 let closure = Box::new(move |err, key, msg| {
347 sender.send((err, key, msg)).unwrap_or_else(log_error);
348 });
349
350 let (command_handle, cb) = ClosureHandler::convert_cb_ec_string_slice(closure);
351
352 (receiver, command_handle, cb)
353 }
354
355 pub fn convert_cb_ec_string_slice(closure: Box<FnMut(ErrorCode, String, Vec<u8>) + Send>) -> (IndyHandle, Option<ResponseStringSliceCB>) {
356 lazy_static! {
357 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, String, Vec<u8>) + Send> >> = Default::default();
358 }
359
360 extern "C" fn _callback(command_handle: IndyHandle, err: i32, vk: *const c_char, msg_raw: *const u8, msg_len: u32) {
361 let mut callbacks = CALLBACKS.lock().unwrap();
362 let mut cb = callbacks.remove(&command_handle).unwrap();
363 let key = rust_str!(vk);
364 let msg = rust_slice!(msg_raw, msg_len);
365 cb(ErrorCode::from(err), key, msg.to_vec())
366 }
367
368 let mut callbacks = CALLBACKS.lock().unwrap();
369 let command_handle = SequenceUtils::get_next_id();
370 callbacks.insert(command_handle, closure);
371
372 (command_handle, Some(_callback))
373 }
374
375 pub fn cb_ec_bool() -> (Receiver<(ErrorCode, bool)>, IndyHandle, Option<ResponseBoolCB>) {
376 let (sender, receiver) = channel();
377
378 let closure = Box::new(move |err, v| {
379 sender.send((err, v)).unwrap_or_else(log_error);
380 });
381
382 let (command_handle, cb) = ClosureHandler::convert_cb_ec_bool(closure);
383
384 (receiver, command_handle, cb)
385 }
386
387 pub fn convert_cb_ec_bool(closure: Box<FnMut(ErrorCode, bool) + Send>) -> (IndyHandle, Option<ResponseBoolCB>) {
388 lazy_static! {
389 static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(ErrorCode, bool) + Send> >> = Default::default();
390 }
391
392 extern "C" fn _callback(command_handle: IndyHandle, err: i32, valid: u8) {
393 let mut callbacks = CALLBACKS.lock().unwrap();
394 let mut cb = callbacks.remove(&command_handle).unwrap();
395 let v = valid > 0;
396 cb(ErrorCode::from(err), v)
397 }
398
399 let mut callbacks = CALLBACKS.lock().unwrap();
400 let command_handle = SequenceUtils::get_next_id();
401 callbacks.insert(command_handle, closure);
402
403 (command_handle, Some(_callback))
404 }
405}
406
407#[cfg(test)]
408mod test {
409 use super::*;
410
411 use std::ffi::CString;
412 use std::ptr::null;
413
414 #[test]
415 fn cb_ec_slice() {
416 let (receiver, command_handle, cb) = ClosureHandler::cb_ec_slice();
417
418 let test_vec: Vec<u8> = vec![250, 251, 252, 253, 254, 255];
419 let callback = cb.unwrap();
420 callback(command_handle, 0, test_vec.as_ptr(), test_vec.len() as u32);
421
422 let (err, slice1) = receiver.recv().unwrap();
423 assert_eq!(err, ErrorCode::Success);
424 assert_eq!(test_vec, slice1);
425 }
426
427 #[test]
428 fn ec_string_opt_string_null() {
429 let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_opt_string();
430
431 let callback = cb.unwrap();
432 callback(command_handle, 0, CString::new("This is a test").unwrap().as_ptr(), null());
433
434 let (err, str1, str2) = receiver.recv().unwrap();
435 assert_eq!(err, ErrorCode::Success);
436 assert_eq!(str1, "This is a test".to_string());
437 assert_eq!(str2, None);
438 }
439
440 #[test]
441 fn ec_string_opt_string_some() {
442 let (receiver, command_handle, cb) = ClosureHandler::cb_ec_string_opt_string();
443
444 let callback = cb.unwrap();
445 callback(command_handle, 0, CString::new("This is a test").unwrap().as_ptr(), CString::new("The second string has something").unwrap().as_ptr());
446
447 let (err, str1, str2) = receiver.recv().unwrap();
448 assert_eq!(err, ErrorCode::Success);
449 assert_eq!(str1, "This is a test".to_string());
450 assert_eq!(str2, Some("The second string has something".to_string()));
451 }
452}