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
207unsafe 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}