1use crate::{free, Alpm, AnyDownloadEvent, AnyEvent, AnyQuestion, FetchResult, LogLevel, Progress};
2use alpm_sys_ll::*;
3use std::cell::{RefCell, UnsafeCell};
4use std::ffi::{c_void, CStr};
5use std::mem::transmute;
6use std::os::raw::{c_char, c_int};
7use std::{fmt, panic, ptr};
8
9extern "C" {
10 fn vasprintf(str: *const *mut c_char, fmt: *const c_char, args: *mut __va_list_tag) -> c_int;
11}
12
13type Cb<T> = UnsafeCell<Option<Box<T>>>;
14
15#[derive(Default)]
16pub(crate) struct Callbacks {
17 pub(crate) log: Cb<dyn LogCbTrait>,
18 pub(crate) dl: Cb<dyn DlCbTrait>,
19 pub(crate) event: Cb<dyn EventCbTrait>,
20 pub(crate) progress: Cb<dyn ProgressCbTrait>,
21 pub(crate) question: Cb<dyn QuestionCbTrait>,
22 pub(crate) fetch: Cb<dyn FetchCbTrait>,
23}
24
25pub(crate) trait LogCbTrait {
26 fn call(&self, level: LogLevel, s: &str);
27 fn assert_unlocked(&self);
28}
29
30pub(crate) trait DlCbTrait {
31 fn call(&self, filename: &str, event: AnyDownloadEvent);
32 fn assert_unlocked(&self);
33}
34
35pub(crate) trait EventCbTrait {
36 fn call(&self, event: AnyEvent);
37 fn handle(&self) -> *mut alpm_handle_t;
38 fn assert_unlocked(&self);
39}
40
41pub(crate) trait ProgressCbTrait {
42 fn call(&self, progress: Progress, pkgname: &str, percent: i32, howmany: usize, current: usize);
43 fn assert_unlocked(&self);
44}
45
46pub(crate) trait QuestionCbTrait {
47 fn call(&self, question: AnyQuestion);
48 fn handle(&self) -> *mut alpm_handle_t;
49 fn assert_unlocked(&self);
50}
51
52pub(crate) trait FetchCbTrait {
53 fn call(&self, url: &str, filename: &str, force: bool) -> FetchResult;
54 fn assert_unlocked(&self);
55}
56
57struct LogCbImpl<T, F>(RefCell<(F, T)>);
58
59impl<T, F: FnMut(LogLevel, &str, &mut T)> LogCbTrait for LogCbImpl<T, F> {
60 fn call(&self, level: LogLevel, s: &str) {
61 let mut cb = self.0.borrow_mut();
62 let cb = &mut *cb;
63 (cb.0)(level, s, &mut cb.1)
64 }
65 fn assert_unlocked(&self) {
66 self.0.try_borrow_mut().expect("callback is in use");
67 }
68}
69
70struct DlCbImpl<T, F>(RefCell<(F, T)>);
71
72impl<T, F: FnMut(&str, AnyDownloadEvent, &mut T)> DlCbTrait for DlCbImpl<T, F> {
73 fn call(&self, s: &str, event: AnyDownloadEvent) {
74 let mut cb = self.0.borrow_mut();
75 let cb = &mut *cb;
76 (cb.0)(s, event, &mut cb.1)
77 }
78 fn assert_unlocked(&self) {
79 self.0.try_borrow_mut().expect("callback is in use");
80 }
81}
82
83struct EventCbImpl<T, F>(RefCell<(F, T)>, *mut alpm_handle_t);
84
85impl<T, F: FnMut(AnyEvent, &mut T)> EventCbTrait for EventCbImpl<T, F> {
86 fn call(&self, event: AnyEvent) {
87 let mut cb = self.0.borrow_mut();
88 let cb = &mut *cb;
89 (cb.0)(event, &mut cb.1)
90 }
91
92 fn assert_unlocked(&self) {
93 self.0.try_borrow_mut().expect("callback is in use");
94 }
95
96 fn handle(&self) -> *mut alpm_handle_t {
97 self.1
98 }
99}
100
101struct ProgressCbImpl<T, F>(RefCell<(F, T)>);
102
103impl<T, F: FnMut(Progress, &str, i32, usize, usize, &mut T)> ProgressCbTrait
104 for ProgressCbImpl<T, F>
105{
106 fn call(
107 &self,
108 progress: Progress,
109 pkgname: &str,
110 percent: i32,
111 howmany: usize,
112 current: usize,
113 ) {
114 let mut cb = self.0.borrow_mut();
115 let cb = &mut *cb;
116 (cb.0)(progress, pkgname, percent, howmany, current, &mut cb.1)
117 }
118 fn assert_unlocked(&self) {
119 self.0.try_borrow_mut().expect("callback is in use");
120 }
121}
122
123struct QuestionCbImpl<T, F>(RefCell<(F, T)>, *mut alpm_handle_t);
124
125impl<T, F: FnMut(AnyQuestion, &mut T)> QuestionCbTrait for QuestionCbImpl<T, F> {
126 fn call(&self, question: AnyQuestion) {
127 let mut cb = self.0.borrow_mut();
128 let cb = &mut *cb;
129 (cb.0)(question, &mut cb.1)
130 }
131 fn assert_unlocked(&self) {
132 self.0.try_borrow_mut().expect("callback is in use");
133 }
134
135 fn handle(&self) -> *mut alpm_handle_t {
136 self.1
137 }
138}
139
140struct FetchCbImpl<T, F>(RefCell<(F, T)>);
141
142impl<T, F: FnMut(&str, &str, bool, &mut T) -> FetchResult> FetchCbTrait for FetchCbImpl<T, F> {
143 fn call(&self, url: &str, filename: &str, force: bool) -> FetchResult {
144 let mut cb = self.0.borrow_mut();
145 let cb = &mut *cb;
146 (cb.0)(url, filename, force, &mut cb.1)
147 }
148
149 fn assert_unlocked(&self) {
150 self.0.try_borrow_mut().expect("callback is in use");
151 }
152}
153
154pub struct RawLogCb {
155 pub(crate) raw: alpm_cb_log,
156 pub(crate) ctx: *mut c_void,
157 pub(crate) cb: Option<Box<dyn LogCbTrait>>,
158}
159
160impl fmt::Debug for RawLogCb {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 f.write_str("RawLogCb")
163 }
164}
165
166pub struct RawDlCb {
167 pub(crate) raw: alpm_cb_download,
168 pub(crate) ctx: *mut c_void,
169 pub(crate) cb: Option<Box<dyn DlCbTrait>>,
170}
171
172impl fmt::Debug for RawDlCb {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 f.write_str("RawDlCb")
175 }
176}
177
178pub struct RawEventCb {
179 pub(crate) raw: alpm_cb_event,
180 pub(crate) ctx: *mut c_void,
181 pub(crate) cb: Option<Box<dyn EventCbTrait>>,
182}
183
184impl fmt::Debug for RawEventCb {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 f.write_str("RawEventCb")
187 }
188}
189
190pub struct RawProgressCb {
191 pub(crate) raw: alpm_cb_progress,
192 pub(crate) ctx: *mut c_void,
193 pub(crate) cb: Option<Box<dyn ProgressCbTrait>>,
194}
195
196impl fmt::Debug for RawProgressCb {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 f.write_str("RawProgressCb")
199 }
200}
201
202pub struct RawQuestionCb {
203 pub(crate) raw: alpm_cb_question,
204 pub(crate) ctx: *mut c_void,
205 pub(crate) cb: Option<Box<dyn QuestionCbTrait>>,
206}
207
208impl fmt::Debug for RawQuestionCb {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 f.write_str("RawQuestionCb")
211 }
212}
213
214pub struct RawFetchCb {
215 pub(crate) raw: alpm_cb_fetch,
216 pub(crate) ctx: *mut c_void,
217 pub(crate) cb: Option<Box<dyn FetchCbTrait>>,
218}
219
220impl fmt::Debug for RawFetchCb {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 f.write_str("RawFetchCb")
223 }
224}
225
226impl Alpm {
227 pub fn set_log_cb<T: 'static, F: FnMut(LogLevel, &str, &mut T) + 'static>(
228 &self,
229 data: T,
230 f: F,
231 ) {
232 let c = unsafe { &mut *self.cbs.log.get() };
233 if let Some(cb) = c.as_ref() {
234 cb.assert_unlocked()
235 }
236 let ctx = LogCbImpl(RefCell::new((f, data)));
237 let ctx = Box::new(ctx);
238 let cb = logcb::<LogCbImpl<T, F>>;
239 unsafe { self.lib.alpm_option_set_logcb(self.as_ptr(), Some(cb), &*ctx as *const _ as *mut _) };
240 c.replace(ctx);
241 }
242
243 pub fn set_dl_cb<T: 'static, F: FnMut(&str, AnyDownloadEvent, &mut T) + 'static>(
244 &self,
245 data: T,
246 f: F,
247 ) {
248 let c = unsafe { &mut *self.cbs.dl.get() };
249 if let Some(cb) = c.as_ref() {
250 cb.assert_unlocked()
251 }
252
253 if let Some(cb) = c.as_ref() {
254 cb.assert_unlocked()
255 }
256 let ctx = DlCbImpl(RefCell::new((f, data)));
257 let ctx = Box::new(ctx);
258 let cb = dlcb::<DlCbImpl<T, F>>;
259 unsafe { self.lib.alpm_option_set_dlcb(self.as_ptr(), Some(cb), &*ctx as *const _ as *mut _) };
260 c.replace(ctx);
261 }
262
263 pub fn set_event_cb<T: 'static, F: FnMut(AnyEvent, &mut T) + 'static>(&self, data: T, f: F) {
264 let c = unsafe { &mut *self.cbs.event.get() };
265 if let Some(cb) = c.as_ref() {
266 cb.assert_unlocked()
267 }
268 let ctx = EventCbImpl(RefCell::new((f, data)), self.as_ptr());
269 let ctx = Box::new(ctx);
270 let cb = eventcb::<EventCbImpl<T, F>>;
271 unsafe { self.lib.alpm_option_set_eventcb(self.as_ptr(), Some(cb), &*ctx as *const _ as *mut _) };
272 c.replace(ctx);
273 }
274
275 pub fn set_progress_cb<
276 T: 'static,
277 F: FnMut(Progress, &str, i32, usize, usize, &mut T) + 'static,
278 >(
279 &self,
280 data: T,
281 f: F,
282 ) {
283 let c = unsafe { &mut *self.cbs.progress.get() };
284 if let Some(cb) = c.as_ref() {
285 cb.assert_unlocked()
286 }
287 let ctx = ProgressCbImpl(RefCell::new((f, data)));
288 let ctx = Box::new(ctx);
289 let cb = progresscb::<ProgressCbImpl<T, F>>;
290 unsafe { self.lib.alpm_option_set_progresscb(self.as_ptr(), Some(cb), &*ctx as *const _ as *mut _) };
291 c.replace(ctx);
292 }
293
294 pub fn set_question_cb<T: 'static, F: FnMut(AnyQuestion, &mut T) + 'static>(
295 &self,
296 data: T,
297 f: F,
298 ) {
299 let c = unsafe { &mut *self.cbs.question.get() };
300 if let Some(cb) = c.as_ref() {
301 cb.assert_unlocked()
302 }
303 let ctx = QuestionCbImpl(RefCell::new((f, data)), self.as_ptr());
304 let ctx = Box::new(ctx);
305 let cb = questioncb::<QuestionCbImpl<T, F>>;
306 unsafe { self.lib.alpm_option_set_questioncb(self.as_ptr(), Some(cb), &*ctx as *const _ as *mut _) };
307 c.replace(ctx);
308 }
309
310 pub fn set_fetch_cb<T: 'static, F: FnMut(&str, &str, bool, &mut T) -> FetchResult + 'static>(
311 &self,
312 data: T,
313 f: F,
314 ) {
315 let c = unsafe { &mut *self.cbs.fetch.get() };
316 if let Some(cb) = c.as_ref() {
317 cb.assert_unlocked()
318 }
319 let ctx = FetchCbImpl(RefCell::new((f, data)));
320 let ctx = Box::new(ctx);
321 let cb = fetchcb::<FetchCbImpl<T, F>>;
322 unsafe { self.lib.alpm_option_set_fetchcb(self.as_ptr(), Some(cb), &*ctx as *const _ as *mut _) };
323 c.replace(ctx);
324 }
325
326 pub fn take_raw_log_cb(&self) -> RawLogCb {
327 let c = unsafe { &mut *self.cbs.log.get() };
328 if let Some(cb) = c.as_ref() {
329 cb.assert_unlocked()
330 }
331
332 let cb = RawLogCb {
333 ctx: unsafe { self.lib.alpm_option_get_logcb_ctx(self.as_ptr()) },
334 raw: unsafe { self.lib.alpm_option_get_logcb(self.as_ptr()) },
335 cb: c.take(),
336 };
337 unsafe { self.lib.alpm_option_set_logcb(self.as_ptr(), None, ptr::null_mut()) };
338 cb
339 }
340
341 pub fn set_raw_log_cb(&self, cb: RawLogCb) {
342 let c = unsafe { &mut *self.cbs.log.get() };
343 if let Some(cb) = c.as_ref() {
344 cb.assert_unlocked()
345 }
346 unsafe { self.lib.alpm_option_set_logcb(self.as_ptr(), cb.raw, cb.ctx) };
347 *c = cb.cb
348 }
349
350 pub fn take_raw_dl_cb(&self) -> RawDlCb {
351 let c = unsafe { &mut *self.cbs.dl.get() };
352 if let Some(cb) = c.as_ref() {
353 cb.assert_unlocked()
354 }
355 let cb = RawDlCb {
356 ctx: unsafe { self.lib.alpm_option_get_dlcb_ctx(self.as_ptr()) },
357 raw: unsafe { self.lib.alpm_option_get_dlcb(self.as_ptr()) },
358 cb: c.take(),
359 };
360 unsafe { self.lib.alpm_option_set_dlcb(self.as_ptr(), None, ptr::null_mut()) };
361 cb
362 }
363
364 pub fn set_raw_dl_cb(&self, cb: RawDlCb) {
365 let c = unsafe { &mut *self.cbs.dl.get() };
366 if let Some(cb) = c.as_ref() {
367 cb.assert_unlocked()
368 }
369 unsafe { self.lib.alpm_option_set_dlcb(self.as_ptr(), cb.raw, cb.ctx) };
370 *c = cb.cb
371 }
372
373 pub fn take_raw_event_cb(&self) -> RawEventCb {
374 let c = unsafe { &mut *self.cbs.event.get() };
375 if let Some(cb) = c.as_ref() {
376 cb.assert_unlocked()
377 }
378 let cb = RawEventCb {
379 ctx: unsafe { self.lib.alpm_option_get_eventcb_ctx(self.as_ptr()) },
380 raw: unsafe { self.lib.alpm_option_get_eventcb(self.as_ptr()) },
381 cb: c.take(),
382 };
383 unsafe { self.lib.alpm_option_set_eventcb(self.as_ptr(), None, ptr::null_mut()) };
384 cb
385 }
386
387 pub fn set_raw_event_cb(&self, cb: RawEventCb) {
388 let c = unsafe { &mut *self.cbs.event.get() };
389 if let Some(cb) = c.as_ref() {
390 cb.assert_unlocked()
391 }
392
393 unsafe { self.lib.alpm_option_set_eventcb(self.as_ptr(), cb.raw, cb.ctx) };
394 *c = cb.cb
395 }
396
397 pub fn take_raw_progress_cb(&self) -> RawProgressCb {
398 let c = unsafe { &mut *self.cbs.progress.get() };
399 if let Some(cb) = c.as_ref() {
400 cb.assert_unlocked()
401 }
402
403 let cb = RawProgressCb {
404 ctx: unsafe { self.lib.alpm_option_get_progresscb_ctx(self.as_ptr()) },
405 raw: unsafe { self.lib.alpm_option_get_progresscb(self.as_ptr()) },
406 cb: c.take(),
407 };
408 unsafe { self.lib.alpm_option_set_progresscb(self.as_ptr(), None, ptr::null_mut()) };
409 cb
410 }
411
412 pub fn set_raw_progress_cb(&self, cb: RawProgressCb) {
413 let c = unsafe { &mut *self.cbs.progress.get() };
414 if let Some(cb) = c.as_ref() {
415 cb.assert_unlocked()
416 }
417
418 unsafe { self.lib.alpm_option_set_progresscb(self.as_ptr(), cb.raw, cb.ctx) };
419 *c = cb.cb;
420 }
421
422 pub fn take_raw_question_cb(&self) -> RawQuestionCb {
423 let c = unsafe { &mut *self.cbs.question.get() };
424 if let Some(cb) = c.as_ref() {
425 cb.assert_unlocked()
426 }
427
428 let cb = RawQuestionCb {
429 ctx: unsafe { self.lib.alpm_option_get_questioncb_ctx(self.as_ptr()) },
430 raw: unsafe { self.lib.alpm_option_get_questioncb(self.as_ptr()) },
431 cb: c.take(),
432 };
433 unsafe { self.lib.alpm_option_set_questioncb(self.as_ptr(), None, ptr::null_mut()) };
434 cb
435 }
436
437 pub fn set_raw_question_cb(&self, cb: RawQuestionCb) {
438 let c = unsafe { &mut *self.cbs.question.get() };
439 if let Some(cb) = c.as_ref() {
440 cb.assert_unlocked()
441 }
442
443 unsafe { self.lib.alpm_option_set_questioncb(self.as_ptr(), cb.raw, cb.ctx) };
444 *c = cb.cb;
445 }
446
447 pub fn take_raw_fetch_cb(&self) -> RawFetchCb {
448 let c = unsafe { &mut *self.cbs.fetch.get() };
449 if let Some(cb) = c.as_ref() {
450 cb.assert_unlocked()
451 }
452
453 let cb = RawFetchCb {
454 ctx: unsafe { self.lib.alpm_option_get_fetchcb_ctx(self.as_ptr()) },
455 raw: unsafe { self.lib.alpm_option_get_fetchcb(self.as_ptr()) },
456 cb: c.take(),
457 };
458
459 unsafe { self.lib.alpm_option_set_fetchcb(self.as_ptr(), None, ptr::null_mut()) };
460 cb
461 }
462
463 pub fn set_raw_fetch_cb(&self, cb: RawFetchCb) {
464 let c = unsafe { &mut *self.cbs.fetch.get() };
465 if let Some(cb) = c.as_ref() {
466 cb.assert_unlocked()
467 }
468
469 unsafe { self.lib.alpm_option_set_fetchcb(self.as_ptr(), cb.raw, cb.ctx) };
470 *c = cb.cb;
471 }
472}
473
474extern "C" fn logcb<C: LogCbTrait>(
475 ctx: *mut c_void,
476 level: alpm_loglevel_t,
477 fmt: *const c_char,
478 args: *mut __va_list_tag,
479) {
480 let buff = ptr::null_mut();
481 let n = unsafe { vasprintf(&buff, fmt, args) };
482 if n != -1 {
483 let _ = panic::catch_unwind(|| {
484 let s = unsafe { CStr::from_ptr(buff) };
485 let level = LogLevel::from_bits(level).unwrap();
486 let cb = unsafe { &*(ctx as *const C) };
487 cb.call(level, &s.to_string_lossy());
488 });
489
490 unsafe { free(buff as *mut c_void) };
491 }
492}
493
494extern "C" fn dlcb<C: DlCbTrait>(
495 ctx: *mut c_void,
496 filename: *const c_char,
497 event: alpm_download_event_type_t,
498 data: *mut c_void,
499) {
500 let _ = panic::catch_unwind(|| {
501 let filename = unsafe { CStr::from_ptr(filename) };
502 let filename = filename.to_str().unwrap();
503 let event = unsafe { AnyDownloadEvent::new(event, data) };
504 let cb = unsafe { &*(ctx as *const C) };
505 cb.call(filename, event);
506 });
507}
508
509extern "C" fn fetchcb<C: FetchCbTrait>(
510 ctx: *mut c_void,
511 url: *const c_char,
512 localpath: *const c_char,
513 force: c_int,
514) -> c_int {
515 let ret = panic::catch_unwind(|| {
516 let url = unsafe { CStr::from_ptr(url).to_str().unwrap() };
517 let localpath = unsafe { CStr::from_ptr(localpath).to_str().unwrap() };
518 let cb = unsafe { &*(ctx as *const C) };
519 let ret = cb.call(url, localpath, force != 0);
520
521 match ret {
522 FetchResult::Ok => 0,
523 FetchResult::Err => -1,
524 FetchResult::FileExists => 1,
525 }
526 });
527
528 ret.unwrap_or(-1)
529}
530
531extern "C" fn eventcb<C: EventCbTrait>(ctx: *mut c_void, event: *mut alpm_event_t) {
532 let _ = panic::catch_unwind(|| {
533 let cb = unsafe { &*(ctx as *const C) };
534
535 let event = unsafe { AnyEvent::new(cb.handle(), event) };
536 cb.call(event);
537 });
538}
539
540extern "C" fn questioncb<C: QuestionCbTrait>(ctx: *mut c_void, question: *mut alpm_question_t) {
541 let _ = panic::catch_unwind(|| {
542 let cb = unsafe { &*(ctx as *const C) };
543 let question = unsafe { AnyQuestion::new(cb.handle(), question) };
544 cb.call(question);
545 });
546}
547
548extern "C" fn progresscb<C: ProgressCbTrait>(
549 ctx: *mut c_void,
550 progress: alpm_progress_t,
551 pkgname: *const c_char,
552 percent: c_int,
553 howmany: usize,
554 current: usize,
555) {
556 let _ = panic::catch_unwind(|| {
557 let pkgname = unsafe { CStr::from_ptr(pkgname) };
558 let pkgname = pkgname.to_str().unwrap();
559 let progress = unsafe { transmute::<alpm_progress_t, Progress>(progress) };
560 let cb = unsafe { &*(ctx as *const C) };
561 cb.call(progress, pkgname, percent as i32, howmany, current);
562 });
563}
564
565#[cfg(test)]
566mod tests {
567 use super::*;
568 use crate::{
569 log_action, version, AnyDownloadEvent, AnyEvent, AnyQuestion, Capabilities, DownloadEvent,
570 Event, FetchResult, Progress, Question, SigLevel,
571 };
572 use std::cell::Cell;
573 use std::rc::Rc;
574
575 fn eventcb(event: AnyEvent, _: &mut ()) {
576 match event.event() {
577 Event::DatabaseMissing(x) => println!("missing database: {}", x.dbname()),
578 _ => println!("event: {:?}", event),
579 }
580 }
581
582 fn fetchcb(_url: &str, _path: &str, _force: bool, _: &mut ()) -> FetchResult {
583 FetchResult::Ok
584 }
585
586 fn questioncb(question: AnyQuestion, _: &mut ()) {
587 println!("question {:?}", question);
588 match question.question() {
589 Question::Conflict(x) => {
590 let c = x.conflict();
591 println!("CONFLICT BETWEEN {} AND {}", c.package1(), c.package2(),);
592 println!("conflict: {}", c.reason());
593 }
594 _ => (),
595 }
596 }
597
598 fn downloadcb(filename: &str, download: AnyDownloadEvent, _: &mut ()) {
599 match download.event() {
600 DownloadEvent::Init(init) => {
601 println!("init: file={} optional={}", filename, init.optional)
602 }
603 DownloadEvent::Completed(comp) => println!(
604 "complete: file={} total={} result={:?}",
605 filename, comp.total, comp.result
606 ),
607 _ => (),
608 }
609 }
610
611 fn progresscb(
612 progress: Progress,
613 pkgname: &str,
614 percent: i32,
615 howmany: usize,
616 current: usize,
617 _: &mut (),
618 ) {
619 println!(
620 "progress {:?}, {} {} {} {}",
621 progress, pkgname, percent, howmany, current
622 );
623 }
624
625 #[test]
626 fn test_capabilities() {
627 let _caps = Capabilities::new();
628 }
629
630 #[test]
631 fn test_init() {
632 let _handle = Alpm::new("/", "tests/db").unwrap();
633 }
634
635 #[test]
636 fn test_version() {
637 assert!(!version().is_empty());
638 }
639
640 #[test]
641 fn test_cb() {
642 let mut handle = Alpm::new("/", "tests/db").unwrap();
643
644 handle.set_use_syslog(true);
645 handle.set_logfile("tests/log").unwrap();
646 handle.set_log_cb(0, |_, msg, data| {
647 print!("log {} {}", data, msg);
648 *data += 1;
649 });
650 handle.set_event_cb((), eventcb);
651 handle.set_fetch_cb((), fetchcb);
652 handle.set_question_cb((), questioncb);
653 handle.set_dl_cb((), downloadcb);
654 handle.set_progress_cb((), progresscb);
655
656 log_action!(handle, "me", "look i am logging an action {}", ":D").unwrap();
657 handle
658 .log_action("me", "look i am logging an action 2")
659 .unwrap();
660 handle
661 .log_action("me", "look i am logging an action 2")
662 .unwrap();
663 handle
664 .log_action("me", "look i am logging an action 2")
665 .unwrap();
666 handle
667 .log_action("me", "look i am logging an action 2")
668 .unwrap();
669 handle
670 .log_action("me", "look i am logging an action 2")
671 .unwrap();
672
673 let db = handle.register_syncdb_mut("core", SigLevel::NONE).unwrap();
674 db.add_server("https://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/core/os/x86_64")
675 .unwrap();
676 db.pkg("filesystem").unwrap();
677 }
678
679 #[test]
680 fn test_cb_data() {
681 let handle = Alpm::new("/", "tests/db").unwrap();
682
683 let data = Rc::new(Cell::new(0));
684
685 handle.set_log_cb(data.clone(), |_, _, data| data.set(7));
686 handle.register_syncdb("core", SigLevel::NONE).unwrap();
687
688 assert_eq!(data.get(), 7);
689 }
690
691 #[test]
692 fn test_cb_refcell1() {
693 let handle = Alpm::new("/", "tests/db").unwrap();
694 let handle = Rc::new(handle);
695
696 handle.set_log_cb(Rc::downgrade(&handle), |_, msg, data| {
697 let handle = data.upgrade().unwrap();
698 println!("{} {:?}", msg, handle);
699 handle.take_raw_log_cb();
700 });
701 handle.register_syncdb("core", SigLevel::NONE).unwrap();
702 }
703
704 #[test]
705 fn test_cb_refcell2() {
706 let handle = Alpm::new("/", "tests/db").unwrap();
707 let handle = Rc::new(handle);
708
709 handle.set_log_cb(Rc::downgrade(&handle), |_, msg, data| {
710 let handle = data.upgrade().unwrap();
711 println!("{} {:?}", msg, handle);
712 handle.set_log_cb((), |_, _, _| {});
713 });
714 handle.register_syncdb("core", SigLevel::NONE).unwrap();
715 }
716
717 #[ignore]
718 #[test]
719 fn test_cb_refcell_mut() {
720 let handle = Alpm::new("/", "tests/db").unwrap();
721 let handle = Rc::new(RefCell::new(handle));
722 let borrow = handle.borrow();
723 let db = borrow.register_syncdb("core", SigLevel::NONE).unwrap();
724
725 handle
726 .borrow()
727 .set_log_cb(Rc::clone(&handle), |_, msg, data| {
728 let handle = data;
729 println!("{} {:?}", msg, handle);
730 handle.borrow_mut().unregister_all_syncdbs().unwrap();
731 println!("Done");
732 });
733
734 println!("{:?}", db.pkg("linux"));
735 assert_eq!(handle.borrow().syncdbs().len(), 1);
736 }
737
738 #[test]
739 fn test_cb_drop() {
740 let handle = Alpm::new("/", "tests/db").unwrap();
741 let mut val = Rc::new(42);
742 handle.set_log_cb(Rc::clone(&val), |_, _, _| ());
743 assert!(Rc::get_mut(&mut val).is_none());
744 let cb = handle.take_raw_log_cb();
745 assert!(Rc::get_mut(&mut val).is_none());
746 drop(cb);
747 Rc::get_mut(&mut val).unwrap();
748 drop(handle);
749 }
750}