1use alpm_sys::*;
2
3use crate::{
4 AlpmList, Backup, Conflict, Db, DbMut, Dep, DepMissing, Depend, DependMissing, FileConflict,
5 IntoAlpmListItem, Iter, LoadedPackage, OwnedConflict, OwnedFileConflict, Package, Pkg, free,
6};
7
8use std::ffi::c_void;
9use std::fmt;
10use std::fmt::Debug;
11use std::iter::FromIterator;
12use std::marker::PhantomData;
13use std::mem::ManuallyDrop;
14use std::ptr;
15
16unsafe extern "C" {
17 unsafe fn calloc(n: usize, s: usize) -> *mut c_void;
18 unsafe fn memcpy(dst: *mut c_void, src: *const c_void, n: usize);
19}
20
21fn alloc_str(s: &str) -> *mut c_void {
22 let buf = unsafe { calloc(s.len() + 1, 1) };
23 unsafe {
24 memcpy(buf, s.as_ptr() as _, s.len());
25 }
26 buf as _
27}
28
29#[doc(hidden)]
30pub unsafe trait BorrowAlpmListItem<'a> {
31 type Borrow: IntoAlpmListItem;
32}
33
34#[doc(hidden)]
35pub unsafe trait IntoAlpmListPtr: Sized {
36 type Output: IntoAlpmListItem;
37 fn into_ptr(self) -> *mut c_void {
38 ManuallyDrop::new(self).as_ptr()
39 }
40 fn as_ptr(&self) -> *mut c_void;
41}
42
43pub struct AlpmListMut<T: IntoAlpmListItem> {
44 _marker: PhantomData<T>,
45 list: *mut alpm_list_t,
46}
47
48unsafe impl<T: IntoAlpmListItem + Send> Send for AlpmListMut<T> {}
49unsafe impl<T: IntoAlpmListItem + Sync> Sync for AlpmListMut<T> {}
50
51impl<'a, T: IntoAlpmListItem + BorrowAlpmListItem<'a>> fmt::Debug for AlpmListMut<T>
52where
53 T::Borrow: Debug,
54{
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 fmt::Debug::fmt(&self.list(), f)
57 }
58}
59
60pub struct IntoIter<T: IntoAlpmListItem> {
61 list: *mut alpm_list_t,
62 start: *mut alpm_list_t,
63 _marker: PhantomData<T>,
64}
65
66unsafe impl<T: IntoAlpmListItem + Send> Send for IntoIter<T> {}
67unsafe impl<T: IntoAlpmListItem + Sync> Sync for IntoIter<T> {}
68
69impl<'a, T: IntoAlpmListItem + BorrowAlpmListItem<'a>> Debug for IntoIter<T>
70where
71 T::Borrow: Debug,
72{
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 unsafe {
75 f.debug_struct("Iter")
76 .field("list", &AlpmList::<T::Borrow>::from_ptr(self.list))
77 .finish()
78 }
79 }
80}
81
82impl<T: IntoAlpmListItem> Drop for AlpmListMut<T> {
83 fn drop(&mut self) {
84 let mut list = self.list;
85 let start = self.list;
86
87 while !list.is_null() {
88 unsafe { T::drop_item((*list).data) };
89 list = unsafe { (*list).next };
90 }
91
92 unsafe { alpm_list_free(start) }
93 }
94}
95
96impl<T: IntoAlpmListItem> IntoIterator for AlpmListMut<T> {
97 type IntoIter = IntoIter<T>;
98 type Item = T;
99
100 fn into_iter(self) -> Self::IntoIter {
101 let list = ManuallyDrop::new(self);
102 IntoIter {
103 list: list.list,
104 start: list.list,
105 _marker: PhantomData,
106 }
107 }
108}
109
110impl<'a, T: IntoAlpmListItem> IntoIterator for &'a AlpmListMut<T>
111where
112 T: BorrowAlpmListItem<'a>,
113{
114 type IntoIter = Iter<'a, T::Borrow>;
115 type Item = T::Borrow;
116
117 fn into_iter(self) -> Self::IntoIter {
118 self.list().into_iter()
119 }
120}
121
122impl<T: IntoAlpmListPtr> FromIterator<T> for AlpmListMut<T::Output> {
123 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
124 let mut list = AlpmListMut::new();
125 list.extend(iter);
126 list
127 }
128}
129
130impl<T: IntoAlpmListPtr> Extend<T> for AlpmListMut<T::Output> {
131 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
132 for item in iter {
133 self.push(item);
134 }
135 }
136}
137
138impl<'a, T: IntoAlpmListItem + BorrowAlpmListItem<'a>> AlpmListMut<T> {
139 pub fn list(&self) -> AlpmList<T::Borrow> {
140 unsafe { AlpmList::from_ptr(self.list) }
141 }
142}
143
144impl<T: IntoAlpmListItem> Default for AlpmListMut<T> {
145 fn default() -> Self {
146 Self::new()
147 }
148}
149
150impl<T: IntoAlpmListItem> AlpmListMut<T> {
151 pub(crate) unsafe fn from_ptr(list: *mut alpm_list_t) -> AlpmListMut<T> {
152 AlpmListMut {
153 list,
154 _marker: PhantomData,
155 }
156 }
157
158 pub fn new() -> AlpmListMut<T> {
159 AlpmListMut {
160 list: ptr::null_mut(),
161 _marker: PhantomData,
162 }
163 }
164
165 pub fn len(&self) -> usize {
166 unsafe { alpm_list_count(self.list) }
167 }
168
169 pub fn retain<F>(&mut self, mut f: F)
170 where
171 F: FnMut(&T) -> bool,
172 {
173 let mut curr = self.list;
174
175 while !curr.is_null() {
176 let item = unsafe { ManuallyDrop::new(T::into_list_item((*curr).data)) };
177 let next = unsafe { (*curr).next };
178 if !f(&item) {
179 ManuallyDrop::into_inner(item);
180 unsafe { self.list = alpm_list_remove_item(self.list, curr) };
181 unsafe { free(curr as _) };
182 }
183 curr = next;
184 }
185 }
186
187 pub fn remove(&mut self, n: usize) -> Option<T> {
188 if n >= self.len() {
189 return None;
190 }
191
192 let item = unsafe { alpm_list_nth(self.list, n) };
193 unsafe { self.list = alpm_list_remove_item(self.list, item) };
194 let ret = unsafe { Some(T::into_list_item((*item).data)) };
195 unsafe { free(item as _) };
196 ret
197 }
198
199 pub fn pop(&mut self) -> Option<T> {
200 if self.list.is_null() {
201 return None;
202 }
203
204 let last = unsafe { (*self.list).prev };
205 unsafe { self.list = alpm_list_remove_item(self.list, last) };
206 let ret = unsafe { Some(T::into_list_item((*last).data)) };
207 unsafe { free(last as _) };
208 ret
209 }
210}
211
212impl<T: IntoAlpmListItem> AlpmListMut<T> {
213 pub fn push<U: IntoAlpmListPtr<Output = T>>(&mut self, t: U) {
214 unsafe { self.list = alpm_list_add(self.list, U::into_ptr(t)) }
215 }
216}
217
218impl AlpmListMut<String> {
219 pub fn push_str(&mut self, s: &str) {
220 let s = alloc_str(s);
221 unsafe { self.list = alpm_list_add(self.list, s as *mut c_void) };
222 }
223}
224
225impl<T: IntoAlpmListItem> AlpmListMut<T> {
227 pub fn is_empty(&self) -> bool {
228 self.list.is_null()
229 }
230}
231
232impl<'a, T: IntoAlpmListItem + BorrowAlpmListItem<'a>> AlpmListMut<T> {
233 pub fn first(&self) -> Option<T::Borrow> {
234 self.list().first()
235 }
236
237 pub fn last(&self) -> Option<T::Borrow> {
238 self.list().last()
239 }
240
241 pub fn iter(&self) -> Iter<T::Borrow> {
242 unsafe { AlpmList::from_ptr(self.list).into_iter() }
243 }
244}
245
246impl<T: IntoAlpmListItem> Drop for IntoIter<T> {
247 fn drop(&mut self) {
248 let mut list = self.list;
249
250 while !list.is_null() {
251 unsafe { T::drop_item((*list).data) };
252 list = unsafe { (*list).next };
253 }
254
255 unsafe { alpm_list_free(self.start) }
256 }
257}
258
259impl<T: IntoAlpmListItem> IntoIter<T> {
260 fn next_data(&mut self) -> Option<*mut c_void> {
261 if self.list.is_null() {
262 None
263 } else {
264 let data = unsafe { (*(self.list)).data };
265 self.list = unsafe { alpm_list_next(self.list) };
266
267 Some(data)
268 }
269 }
270}
271
272impl<T: IntoAlpmListItem> Iterator for IntoIter<T> {
273 type Item = T;
274
275 fn next(&mut self) -> Option<Self::Item> {
276 unsafe { self.next_data().map(|i| T::into_list_item(i)) }
277 }
278
279 fn size_hint(&self) -> (usize, Option<usize>) {
280 let size = unsafe { alpm_list_count(self.list) };
281 (size, Some(size))
282 }
283}
284
285unsafe impl<'a, T: IntoAlpmListPtr> IntoAlpmListPtr for &&'a T
288where
289 &'a T::Output: BorrowAlpmListItem<'a>,
290{
291 type Output = <&'a T::Output as BorrowAlpmListItem<'a>>::Borrow;
292 fn as_ptr(&self) -> *mut c_void {
293 T::as_ptr(*self)
294 }
295}
296
297unsafe impl IntoAlpmListPtr for Depend {
298 type Output = Self;
299 fn as_ptr(&self) -> *mut c_void {
300 Dep::as_ptr(self) as _
301 }
302}
303
304unsafe impl IntoAlpmListPtr for &Dep {
305 type Output = Self;
306 fn as_ptr(&self) -> *mut c_void {
307 Dep::as_ptr(self) as _
308 }
309}
310
311unsafe impl IntoAlpmListPtr for &Pkg {
312 type Output = Self;
313 fn as_ptr(&self) -> *mut c_void {
314 Pkg::as_ptr(self) as _
315 }
316}
317
318unsafe impl IntoAlpmListPtr for &Package {
319 type Output = Self;
320 fn as_ptr(&self) -> *mut c_void {
321 Pkg::as_ptr(self) as _
322 }
323}
324
325unsafe impl IntoAlpmListPtr for LoadedPackage<'_> {
326 type Output = Self;
327 fn as_ptr(&self) -> *mut c_void {
328 Pkg::as_ptr(self) as _
329 }
330}
331
332unsafe impl IntoAlpmListPtr for &Db {
333 type Output = Self;
334 fn as_ptr(&self) -> *mut c_void {
335 Db::as_ptr(self) as _
336 }
337}
338
339unsafe impl IntoAlpmListPtr for DbMut<'_> {
340 type Output = Self;
341 fn as_ptr(&self) -> *mut c_void {
342 Db::as_ptr(self) as _
343 }
344}
345
346unsafe impl IntoAlpmListPtr for DependMissing {
347 type Output = Self;
348 fn as_ptr(&self) -> *mut c_void {
349 DepMissing::as_ptr(self) as _
350 }
351}
352
353unsafe impl IntoAlpmListPtr for &DepMissing {
354 type Output = Self;
355 fn as_ptr(&self) -> *mut c_void {
356 DepMissing::as_ptr(self) as _
357 }
358}
359
360unsafe impl IntoAlpmListPtr for &Conflict {
361 type Output = Self;
362 fn as_ptr(&self) -> *mut c_void {
363 Conflict::as_ptr(self) as _
364 }
365}
366
367unsafe impl IntoAlpmListPtr for OwnedConflict {
368 type Output = Self;
369 fn as_ptr(&self) -> *mut c_void {
370 Conflict::as_ptr(self) as _
371 }
372}
373
374unsafe impl IntoAlpmListPtr for &FileConflict {
375 type Output = Self;
376 fn as_ptr(&self) -> *mut c_void {
377 FileConflict::as_ptr(self) as _
378 }
379}
380
381unsafe impl IntoAlpmListPtr for OwnedFileConflict {
382 type Output = Self;
383 fn as_ptr(&self) -> *mut c_void {
384 FileConflict::as_ptr(self) as _
385 }
386}
387
388unsafe impl IntoAlpmListPtr for &Backup {
389 type Output = Self;
390 fn as_ptr(&self) -> *mut c_void {
391 Backup::as_ptr(self) as _
392 }
393}
394
395unsafe impl IntoAlpmListPtr for String {
396 type Output = Self;
397 fn as_ptr(&self) -> *mut c_void {
398 alloc_str(self)
399 }
400 fn into_ptr(self) -> *mut c_void {
401 alloc_str(&self)
402 }
403}
404
405unsafe impl IntoAlpmListPtr for &String {
406 type Output = String;
407 fn as_ptr(&self) -> *mut c_void {
408 alloc_str(self)
409 }
410 fn into_ptr(self) -> *mut c_void {
411 alloc_str(&self)
412 }
413}
414
415unsafe impl IntoAlpmListPtr for &str {
416 type Output = String;
417 fn as_ptr(&self) -> *mut c_void {
418 alloc_str(&self)
419 }
420 fn into_ptr(self) -> *mut c_void {
421 alloc_str(&self)
422 }
423}
424
425unsafe impl IntoAlpmListPtr for &&str {
428 type Output = String;
429 fn as_ptr(&self) -> *mut c_void {
430 alloc_str(self)
431 }
432 fn into_ptr(self) -> *mut c_void {
433 alloc_str(&self)
434 }
435}
436
437unsafe impl<'a> IntoAlpmListPtr for &'a Depend {
438 type Output = &'a Dep;
439 fn as_ptr(&self) -> *mut c_void {
440 Dep::as_ptr(self) as _
441 }
442}
443
444unsafe impl<'a> IntoAlpmListPtr for &&'a Dep {
445 type Output = &'a Dep;
446 fn as_ptr(&self) -> *mut c_void {
447 Dep::as_ptr(self) as _
448 }
449}
450
451unsafe impl<'a> IntoAlpmListPtr for &&'a Package {
452 type Output = &'a Pkg;
453 fn as_ptr(&self) -> *mut c_void {
454 Pkg::as_ptr(self) as _
455 }
456}
457
458unsafe impl<'a> IntoAlpmListPtr for &&'a Pkg {
459 type Output = &'a Pkg;
460 fn as_ptr(&self) -> *mut c_void {
461 Pkg::as_ptr(self) as _
462 }
463}
464
465unsafe impl<'a> IntoAlpmListPtr for &LoadedPackage<'a> {
466 type Output = &'a Pkg;
467 fn as_ptr(&self) -> *mut c_void {
468 Pkg::as_ptr(self) as _
469 }
470}
471
472unsafe impl<'a> IntoAlpmListPtr for &&'a Db {
473 type Output = &'a Db;
474 fn as_ptr(&self) -> *mut c_void {
475 Db::as_ptr(self) as _
476 }
477}
478
479unsafe impl<'a> IntoAlpmListPtr for &DbMut<'a> {
480 type Output = DbMut<'a>;
481 fn as_ptr(&self) -> *mut c_void {
482 Db::as_ptr(self) as _
483 }
484}
485
486unsafe impl<'a> IntoAlpmListPtr for &'a DependMissing {
487 type Output = &'a DepMissing;
488 fn as_ptr(&self) -> *mut c_void {
489 DepMissing::as_ptr(self) as _
490 }
491}
492
493unsafe impl<'a> IntoAlpmListPtr for &&'a DepMissing {
494 type Output = &'a DepMissing;
495 fn as_ptr(&self) -> *mut c_void {
496 DepMissing::as_ptr(self) as _
497 }
498}
499
500unsafe impl<'a> IntoAlpmListPtr for &&'a Conflict {
501 type Output = &'a Conflict;
502 fn as_ptr(&self) -> *mut c_void {
503 Conflict::as_ptr(self) as _
504 }
505}
506
507unsafe impl<'a> IntoAlpmListPtr for &'a OwnedConflict {
508 type Output = &'a Conflict;
509 fn as_ptr(&self) -> *mut c_void {
510 Conflict::as_ptr(self) as _
511 }
512}
513
514unsafe impl<'a> IntoAlpmListPtr for &&'a FileConflict {
515 type Output = &'a FileConflict;
516 fn as_ptr(&self) -> *mut c_void {
517 FileConflict::as_ptr(self) as _
518 }
519}
520
521unsafe impl<'a> IntoAlpmListPtr for &'a OwnedFileConflict {
522 type Output = &'a FileConflict;
523 fn as_ptr(&self) -> *mut c_void {
524 FileConflict::as_ptr(self) as _
525 }
526}
527
528unsafe impl<'a> IntoAlpmListPtr for &&'a Backup {
529 type Output = &'a Backup;
530 fn as_ptr(&self) -> *mut c_void {
531 Backup::as_ptr(self) as _
532 }
533}
534
535unsafe impl<'a, T: BorrowAlpmListItem<'a>> BorrowAlpmListItem<'a> for &T {
538 type Borrow = T::Borrow;
539}
540
541unsafe impl<'a> BorrowAlpmListItem<'a> for Depend {
542 type Borrow = &'a Dep;
543}
544
545unsafe impl<'a> BorrowAlpmListItem<'a> for DbMut<'a> {
546 type Borrow = DbMut<'a>;
547}
548
549unsafe impl<'a> BorrowAlpmListItem<'a> for &Db {
550 type Borrow = &'a Db;
551}
552
553unsafe impl<'a> BorrowAlpmListItem<'a> for &Dep {
554 type Borrow = &'a Dep;
555}
556
557unsafe impl<'a> BorrowAlpmListItem<'a> for &Pkg {
558 type Borrow = &'a Pkg;
559}
560
561unsafe impl<'a> BorrowAlpmListItem<'a> for &Package {
562 type Borrow = &'a Pkg;
563}
564
565unsafe impl<'a> BorrowAlpmListItem<'a> for LoadedPackage<'a> {
566 type Borrow = &'a Pkg;
567}
568
569unsafe impl<'a> BorrowAlpmListItem<'a> for DependMissing {
570 type Borrow = &'a DepMissing;
571}
572
573unsafe impl<'a> BorrowAlpmListItem<'a> for &DepMissing {
574 type Borrow = &'a DepMissing;
575}
576
577unsafe impl<'a> BorrowAlpmListItem<'a> for &Conflict {
578 type Borrow = &'a Conflict;
579}
580
581unsafe impl<'a> BorrowAlpmListItem<'a> for OwnedConflict {
582 type Borrow = &'a Conflict;
583}
584
585unsafe impl<'a> BorrowAlpmListItem<'a> for &FileConflict {
586 type Borrow = &'a FileConflict;
587}
588
589unsafe impl<'a> BorrowAlpmListItem<'a> for OwnedFileConflict {
590 type Borrow = &'a FileConflict;
591}
592
593unsafe impl<'a> BorrowAlpmListItem<'a> for &Backup {
594 type Borrow = &'a Backup;
595}
596
597unsafe impl<'a> BorrowAlpmListItem<'a> for String {
598 type Borrow = &'a str;
599}
600
601unsafe impl<'a> BorrowAlpmListItem<'a> for &str {
602 type Borrow = &'a str;
603}
604
605#[cfg(test)]
606mod tests {
607 use super::*;
608 use crate::{Alpm, SigLevel};
609
610 #[test]
611 fn test_depends_list_free() {
612 let mut list = AlpmListMut::new();
613 list.push(Depend::new("aaaa"));
614 list.push(Depend::new("aaaa"));
615 list.push(Depend::new("aaaa"));
616 list.push(Depend::new("aaaa"));
617 }
618
619 #[test]
620 fn test_depends_list_free_iter() {
621 let mut list = AlpmListMut::new();
622 list.push(Depend::new("aaaa"));
623 list.push(Depend::new("aaaa"));
624 list.push(Depend::new("aaaa"));
625 list.push(Depend::new("aaaa"));
626 let mut iter = list.into_iter();
627 iter.next().unwrap();
628 }
629
630 #[test]
631 fn test_depends_list_pop() {
632 let mut list = AlpmListMut::new();
633 list.push(Depend::new("aaaa"));
634 list.push(Depend::new("bbbb"));
635 list.push(Depend::new("cccc"));
636 list.push(Depend::new("dddd"));
637 assert_eq!(list.pop().unwrap().name(), "dddd");
638 assert_eq!(list.pop().unwrap().name(), "cccc");
639 assert_eq!(list.pop().unwrap().name(), "bbbb");
640 assert_eq!(list.pop().unwrap().name(), "aaaa");
641 assert_eq!(list.pop(), None);
642 }
643
644 #[test]
645 fn test_depends_list_remove() {
646 let mut list = AlpmListMut::new();
647 list.push(Depend::new("aaaa"));
648 list.push(Depend::new("bbbb"));
649 list.push(Depend::new("cccc"));
650 list.push(Depend::new("dddd"));
651 assert_eq!(list.remove(0).unwrap().name(), "aaaa");
652 assert_eq!(list.remove(2).unwrap().name(), "dddd");
653 assert_eq!(list.remove(3), None);
654 }
655
656 #[test]
657 fn test_depends_list_from_iter() {
658 let vec = vec![
659 Depend::new("aaaa"),
660 Depend::new("bbbb"),
661 Depend::new("cccc"),
662 Depend::new("dddd"),
663 ];
664
665 let list = vec.clone().into_iter().collect::<AlpmListMut<_>>();
666 let mut iter = list.iter();
667
668 assert_eq!(iter.next().unwrap().name(), "aaaa");
669 assert_eq!(iter.next().unwrap().name(), "bbbb");
670 assert_eq!(iter.next().unwrap().name(), "cccc");
671 assert_eq!(iter.next().unwrap().name(), "dddd");
672 assert_eq!(iter.next(), None);
673 }
674
675 #[test]
676 fn test_depends_list_debug() {
677 let handle = Alpm::new("/", "tests/db").unwrap();
678 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
679 let pkg = db.pkg("linux").unwrap();
680
681 println!("{:#?}", db.pkgs());
682 println!("{:#?}", pkg.depends());
683 }
684
685 #[test]
686 fn test_depends_list_free2() {
687 let handle = Alpm::new("/", "tests/db").unwrap();
688 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
689 let pkg = db.pkg("linux").unwrap();
690 let depends = pkg.depends();
691 assert_eq!(depends.first().unwrap().to_string(), "coreutils");
692 }
693
694 #[test]
695 fn test_is_empty() {
696 let handle = Alpm::new("/", "tests/db").unwrap();
697 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
698 let pkg = db.pkg("linux").unwrap();
699 let depends = pkg.depends();
700 assert!(!depends.is_empty());
701
702 let pkg = db.pkg("tzdata").unwrap();
703 let depends = pkg.depends();
704 assert!(depends.is_empty());
705 }
706
707 #[test]
708 fn test_string_list_free() {
709 let handle = Alpm::new("/", "tests/db").unwrap();
710 handle.register_syncdb("community", SigLevel::NONE).unwrap();
711 handle.register_syncdb("extra", SigLevel::NONE).unwrap();
712 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
713 let pkg = db.pkg("linux").unwrap();
714 let required_by = pkg.required_by();
715 assert_eq!("acpi_call", required_by.first().unwrap());
716 }
717
718 #[test]
719 fn test_str_list_free() {
720 let handle = Alpm::new("/", "tests/db").unwrap();
721 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
722 let pkg = db.pkg("pacman").unwrap();
723 let groups = pkg.groups();
724 assert_eq!("base", groups.first().unwrap());
725 }
726
727 #[test]
728 fn test_push() {
729 let handle = Alpm::new("/", "tests/db").unwrap();
730 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
731 let pkg = db.pkg("pacman").unwrap();
732
733 let mut list = AlpmListMut::new();
734 list.push(pkg);
735 assert_eq!(list.first().unwrap().name(), "pacman");
736
737 let mut list = AlpmListMut::new();
738 list.push(Depend::new("a"));
739 list.push(Depend::new("b"));
740 list.push(Depend::new("c"));
741
742 let mut list = AlpmListMut::new();
743 list.push("a".to_string());
744 list.push("b".to_string());
745 list.push("c".to_string());
746
747 let mut list = AlpmListMut::new();
748 list.push("a".to_string());
749 list.push_str("b");
750 list.push_str("c");
751 }
752
753 #[test]
754 fn test_retain() {
755 let handle = Alpm::new("/", "tests/db").unwrap();
756 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
757 let mut pkgs = db.pkgs().to_list_mut();
758 pkgs.retain(|p| p.name().starts_with('a'));
759
760 assert!(!pkgs.is_empty());
761 pkgs.iter().for_each(|p| assert!(p.name().starts_with('a')));
762 }
763}