alpm/
list.rs

1use crate::{
2    AlpmListMut, Backup, Conflict, Db, DbMut, Dep, DepMissing, Depend, DependMissing, FileConflict,
3    Group, LoadedPackage, OwnedConflict, OwnedFileConflict, Package, Pkg, free,
4};
5
6use std::ffi::{CStr, c_void};
7use std::fmt;
8use std::fmt::Debug;
9use std::iter::{ExactSizeIterator, Iterator};
10use std::marker::PhantomData;
11use std::os::raw::c_char;
12
13use alpm_sys::*;
14
15#[doc(hidden)]
16pub unsafe trait IntoAlpmListItem: Sized {
17    unsafe fn into_list_item(ptr: *mut c_void) -> Self;
18    unsafe fn drop_item(ptr: *mut c_void) {
19        unsafe { Self::into_list_item(ptr) };
20    }
21}
22
23pub struct AlpmList<'l, T> {
24    _marker: PhantomData<(&'l (), T)>,
25    list: *mut alpm_list_t,
26}
27
28unsafe impl<T: Send> Send for AlpmList<'_, T> {}
29unsafe impl<T: Sync> Sync for AlpmList<'_, T> {}
30
31impl<T> Clone for AlpmList<'_, T> {
32    fn clone(&self) -> Self {
33        *self
34    }
35}
36
37impl<T> Copy for AlpmList<'_, T> {}
38
39impl<T: IntoAlpmListItem + Debug> fmt::Debug for AlpmList<'_, T> {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        f.write_str("AlpmList ")?;
42        f.debug_list().entries(self.iter()).finish()
43    }
44}
45
46impl<T> AlpmList<'_, T> {
47    pub(crate) unsafe fn from_ptr<'a>(list: *mut alpm_list_t) -> AlpmList<'a, T> {
48        AlpmList {
49            _marker: PhantomData,
50            list,
51        }
52    }
53
54    pub(crate) fn as_ptr(self) -> *mut alpm_list_t {
55        self.list
56    }
57
58    pub fn is_empty(self) -> bool {
59        self.list.is_null()
60    }
61
62    pub fn len(self) -> usize {
63        unsafe { alpm_list_count(self.list) }
64    }
65}
66
67impl<'l, T: IntoAlpmListItem> AlpmList<'l, T> {
68    pub fn first(self) -> Option<T> {
69        if self.list.is_null() {
70            None
71        } else {
72            unsafe { Some(T::into_list_item((*self.list).data)) }
73        }
74    }
75
76    pub fn last(self) -> Option<T> {
77        if !self.list.is_null() && unsafe { !(*self.list).prev.is_null() } {
78            unsafe { Some(T::into_list_item((*(*self.list).prev).data)) }
79        } else {
80            None
81        }
82    }
83
84    pub fn iter(self) -> Iter<'l, T> {
85        self.into_iter()
86    }
87
88    pub fn to_list_mut(&self) -> AlpmListMut<T> {
89        let list = unsafe { alpm_list_copy(self.list) };
90        unsafe { AlpmListMut::from_ptr(list) }
91    }
92}
93
94impl<'l, T: IntoAlpmListItem> IntoIterator for AlpmList<'l, T> {
95    type IntoIter = Iter<'l, T>;
96    type Item = T;
97
98    fn into_iter(self) -> Self::IntoIter {
99        Iter {
100            list: self.list,
101            _marker: PhantomData,
102        }
103    }
104}
105
106pub struct Iter<'l, T> {
107    _marker: PhantomData<(&'l (), T)>,
108    list: *mut alpm_list_t,
109}
110
111unsafe impl<T: Send> Send for Iter<'_, T> {}
112unsafe impl<T: Sync> Sync for Iter<'_, T> {}
113
114impl<T: IntoAlpmListItem + Debug> Debug for Iter<'_, T> {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        unsafe {
117            f.debug_struct("Iter")
118                .field("list", &AlpmList::<T>::from_ptr(self.list))
119                .finish()
120        }
121    }
122}
123
124impl<T> Iter<'_, T> {
125    fn next_data(&mut self) -> Option<*mut c_void> {
126        if self.list.is_null() {
127            None
128        } else {
129            let data = unsafe { (*(self.list)).data };
130            self.list = unsafe { alpm_list_next(self.list) };
131
132            Some(data)
133        }
134    }
135}
136
137impl<T: IntoAlpmListItem> Iterator for Iter<'_, T> {
138    type Item = T;
139
140    fn next(&mut self) -> Option<Self::Item> {
141        unsafe { self.next_data().map(|i| T::into_list_item(i)) }
142    }
143
144    fn size_hint(&self) -> (usize, Option<usize>) {
145        let size = unsafe { alpm_list_count(self.list) };
146        (size, Some(size))
147    }
148}
149
150impl<T: IntoAlpmListItem> ExactSizeIterator for Iter<'_, T> {}
151
152unsafe impl IntoAlpmListItem for &Dep {
153    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
154        unsafe { Dep::from_ptr(ptr as _) }
155    }
156}
157
158unsafe impl IntoAlpmListItem for &Conflict {
159    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
160        unsafe { Conflict::from_ptr(ptr as _) }
161    }
162}
163
164unsafe impl IntoAlpmListItem for &Pkg {
165    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
166        unsafe { Pkg::from_ptr(ptr as _) }
167    }
168}
169
170unsafe impl IntoAlpmListItem for &Package {
171    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
172        unsafe { Package::from_ptr(ptr as _) }
173    }
174}
175
176unsafe impl IntoAlpmListItem for &Db {
177    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
178        unsafe { Db::from_ptr(ptr as _) }
179    }
180}
181
182unsafe impl IntoAlpmListItem for &Group {
183    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
184        unsafe { Group::from_ptr(ptr as _) }
185    }
186}
187
188unsafe impl IntoAlpmListItem for &DepMissing {
189    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
190        unsafe { DepMissing::from_ptr(ptr as _) }
191    }
192}
193
194unsafe impl IntoAlpmListItem for &FileConflict {
195    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
196        unsafe { FileConflict::from_ptr(ptr as _) }
197    }
198}
199
200unsafe impl IntoAlpmListItem for &str {
201    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
202        let s = unsafe { CStr::from_ptr(ptr as *mut c_char) };
203        s.to_str().unwrap()
204    }
205}
206
207// owned
208
209unsafe impl IntoAlpmListItem for Depend {
210    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
211        unsafe { Depend::from_ptr(ptr as _) }
212    }
213}
214
215unsafe impl IntoAlpmListItem for OwnedConflict {
216    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
217        unsafe { OwnedConflict::from_ptr(ptr as _) }
218    }
219}
220
221unsafe impl IntoAlpmListItem for LoadedPackage<'_> {
222    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
223        unsafe { LoadedPackage::from_ptr(ptr as _) }
224    }
225}
226
227unsafe impl IntoAlpmListItem for DbMut<'_> {
228    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
229        unsafe { DbMut::from_ptr(ptr as _) }
230    }
231}
232
233unsafe impl IntoAlpmListItem for DependMissing {
234    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
235        unsafe { DependMissing::from_ptr(ptr as _) }
236    }
237}
238
239unsafe impl IntoAlpmListItem for &Backup {
240    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
241        unsafe { Backup::from_ptr(ptr as _) }
242    }
243}
244
245unsafe impl IntoAlpmListItem for OwnedFileConflict {
246    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
247        unsafe { OwnedFileConflict::from_ptr(ptr as _) }
248    }
249}
250
251unsafe impl IntoAlpmListItem for String {
252    unsafe fn into_list_item(ptr: *mut c_void) -> Self {
253        let s = unsafe { CStr::from_ptr(ptr as *mut c_char) };
254        let ret = s.to_str().unwrap().to_string();
255        unsafe { free(ptr) };
256        ret
257    }
258    unsafe fn drop_item(ptr: *mut c_void) {
259        unsafe { free(ptr) }
260    }
261}