rust_libindy_wrapper/utils/
callbacks.rs

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}