1use cfg_if::cfg_if;
2use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
3use libc::c_int;
4use std::borrow::Borrow;
5use std::convert::AsRef;
6use std::fmt;
7use std::iter;
8use std::marker::PhantomData;
9use std::mem;
10use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
11
12use crate::error::ErrorStack;
13use crate::util::ForeignTypeExt;
14use crate::{cvt, cvt_p, LenType};
15
16cfg_if! {
17 if #[cfg(ossl110)] {
18 use ffi::{
19 OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK,
20 OPENSSL_sk_new_null, OPENSSL_sk_push,
21 };
22 } else {
23 use ffi::{
24 sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num,
25 sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK,
26 sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push,
27 };
28 }
29}
30
31/// Trait implemented by types which can be placed in a stack.
32///
33/// It should not be implemented for any type outside of this crate.
34pub trait Stackable: ForeignType {
35 /// The C stack type for this element.
36 ///
37 /// Generally called `stack_st_{ELEMENT_TYPE}`, normally hidden by the
38 /// `STACK_OF(ELEMENT_TYPE)` macro in the OpenSSL API.
39 type StackType;
40}
41
42/// An owned stack of `T`.
43pub struct Stack<T: Stackable>(*mut T::StackType);
44
45unsafe impl<T: Stackable + Send> Send for Stack<T> {}
46unsafe impl<T: Stackable + Sync> Sync for Stack<T> {}
47
48impl<T> fmt::Debug for Stack<T>
49where
50 T: Stackable,
51 T::Ref: fmt::Debug,
52{
53 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
54 fmt.debug_list().entries(self).finish()
55 }
56}
57impl<T: Stackable> Drop for Stack<T> {
58 fn drop(&mut self) {
59 unsafe {
60 while self.pop().is_some() {}
61 OPENSSL_sk_free(self.0 as *mut _);
62 }
63 }
64}
65
66impl<T: Stackable> Stack<T> {
67 pub fn new() -> Result<Stack<T>, ErrorStack> {
68 unsafe {
69 ffi::init();
70 let ptr: *mut OPENSSL_STACK = cvt_p(OPENSSL_sk_new_null())?;
71 Ok(Stack(ptr as *mut _))
72 }
73 }
74}
75
76impl<T: Stackable> iter::IntoIterator for Stack<T> {
77 type IntoIter = IntoIter<T>;
78 type Item = T;
79
80 fn into_iter(self) -> IntoIter<T> {
81 let it: IntoIter = IntoIter {
82 stack: self.0,
83 idxs: 0..self.len() as LenType,
84 };
85 mem::forget(self);
86 it
87 }
88}
89
90impl<T: Stackable> AsRef<StackRef<T>> for Stack<T> {
91 fn as_ref(&self) -> &StackRef<T> {
92 self
93 }
94}
95
96impl<T: Stackable> Borrow<StackRef<T>> for Stack<T> {
97 fn borrow(&self) -> &StackRef<T> {
98 self
99 }
100}
101
102impl<T: Stackable> ForeignType for Stack<T> {
103 type CType = T::StackType;
104 type Ref = StackRef<T>;
105
106 #[inline]
107 unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack<T> {
108 assert!(
109 !ptr.is_null(),
110 "Must not instantiate a Stack from a null-ptr - use Stack::new() in \
111 that case"
112 );
113 Stack(ptr)
114 }
115
116 #[inline]
117 fn as_ptr(&self) -> *mut T::StackType {
118 self.0
119 }
120}
121
122impl<T: Stackable> Deref for Stack<T> {
123 type Target = StackRef<T>;
124
125 fn deref(&self) -> &StackRef<T> {
126 unsafe { StackRef::from_ptr(self.0) }
127 }
128}
129
130impl<T: Stackable> DerefMut for Stack<T> {
131 fn deref_mut(&mut self) -> &mut StackRef<T> {
132 unsafe { StackRef::from_ptr_mut(self.0) }
133 }
134}
135
136pub struct IntoIter<T: Stackable> {
137 stack: *mut T::StackType,
138 idxs: Range<LenType>,
139}
140
141impl<T: Stackable> Drop for IntoIter<T> {
142 fn drop(&mut self) {
143 unsafe {
144 // https://github.com/rust-lang/rust-clippy/issues/7510
145 #[allow(clippy::while_let_on_iterator)]
146 while let Some(_) = self.next() {}
147 OPENSSL_sk_free(self.stack as *mut _);
148 }
149 }
150}
151
152impl<T: Stackable> Iterator for IntoIter<T> {
153 type Item = T;
154
155 fn next(&mut self) -> Option<T> {
156 unsafe {
157 self.idxs
158 .next()
159 .map(|i: i32| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, idx:i) as *mut _))
160 }
161 }
162
163 fn size_hint(&self) -> (usize, Option<usize>) {
164 self.idxs.size_hint()
165 }
166}
167
168impl<T: Stackable> DoubleEndedIterator for IntoIter<T> {
169 fn next_back(&mut self) -> Option<T> {
170 unsafe {
171 self.idxs
172 .next_back()
173 .map(|i: i32| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, idx:i) as *mut _))
174 }
175 }
176}
177
178impl<T: Stackable> ExactSizeIterator for IntoIter<T> {}
179
180pub struct StackRef<T: Stackable>(Opaque, PhantomData<T>);
181
182unsafe impl<T: Stackable + Send> Send for StackRef<T> {}
183unsafe impl<T: Stackable + Sync> Sync for StackRef<T> {}
184
185impl<T: Stackable> ForeignTypeRef for StackRef<T> {
186 type CType = T::StackType;
187}
188
189impl<T: Stackable> StackRef<T> {
190 fn as_stack(&self) -> *mut OPENSSL_STACK {
191 self.as_ptr() as *mut _
192 }
193
194 /// Returns the number of items in the stack.
195 pub fn len(&self) -> usize {
196 unsafe { OPENSSL_sk_num(self.as_stack()) as usize }
197 }
198
199 /// Determines if the stack is empty.
200 pub fn is_empty(&self) -> bool {
201 self.len() == 0
202 }
203
204 pub fn iter(&self) -> Iter<'_, T> {
205 Iter {
206 stack: self,
207 idxs: 0..self.len() as LenType,
208 }
209 }
210
211 pub fn iter_mut(&mut self) -> IterMut<'_, T> {
212 IterMut {
213 idxs: 0..self.len() as LenType,
214 stack: self,
215 }
216 }
217
218 /// Returns a reference to the element at the given index in the
219 /// stack or `None` if the index is out of bounds
220 pub fn get(&self, idx: usize) -> Option<&T::Ref> {
221 unsafe {
222 if idx >= self.len() {
223 return None;
224 }
225
226 Some(T::Ref::from_ptr(self._get(idx)))
227 }
228 }
229
230 /// Returns a mutable reference to the element at the given index in the
231 /// stack or `None` if the index is out of bounds
232 pub fn get_mut(&mut self, idx: usize) -> Option<&mut T::Ref> {
233 unsafe {
234 if idx >= self.len() {
235 return None;
236 }
237
238 Some(T::Ref::from_ptr_mut(self._get(idx)))
239 }
240 }
241
242 /// Pushes a value onto the top of the stack.
243 pub fn push(&mut self, data: T) -> Result<(), ErrorStack> {
244 unsafe {
245 cvt(OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _) as c_int)?;
246 mem::forget(data);
247 Ok(())
248 }
249 }
250
251 /// Removes the last element from the stack and returns it.
252 pub fn pop(&mut self) -> Option<T> {
253 unsafe {
254 let ptr = OPENSSL_sk_pop(self.as_stack());
255 T::from_ptr_opt(ptr as *mut _)
256 }
257 }
258
259 unsafe fn _get(&self, idx: usize) -> *mut T::CType {
260 OPENSSL_sk_value(self.as_stack(), idx as LenType) as *mut _
261 }
262}
263
264impl<T: Stackable> Index<usize> for StackRef<T> {
265 type Output = T::Ref;
266
267 fn index(&self, index: usize) -> &T::Ref {
268 self.get(idx:index).unwrap()
269 }
270}
271
272impl<T: Stackable> IndexMut<usize> for StackRef<T> {
273 fn index_mut(&mut self, index: usize) -> &mut T::Ref {
274 self.get_mut(idx:index).unwrap()
275 }
276}
277
278impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef<T> {
279 type Item = &'a T::Ref;
280 type IntoIter = Iter<'a, T>;
281
282 fn into_iter(self) -> Iter<'a, T> {
283 self.iter()
284 }
285}
286
287impl<'a, T: Stackable> iter::IntoIterator for &'a mut StackRef<T> {
288 type Item = &'a mut T::Ref;
289 type IntoIter = IterMut<'a, T>;
290
291 fn into_iter(self) -> IterMut<'a, T> {
292 self.iter_mut()
293 }
294}
295
296impl<'a, T: Stackable> iter::IntoIterator for &'a Stack<T> {
297 type Item = &'a T::Ref;
298 type IntoIter = Iter<'a, T>;
299
300 fn into_iter(self) -> Iter<'a, T> {
301 self.iter()
302 }
303}
304
305impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack<T> {
306 type Item = &'a mut T::Ref;
307 type IntoIter = IterMut<'a, T>;
308
309 fn into_iter(self) -> IterMut<'a, T> {
310 self.iter_mut()
311 }
312}
313
314/// An iterator over the stack's contents.
315pub struct Iter<'a, T: Stackable> {
316 stack: &'a StackRef<T>,
317 idxs: Range<LenType>,
318}
319
320impl<'a, T: Stackable> Iterator for Iter<'a, T> {
321 type Item = &'a T::Ref;
322
323 fn next(&mut self) -> Option<&'a T::Ref> {
324 unsafe {
325 self.idxs
326 .next()
327 .map(|i: i32| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), idx:i) as *mut _))
328 }
329 }
330
331 fn size_hint(&self) -> (usize, Option<usize>) {
332 self.idxs.size_hint()
333 }
334}
335
336impl<'a, T: Stackable> DoubleEndedIterator for Iter<'a, T> {
337 fn next_back(&mut self) -> Option<&'a T::Ref> {
338 unsafe {
339 self.idxs
340 .next_back()
341 .map(|i: i32| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), idx:i) as *mut _))
342 }
343 }
344}
345
346impl<'a, T: Stackable> ExactSizeIterator for Iter<'a, T> {}
347
348/// A mutable iterator over the stack's contents.
349pub struct IterMut<'a, T: Stackable> {
350 stack: &'a mut StackRef<T>,
351 idxs: Range<LenType>,
352}
353
354impl<'a, T: Stackable> Iterator for IterMut<'a, T> {
355 type Item = &'a mut T::Ref;
356
357 fn next(&mut self) -> Option<&'a mut T::Ref> {
358 unsafe {
359 self.idxs
360 .next()
361 .map(|i: i32| T::Ref::from_ptr_mut(ptr:OPENSSL_sk_value(self.stack.as_stack(), idx:i) as *mut _))
362 }
363 }
364
365 fn size_hint(&self) -> (usize, Option<usize>) {
366 self.idxs.size_hint()
367 }
368}
369
370impl<'a, T: Stackable> DoubleEndedIterator for IterMut<'a, T> {
371 fn next_back(&mut self) -> Option<&'a mut T::Ref> {
372 unsafe {
373 self.idxs
374 .next_back()
375 .map(|i: i32| T::Ref::from_ptr_mut(ptr:OPENSSL_sk_value(self.stack.as_stack(), idx:i) as *mut _))
376 }
377 }
378}
379
380impl<'a, T: Stackable> ExactSizeIterator for IterMut<'a, T> {}
381