alpm/
list_mut.rs

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
225// cant deref so manual impl
226impl<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
285// ptr impl
286
287unsafe 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
425// ptr impl on &T because String is special
426
427unsafe 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
535// borrow impl
536
537unsafe 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}