openssl/
stack.rs

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(any(ossl110, boringssl, awslc))] {
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 = 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 {
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| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, 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| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, 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(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(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| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), 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| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _))
342        }
343    }
344}
345
346impl<T: Stackable> ExactSizeIterator for Iter<'_, 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| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), 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| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _))
376        }
377    }
378}
379
380impl<T: Stackable> ExactSizeIterator for IterMut<'_, T> {}