alpm_ll/
list.rs

1use crate::{
2    free, Alpm, Backup, Conflict, Db, DbMut, Dep, DepMissing, Depend, DependMissing, FileConflict,
3    Group, LoadedPackage, OwnedConflict, OwnedFileConflict, Package, Pkg, LIBRARY, Library
4};
5
6use std::ffi::{c_void, CStr};
7use std::fmt;
8use std::iter::{ExactSizeIterator, Iterator};
9use std::marker::PhantomData;
10use std::mem::ManuallyDrop;
11use std::os::raw::c_char;
12use std::ptr;
13
14use alpm_sys_ll::*;
15
16extern "C" {
17    fn strndup(cs: *const c_char, n: usize) -> *mut c_char;
18}
19
20pub unsafe trait IntoAlpmListItem<'a, 'b> {
21    type Borrow: fmt::Debug;
22    #[doc(hidden)]
23    unsafe fn ptr_into_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self;
24    #[doc(hidden)]
25    unsafe fn ptr_as_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow;
26}
27
28pub unsafe trait AsAlpmListItemPtr<'a> {
29    type Output;
30    const FREE: Option<unsafe extern "C" fn(_ptr: *mut c_void)> = None;
31    fn as_ptr(&self) -> *mut c_void;
32}
33
34pub trait Bool {
35    const DROP: bool;
36}
37
38pub unsafe trait Push<'a>: AsAlpmListItemPtr<'a> {}
39
40pub struct True;
41pub struct False;
42
43impl Bool for True {
44    const DROP: bool = true;
45}
46
47impl Bool for False {
48    const DROP: bool = false;
49}
50
51pub struct RawAlpmList<'a, T, D>
52where
53    D: Bool,
54    T: AsAlpmListItemPtr<'a>,
55{
56    list: *mut alpm_list_t,
57    _marker1: PhantomData<&'a T>,
58    _marker2: PhantomData<D>,
59}
60
61impl<'a, T, D> RawAlpmList<'a, T, D>
62where
63    D: Bool,
64    T: AsAlpmListItemPtr<'a>,
65{
66    pub fn list(&self) -> *mut alpm_list_t {
67        self.list
68    }
69}
70
71impl<'a, T, D> Drop for RawAlpmList<'a, T, D>
72where
73    D: Bool,
74    T: AsAlpmListItemPtr<'a>,
75{
76    fn drop(&mut self) {
77        if D::DROP {
78            if let Some(free) = T::FREE {
79                unsafe { LIBRARY.force_load().alpm_list_free_inner(self.list, Some(free)) }
80            }
81            unsafe { LIBRARY.force_load().alpm_list_free(self.list) };
82        }
83    }
84}
85
86pub trait IntoRawAlpmList<'a, T>
87where
88    T: AsAlpmListItemPtr<'a>,
89{
90    #[doc(hidden)]
91    type Drop: Bool;
92    #[doc(hidden)]
93    unsafe fn into_raw_alpm_list(self) -> RawAlpmList<'a, T, Self::Drop>;
94}
95
96impl<'a> IntoRawAlpmList<'a, Pkg<'a>> for AlpmList<'a, LoadedPackage<'a>> {
97    type Drop = False;
98    unsafe fn into_raw_alpm_list(self) -> RawAlpmList<'a, Pkg<'a>, Self::Drop> {
99        RawAlpmList {
100            list: self.list,
101            _marker1: PhantomData,
102            _marker2: PhantomData,
103        }
104    }
105}
106
107impl<'a> IntoRawAlpmList<'a, Pkg<'a>> for AlpmList<'a, Package<'a>> {
108    type Drop = False;
109    unsafe fn into_raw_alpm_list(self) -> RawAlpmList<'a, Pkg<'a>, Self::Drop> {
110        RawAlpmList {
111            list: self.list,
112            _marker1: PhantomData,
113            _marker2: PhantomData,
114        }
115    }
116}
117
118impl<'a, T> IntoRawAlpmList<'a, T> for AlpmList<'a, T>
119where
120    T: AsAlpmListItemPtr<'a>,
121{
122    type Drop = False;
123    unsafe fn into_raw_alpm_list(self) -> RawAlpmList<'a, T, Self::Drop> {
124        RawAlpmList {
125            list: self.list,
126            _marker1: PhantomData,
127            _marker2: PhantomData,
128        }
129    }
130}
131
132impl<'a, T> IntoRawAlpmList<'a, T> for &AlpmListMut<'a, T>
133where
134    for<'b> T: IntoAlpmListItem<'a, 'b> + AsAlpmListItemPtr<'a>,
135{
136    type Drop = False;
137    unsafe fn into_raw_alpm_list(self) -> RawAlpmList<'a, T, Self::Drop> {
138        RawAlpmList {
139            list: self.list.list,
140            _marker1: PhantomData,
141            _marker2: PhantomData,
142        }
143    }
144}
145
146impl<'a, T, D: Bool> IntoRawAlpmList<'a, T> for RawAlpmList<'a, T, D>
147where
148    T: AsAlpmListItemPtr<'a>,
149{
150    type Drop = D;
151    unsafe fn into_raw_alpm_list(self) -> RawAlpmList<'a, T, Self::Drop> {
152        self
153    }
154}
155
156impl<'a, T, I> IntoRawAlpmList<'a, T::Output> for I
157where
158    I: Iterator<Item = T>,
159    T: AsAlpmListItemPtr<'a>,
160    T::Output: AsAlpmListItemPtr<'a>,
161{
162    type Drop = True;
163    unsafe fn into_raw_alpm_list(self) -> RawAlpmList<'a, T::Output, Self::Drop> {
164        let mut list = ptr::null_mut();
165
166        for item in self {
167            list = LIBRARY.force_load().alpm_list_add(list, item.as_ptr());
168            if T::FREE.is_none() {
169                std::mem::forget(item);
170            }
171        }
172
173        RawAlpmList {
174            list,
175            _marker1: PhantomData,
176            _marker2: PhantomData,
177        }
178    }
179}
180
181pub struct AlpmList<'a, T> {
182    pub(crate) handle: &'a Alpm,
183    pub(crate) list: *mut alpm_list_t,
184    pub(crate) _marker: PhantomData<T>,
185}
186
187impl<'a, T> fmt::Debug for AlpmList<'a, T>
188where
189    for<'b> T: IntoAlpmListItem<'a, 'b>,
190{
191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        f.write_str("AlpmList ")?;
193        f.debug_list().entries(self).finish()
194    }
195}
196
197impl<'a, T> Clone for AlpmList<'a, T> {
198    fn clone(&self) -> Self {
199        AlpmList {
200            handle: self.handle,
201            list: self.list,
202            _marker: self._marker,
203        }
204    }
205}
206
207impl<'a, T> Copy for AlpmList<'a, T> {}
208
209pub struct AlpmListMut<'a, T>
210where
211    for<'b> T: IntoAlpmListItem<'a, 'b>,
212{
213    list: AlpmList<'a, T>,
214}
215
216impl<'a, T> fmt::Debug for AlpmListMut<'a, T>
217where
218    for<'b> T: IntoAlpmListItem<'a, 'b>,
219{
220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221        fmt::Debug::fmt(&self.as_list(), f)
222    }
223}
224
225impl<'a, T> std::ops::Deref for AlpmListMut<'a, T>
226where
227    for<'b> T: IntoAlpmListItem<'a, 'b>,
228{
229    type Target = AlpmList<'a, T>;
230
231    fn deref(&self) -> &Self::Target {
232        &self.list
233    }
234}
235
236impl<'a, T> Drop for AlpmListMut<'a, T>
237where
238    for<'b> T: IntoAlpmListItem<'a, 'b>,
239{
240    fn drop(&mut self) {
241        let list = self.list.list;
242        let mut curr = list;
243
244        while !curr.is_null() {
245            let item = unsafe { T::ptr_into_alpm_list_item(self.handle, (*curr).data) };
246            drop(item);
247            curr = unsafe { (*curr).next };
248        }
249
250        unsafe { LIBRARY.force_load().alpm_list_free(list) }
251    }
252}
253
254impl<'a, 'b, T> AlpmList<'a, T>
255where
256    T: IntoAlpmListItem<'a, 'b>,
257{
258    pub fn len(&self) -> usize {
259        unsafe { LIBRARY.force_load().alpm_list_count(self.list) }
260    }
261
262    pub fn is_empty(&self) -> bool {
263        self.list.is_null()
264    }
265
266    pub fn first(&'b self) -> Option<T::Borrow> {
267        if self.is_empty() {
268            None
269        } else {
270            unsafe { Some(T::ptr_as_alpm_list_item(self.handle, (*self.list).data)) }
271        }
272    }
273
274    pub fn last(&'b self) -> Option<T::Borrow> {
275        let item = unsafe { LIBRARY.force_load().alpm_list_last(self.list) };
276        if item.is_null() {
277            None
278        } else {
279            unsafe { Some(T::ptr_as_alpm_list_item(self.handle, (*item).data)) }
280        }
281    }
282
283    pub fn iter(&'b self) -> Iter<'a, 'b, T> {
284        self.into_iter()
285    }
286}
287
288impl<'a> AlpmList<'a, String> {
289    pub fn as_str<'b>(&'b self) -> AlpmList<'a, &'b str> {
290        unsafe { AlpmList::from_parts(self.handle, self.list) }
291    }
292}
293
294impl<'a, T> AlpmList<'a, T>
295where
296    for<'b> T: IntoAlpmListItem<'a, 'b>,
297{
298    #[allow(clippy::wrong_self_convention)]
299    pub fn to_list_mut(&self) -> AlpmListMut<'a, T> {
300        let list = unsafe { LIBRARY.force_load().alpm_list_copy(self.list) };
301        AlpmListMut {
302            list: unsafe { AlpmList::from_parts(self.handle, list) },
303        }
304    }
305}
306
307impl<'a, T> AlpmListMut<'a, T>
308where
309    for<'b> T: IntoAlpmListItem<'a, 'b> + Push<'a> + AsAlpmListItemPtr<'a>,
310{
311    pub fn push(&mut self, t: T) {
312        unsafe { self.list.list = LIBRARY.force_load().alpm_list_add(self.list.list, t.as_ptr()) };
313        if T::FREE.is_none() {
314            std::mem::forget(t);
315        }
316    }
317}
318
319impl<'a, T> Extend<T> for AlpmListMut<'a, T>
320where
321    for<'b> T: IntoAlpmListItem<'a, 'b> + Push<'a>,
322{
323    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
324        for item in iter {
325            self.push(item);
326        }
327    }
328}
329
330impl<'a> AlpmListMut<'a, String> {
331    pub fn push_str(&mut self, s: &str) {
332        let s = unsafe { strndup(s.as_bytes().as_ptr() as _, s.len()) };
333        unsafe { self.list.list = LIBRARY.force_load().alpm_list_add(self.list.list, s as *mut c_void) };
334    }
335}
336
337impl<'a, T> AlpmListMut<'a, T>
338where
339    for<'b> T: IntoAlpmListItem<'a, 'b>,
340{
341    pub fn retain<F>(&mut self, mut f: F)
342    where
343        F: FnMut(&T) -> bool,
344    {
345        let mut list = self.list.list;
346        let mut curr = list;
347
348        while !curr.is_null() {
349            let item = unsafe { T::ptr_into_alpm_list_item(self.handle, (*curr).data) };
350            let next = unsafe { (*curr).next };
351            if !f(&item) {
352                drop(item);
353                unsafe { list = LIBRARY.force_load().alpm_list_remove_item(list, curr) };
354                unsafe { free(curr as _) };
355            } else {
356                std::mem::forget(item);
357            }
358            curr = next;
359        }
360
361        self.list.list = list;
362    }
363
364    pub fn remove(&mut self, n: usize) -> Option<T> {
365        if n >= self.len() {
366            return None;
367        }
368
369        let item = unsafe { LIBRARY.force_load().alpm_list_nth(self.list.list, n) };
370        unsafe { self.list.list = LIBRARY.force_load().alpm_list_remove_item(self.list.list, item) };
371        let ret = unsafe {
372            Some(T::ptr_into_alpm_list_item(
373                self.handle,
374                (*self.list.list).data,
375            ))
376        };
377        unsafe { free(item as _) };
378        ret
379    }
380
381    pub fn remove_list(&mut self, n: usize) -> AlpmListMut<'a, T> {
382        if n >= self.len() {
383            return AlpmListMut::new(self.handle);
384        }
385
386        let item = unsafe { LIBRARY.force_load().alpm_list_nth(self.list.list, n) };
387        self.list.list = unsafe { LIBRARY.force_load().alpm_list_remove_item(self.list.list, item) };
388        unsafe { (*item).next = ptr::null_mut() };
389        unsafe { (*item).prev = ptr::null_mut() };
390        unsafe { AlpmListMut::from_parts(self.handle, item) }
391    }
392
393    pub fn as_list(&self) -> AlpmList<'a, T> {
394        self.list
395    }
396}
397
398impl<'a, T> IntoIterator for AlpmListMut<'a, T>
399where
400    for<'b> T: IntoAlpmListItem<'a, 'b>,
401{
402    type Item = T;
403    type IntoIter = IntoIterMut<'a, T>;
404
405    fn into_iter(self) -> Self::IntoIter {
406        IntoIterMut {
407            current: self.list.list,
408            list: ManuallyDrop::new(self),
409        }
410    }
411}
412
413impl<'a, 'b, T> IntoIterator for &'b AlpmListMut<'a, T>
414where
415    for<'c> T: IntoAlpmListItem<'a, 'c>,
416{
417    type Item = <T as IntoAlpmListItem<'a, 'b>>::Borrow;
418    type IntoIter = Iter<'a, 'b, T>;
419
420    fn into_iter(self) -> Self::IntoIter {
421        self.iter()
422    }
423}
424
425impl<'a, 'b, T> IntoIterator for &'b AlpmList<'a, T>
426where
427    T: IntoAlpmListItem<'a, 'b>,
428{
429    type Item = T::Borrow;
430    type IntoIter = Iter<'a, 'b, T>;
431
432    fn into_iter(self) -> Self::IntoIter {
433        Iter {
434            current: self.list,
435            list: self,
436        }
437    }
438}
439
440impl<'a, T> IntoIterator for AlpmList<'a, T>
441where
442    T: IntoAlpmListItem<'a, 'a>,
443{
444    type Item = T::Borrow;
445    type IntoIter = IntoIter<'a, T>;
446
447    fn into_iter(self) -> Self::IntoIter {
448        IntoIter {
449            current: self.list,
450            list: self,
451        }
452    }
453}
454
455#[derive(Copy, Clone)]
456pub struct Iter<'a, 'b, T>
457where
458    T: IntoAlpmListItem<'a, 'b>,
459{
460    list: &'b AlpmList<'a, T>,
461    current: *mut alpm_list_t,
462}
463
464impl<'a, 'b, T> fmt::Debug for Iter<'a, 'b, T>
465where
466    for<'c> T: IntoAlpmListItem<'a, 'c>,
467{
468    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469        f.debug_struct("Iter").field("list", self.list).finish()
470    }
471}
472
473#[derive(Copy, Clone)]
474pub struct IntoIter<'a, T>
475where
476    T: IntoAlpmListItem<'a, 'a>,
477{
478    list: AlpmList<'a, T>,
479    current: *mut alpm_list_t,
480}
481
482impl<'a, T> fmt::Debug for IntoIter<'a, T>
483where
484    for<'b> T: IntoAlpmListItem<'a, 'b>,
485{
486    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487        f.debug_struct("Iter").field("list", &self.list).finish()
488    }
489}
490
491impl<'a, 'b, T> Iter<'a, 'b, T>
492where
493    T: IntoAlpmListItem<'a, 'b>,
494{
495    fn next_data(&mut self) -> Option<*mut c_void> {
496        if self.current.is_null() {
497            None
498        } else {
499            let data = unsafe { (*(self.current)).data };
500            self.current = unsafe { LIBRARY.force_load().alpm_list_next(self.current) };
501
502            Some(data)
503        }
504    }
505}
506
507pub struct IntoIterMut<'a, T>
508where
509    for<'b> T: IntoAlpmListItem<'a, 'b>,
510{
511    list: ManuallyDrop<AlpmListMut<'a, T>>,
512    current: *mut alpm_list_t,
513}
514
515impl<'a, T> fmt::Debug for IntoIterMut<'a, T>
516where
517    for<'b> T: IntoAlpmListItem<'a, 'b>,
518{
519    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
520        f.debug_struct("Iter").field("list", &self.list).finish()
521    }
522}
523
524impl<'a, T> Drop for IntoIterMut<'a, T>
525where
526    for<'b> T: IntoAlpmListItem<'a, 'b>,
527{
528    fn drop(&mut self) {
529        unsafe { AlpmListMut::<T>::from_parts(self.list.handle, self.current) };
530    }
531}
532
533impl<'a, T> ExactSizeIterator for IntoIterMut<'a, T> where for<'b> T: IntoAlpmListItem<'a, 'b> {}
534impl<'a, T> ExactSizeIterator for IntoIter<'a, T> where for<'b> T: IntoAlpmListItem<'a, 'b> {}
535impl<'a, 'b, T> ExactSizeIterator for Iter<'a, 'b, T> where T: IntoAlpmListItem<'a, 'b> {}
536
537impl<'a, T> Iterator for IntoIterMut<'a, T>
538where
539    for<'b> T: IntoAlpmListItem<'a, 'b>,
540{
541    type Item = T;
542    fn next(&mut self) -> Option<Self::Item> {
543        let data = self.next_data();
544
545        match data {
546            Some(data) => unsafe { Some(T::ptr_into_alpm_list_item(self.list.handle, data)) },
547            None => None,
548        }
549    }
550
551    fn size_hint(&self) -> (usize, Option<usize>) {
552        let size = unsafe { LIBRARY.force_load().alpm_list_count(self.list.list.list) };
553        (size, Some(size))
554    }
555}
556
557impl<'a, 'b, T> Iterator for Iter<'a, 'b, T>
558where
559    T: IntoAlpmListItem<'a, 'b>,
560{
561    type Item = T::Borrow;
562    fn next(&mut self) -> Option<Self::Item> {
563        let data = self.next_data();
564
565        match data {
566            Some(data) => unsafe { Some(T::ptr_as_alpm_list_item(self.list.handle, data)) },
567            None => None,
568        }
569    }
570
571    fn size_hint(&self) -> (usize, Option<usize>) {
572        let size = unsafe { LIBRARY.force_load().alpm_list_count(self.list.list) };
573        (size, Some(size))
574    }
575}
576
577impl<'a, T> Iterator for IntoIter<'a, T>
578where
579    T: IntoAlpmListItem<'a, 'a>,
580{
581    type Item = T::Borrow;
582    fn next(&mut self) -> Option<Self::Item> {
583        let data = self.next_data();
584
585        match data {
586            Some(data) => unsafe { Some(T::ptr_as_alpm_list_item(self.list.handle, data)) },
587            None => None,
588        }
589    }
590
591    fn size_hint(&self) -> (usize, Option<usize>) {
592        let size = unsafe { LIBRARY.force_load().alpm_list_count(self.list.list) };
593        (size, Some(size))
594    }
595}
596
597impl<'a, T> IntoIter<'a, T>
598where
599    T: IntoAlpmListItem<'a, 'a>,
600{
601    fn next_data(&mut self) -> Option<*mut c_void> {
602        if self.current.is_null() {
603            None
604        } else {
605            let data = unsafe { (*(self.current)).data };
606            self.current = unsafe { LIBRARY.force_load().alpm_list_next(self.current) };
607
608            Some(data)
609        }
610    }
611}
612
613impl<'a, T> IntoIterMut<'a, T>
614where
615    for<'b> T: IntoAlpmListItem<'a, 'b>,
616{
617    fn next_data(&mut self) -> Option<*mut c_void> {
618        if self.current.is_null() {
619            None
620        } else {
621            let data = unsafe { (*(self.current)).data };
622            self.current = unsafe { LIBRARY.force_load().alpm_list_next(self.current) };
623
624            Some(data)
625        }
626    }
627}
628
629impl<'a, T> AlpmList<'a, T> {
630    pub(crate) unsafe fn from_parts(handle: &'a Alpm, list: *mut alpm_list_t) -> AlpmList<'a, T> {
631        AlpmList {
632            handle,
633            list,
634            _marker: PhantomData,
635        }
636    }
637}
638
639impl<'a, T> AlpmListMut<'a, T>
640where
641    for<'b> T: IntoAlpmListItem<'a, 'b>,
642{
643    pub fn new(handle: &'a Alpm) -> AlpmListMut<'a, T> {
644        AlpmListMut {
645            list: unsafe { AlpmList::from_parts(handle, ptr::null_mut()) },
646        }
647    }
648
649    pub(crate) unsafe fn from_parts(
650        handle: &'a Alpm,
651        list: *mut alpm_list_t,
652    ) -> AlpmListMut<'a, T> {
653        AlpmListMut {
654            list: AlpmList::from_parts(handle, list),
655        }
656    }
657}
658
659unsafe impl<'a> AsAlpmListItemPtr<'a> for Pkg<'a> {
660    type Output = Pkg<'a>;
661
662    fn as_ptr(&self) -> *mut c_void {
663        (*self).as_ptr() as *mut c_void
664    }
665}
666
667unsafe impl<'a> AsAlpmListItemPtr<'a> for Package<'a> {
668    type Output = Package<'a>;
669
670    fn as_ptr(&self) -> *mut c_void {
671        self.pkg.as_ptr() as *mut c_void
672    }
673}
674
675unsafe impl<'a> AsAlpmListItemPtr<'a> for LoadedPackage<'a> {
676    type Output = Pkg<'a>;
677
678    fn as_ptr(&self) -> *mut c_void {
679        self.pkg.as_ptr() as *mut c_void
680    }
681}
682
683unsafe impl<'a> AsAlpmListItemPtr<'a> for Db<'a> {
684    type Output = Db<'a>;
685
686    fn as_ptr(&self) -> *mut c_void {
687        (*self).as_ptr() as *mut c_void
688    }
689}
690
691unsafe impl<'a> AsAlpmListItemPtr<'a> for Depend {
692    type Output = Dep<'a>;
693
694    fn as_ptr(&self) -> *mut c_void {
695        Dep::as_ptr(self) as *mut c_void
696    }
697}
698
699unsafe impl<'a, T: AsAlpmListItemPtr<'a>> AsAlpmListItemPtr<'a> for &T {
700    type Output = T::Output;
701
702    fn as_ptr(&self) -> *mut c_void {
703        (*self).as_ptr()
704    }
705}
706
707unsafe impl<'a> AsAlpmListItemPtr<'a> for Dep<'a> {
708    type Output = Dep<'a>;
709
710    fn as_ptr(&self) -> *mut c_void {
711        Dep::as_ptr(self) as *mut c_void
712    }
713}
714
715unsafe impl<'a> AsAlpmListItemPtr<'a> for String {
716    type Output = String;
717    const FREE: Option<unsafe extern "C" fn(_ptr: *mut c_void)> = Some(free);
718    fn as_ptr(&self) -> *mut c_void {
719        unsafe { strndup(self.as_bytes().as_ptr() as _, self.len()) as *mut c_void }
720    }
721}
722
723unsafe impl<'a> AsAlpmListItemPtr<'a> for &str {
724    type Output = String;
725    const FREE: Option<unsafe extern "C" fn(_ptr: *mut c_void)> = Some(free);
726
727    fn as_ptr(&self) -> *mut c_void {
728        unsafe { strndup(self.as_bytes().as_ptr() as _, self.len()) as *mut c_void }
729    }
730}
731
732unsafe impl<'a> Push<'a> for String {}
733unsafe impl<'a> Push<'a> for Pkg<'a> {}
734unsafe impl<'a> Push<'a> for Package<'a> {}
735unsafe impl<'a> Push<'a> for Db<'a> {}
736unsafe impl<'a> Push<'a> for Depend {}
737unsafe impl<'a> Push<'a> for Dep<'a> {}
738
739unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for Package<'a> {
740    type Borrow = Self;
741    unsafe fn ptr_into_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self {
742        Package::new(handle, ptr as *mut alpm_pkg_t)
743    }
744    unsafe fn ptr_as_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
745        Package::new(handle, ptr as *mut alpm_pkg_t)
746    }
747}
748
749unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for Group<'a> {
750    type Borrow = Self;
751    unsafe fn ptr_into_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self {
752        Group::new(handle, ptr as *mut alpm_group_t)
753    }
754    unsafe fn ptr_as_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
755        Group::new(handle, ptr as *mut alpm_group_t)
756    }
757}
758
759unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for Depend {
760    type Borrow = Dep<'b>;
761    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
762        Depend::from_ptr(ptr as *mut alpm_depend_t)
763    }
764    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
765        Dep::from_ptr(ptr as *mut alpm_depend_t)
766    }
767}
768
769unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for Dep<'a> {
770    type Borrow = Self;
771    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
772        Dep::from_ptr(ptr as *mut alpm_depend_t)
773    }
774
775    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
776        Dep::from_ptr(ptr as *mut alpm_depend_t)
777    }
778}
779
780unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for Backup {
781    type Borrow = Self;
782    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
783        Backup::from_ptr(ptr as *mut alpm_backup_t)
784    }
785    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
786        Backup::from_ptr(ptr as *mut alpm_backup_t)
787    }
788}
789
790unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for OwnedFileConflict {
791    type Borrow = FileConflict<'b>;
792    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
793        OwnedFileConflict {
794            inner: FileConflict::from_ptr(ptr as *mut alpm_fileconflict_t),
795        }
796    }
797
798    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
799        FileConflict::from_ptr(ptr as *mut alpm_fileconflict_t)
800    }
801}
802
803unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for DependMissing {
804    type Borrow = DepMissing<'b>;
805    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
806        DependMissing {
807            inner: DepMissing::from_ptr(ptr as *mut alpm_depmissing_t),
808        }
809    }
810
811    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
812        DepMissing::from_ptr(ptr as *mut alpm_depmissing_t)
813    }
814}
815
816unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for OwnedConflict {
817    type Borrow = Conflict<'b>;
818    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
819        OwnedConflict::from_ptr(ptr as *mut alpm_conflict_t)
820    }
821    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
822        Conflict::from_ptr(ptr as *mut alpm_conflict_t)
823    }
824}
825
826unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for Conflict<'a> {
827    type Borrow = Self;
828    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
829        Conflict::from_ptr(ptr as *mut alpm_conflict_t)
830    }
831    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
832        Conflict::from_ptr(ptr as *mut alpm_conflict_t)
833    }
834}
835
836unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for Db<'a> {
837    type Borrow = Self;
838    unsafe fn ptr_into_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self {
839        Db::new(handle, ptr as *mut alpm_db_t)
840    }
841    unsafe fn ptr_as_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
842        Db::new(handle, ptr as *mut alpm_db_t)
843    }
844}
845
846unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for DbMut<'a> {
847    type Borrow = Self;
848    unsafe fn ptr_into_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self {
849        DbMut {
850            inner: Db::new(handle, ptr as *mut alpm_db_t),
851        }
852    }
853    unsafe fn ptr_as_alpm_list_item(handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
854        DbMut {
855            inner: Db::new(handle, ptr as *mut alpm_db_t),
856        }
857    }
858}
859
860unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for &'a str {
861    type Borrow = Self;
862    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
863        let s = CStr::from_ptr(ptr as *mut c_char);
864        s.to_str().unwrap()
865    }
866    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
867        let s = CStr::from_ptr(ptr as *mut c_char);
868        s.to_str().unwrap()
869    }
870}
871
872unsafe impl<'a, 'b> IntoAlpmListItem<'a, 'b> for String {
873    type Borrow = &'b str;
874    unsafe fn ptr_into_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self {
875        let s = CStr::from_ptr(ptr as *mut c_char);
876        let s = s.to_str().unwrap().to_string();
877        free(ptr);
878        s
879    }
880    unsafe fn ptr_as_alpm_list_item(_handle: &'a Alpm, ptr: *mut c_void) -> Self::Borrow {
881        let s = CStr::from_ptr(ptr as *mut c_char);
882        s.to_str().unwrap()
883    }
884}
885
886#[cfg(test)]
887mod tests {
888    use super::*;
889    use crate::SigLevel;
890
891    #[test]
892    fn test_depends_list_debug() {
893        let handle = Alpm::new("/", "tests/db").unwrap();
894        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
895        let pkg = db.pkg("linux").unwrap();
896
897        println!("{:#?}", db.pkgs());
898        println!("{:#?}", pkg.depends());
899    }
900
901    #[test]
902    fn test_depends_list_free() {
903        let handle = Alpm::new("/", "tests/db").unwrap();
904        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
905        let pkg = db.pkg("linux").unwrap();
906        let depends = pkg.depends();
907        assert_eq!(depends.first().unwrap().to_string(), "coreutils");
908    }
909
910    #[test]
911    fn test_is_empty() {
912        let handle = Alpm::new("/", "tests/db").unwrap();
913        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
914        let pkg = db.pkg("linux").unwrap();
915        let depends = pkg.depends();
916        assert!(!depends.is_empty());
917
918        let pkg = db.pkg("tzdata").unwrap();
919        let depends = pkg.depends();
920        assert!(depends.is_empty());
921    }
922
923    #[test]
924    fn test_string_list_free() {
925        let handle = Alpm::new("/", "tests/db").unwrap();
926        handle.register_syncdb("community", SigLevel::NONE).unwrap();
927        handle.register_syncdb("extra", SigLevel::NONE).unwrap();
928        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
929        let pkg = db.pkg("linux").unwrap();
930        let required_by = pkg.required_by();
931        assert_eq!("acpi_call", required_by.first().unwrap());
932    }
933
934    #[test]
935    fn test_str_list_free() {
936        let handle = Alpm::new("/", "tests/db").unwrap();
937        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
938        let pkg = db.pkg("pacman").unwrap();
939        let groups = pkg.groups();
940        assert_eq!("base", groups.first().unwrap());
941    }
942
943    #[test]
944    fn test_push() {
945        let handle = Alpm::new("/", "tests/db").unwrap();
946        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
947        let pkg = db.pkg("pacman").unwrap();
948
949        let mut list = AlpmListMut::new(&handle);
950        list.push(pkg);
951        assert_eq!(list.first().unwrap().name(), "pacman");
952
953        let mut list = AlpmListMut::new(&handle);
954        list.push(Depend::new("a"));
955        list.push(Depend::new("b"));
956        list.push(Depend::new("c"));
957
958        let mut list = AlpmListMut::new(&handle);
959        list.push("a".to_string());
960        list.push("b".to_string());
961        list.push("c".to_string());
962
963        let mut list = AlpmListMut::new(&handle);
964        list.push("a".to_string());
965        list.push_str("b");
966        list.push_str("c");
967    }
968
969    #[test]
970    fn test_retain() {
971        let handle = Alpm::new("/", "tests/db").unwrap();
972        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
973        let mut pkgs = db.pkgs().to_list_mut();
974        pkgs.retain(|p| p.name().starts_with('a'));
975
976        assert!(!pkgs.is_empty());
977        pkgs.iter().for_each(|p| assert!(p.name().starts_with('a')));
978    }
979
980    #[test]
981    fn test_into_raw_alpm_list() {
982        let handle = Alpm::new("/", "tests/db").unwrap();
983        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
984        let pkg = db.pkg("linux").unwrap();
985        assert_eq!(handle.syncdbs().to_list_mut().remove_list(0).len(), 1);
986        pkg.sync_new_version(handle.syncdbs());
987        pkg.sync_new_version(&handle.syncdbs().to_list_mut().remove_list(0));
988        pkg.sync_new_version(vec![db].into_iter());
989        pkg.sync_new_version(vec![db].iter());
990    }
991
992    #[test]
993    fn test_into_raw_alpm_list2() {
994        let mut handle = Alpm::new("/", "tests/db").unwrap();
995
996        let list = vec![Depend::new("foo")];
997        handle.set_assume_installed(list.iter()).unwrap();
998    }
999}