summaryrefslogtreecommitdiffstats
path: root/vendor/openssl/src/stack.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/openssl/src/stack.rs')
-rw-r--r--vendor/openssl/src/stack.rs380
1 files changed, 380 insertions, 0 deletions
diff --git a/vendor/openssl/src/stack.rs b/vendor/openssl/src/stack.rs
new file mode 100644
index 000000000..416efd5ad
--- /dev/null
+++ b/vendor/openssl/src/stack.rs
@@ -0,0 +1,380 @@
+use cfg_if::cfg_if;
+use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
+use libc::c_int;
+use std::borrow::Borrow;
+use std::convert::AsRef;
+use std::fmt;
+use std::iter;
+use std::marker::PhantomData;
+use std::mem;
+use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
+
+use crate::error::ErrorStack;
+use crate::util::ForeignTypeExt;
+use crate::{cvt, cvt_p, LenType};
+
+cfg_if! {
+ if #[cfg(ossl110)] {
+ use ffi::{
+ OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK,
+ OPENSSL_sk_new_null, OPENSSL_sk_push,
+ };
+ } else {
+ use ffi::{
+ sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num,
+ sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK,
+ sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push,
+ };
+ }
+}
+
+/// Trait implemented by types which can be placed in a stack.
+///
+/// It should not be implemented for any type outside of this crate.
+pub trait Stackable: ForeignType {
+ /// The C stack type for this element.
+ ///
+ /// Generally called `stack_st_{ELEMENT_TYPE}`, normally hidden by the
+ /// `STACK_OF(ELEMENT_TYPE)` macro in the OpenSSL API.
+ type StackType;
+}
+
+/// An owned stack of `T`.
+pub struct Stack<T: Stackable>(*mut T::StackType);
+
+unsafe impl<T: Stackable + Send> Send for Stack<T> {}
+unsafe impl<T: Stackable + Sync> Sync for Stack<T> {}
+
+impl<T> fmt::Debug for Stack<T>
+where
+ T: Stackable,
+ T::Ref: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_list().entries(self).finish()
+ }
+}
+impl<T: Stackable> Drop for Stack<T> {
+ fn drop(&mut self) {
+ unsafe {
+ while self.pop().is_some() {}
+ OPENSSL_sk_free(self.0 as *mut _);
+ }
+ }
+}
+
+impl<T: Stackable> Stack<T> {
+ pub fn new() -> Result<Stack<T>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let ptr = cvt_p(OPENSSL_sk_new_null())?;
+ Ok(Stack(ptr as *mut _))
+ }
+ }
+}
+
+impl<T: Stackable> iter::IntoIterator for Stack<T> {
+ type IntoIter = IntoIter<T>;
+ type Item = T;
+
+ fn into_iter(self) -> IntoIter<T> {
+ let it = IntoIter {
+ stack: self.0,
+ idxs: 0..self.len() as LenType,
+ };
+ mem::forget(self);
+ it
+ }
+}
+
+impl<T: Stackable> AsRef<StackRef<T>> for Stack<T> {
+ fn as_ref(&self) -> &StackRef<T> {
+ self
+ }
+}
+
+impl<T: Stackable> Borrow<StackRef<T>> for Stack<T> {
+ fn borrow(&self) -> &StackRef<T> {
+ self
+ }
+}
+
+impl<T: Stackable> ForeignType for Stack<T> {
+ type CType = T::StackType;
+ type Ref = StackRef<T>;
+
+ #[inline]
+ unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack<T> {
+ assert!(
+ !ptr.is_null(),
+ "Must not instantiate a Stack from a null-ptr - use Stack::new() in \
+ that case"
+ );
+ Stack(ptr)
+ }
+
+ #[inline]
+ fn as_ptr(&self) -> *mut T::StackType {
+ self.0
+ }
+}
+
+impl<T: Stackable> Deref for Stack<T> {
+ type Target = StackRef<T>;
+
+ fn deref(&self) -> &StackRef<T> {
+ unsafe { StackRef::from_ptr(self.0) }
+ }
+}
+
+impl<T: Stackable> DerefMut for Stack<T> {
+ fn deref_mut(&mut self) -> &mut StackRef<T> {
+ unsafe { StackRef::from_ptr_mut(self.0) }
+ }
+}
+
+pub struct IntoIter<T: Stackable> {
+ stack: *mut T::StackType,
+ idxs: Range<LenType>,
+}
+
+impl<T: Stackable> Drop for IntoIter<T> {
+ fn drop(&mut self) {
+ unsafe {
+ // https://github.com/rust-lang/rust-clippy/issues/7510
+ #[allow(clippy::while_let_on_iterator)]
+ while let Some(_) = self.next() {}
+ OPENSSL_sk_free(self.stack as *mut _);
+ }
+ }
+}
+
+impl<T: Stackable> Iterator for IntoIter<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ unsafe {
+ self.idxs
+ .next()
+ .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _))
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.idxs.size_hint()
+ }
+}
+
+impl<T: Stackable> DoubleEndedIterator for IntoIter<T> {
+ fn next_back(&mut self) -> Option<T> {
+ unsafe {
+ self.idxs
+ .next_back()
+ .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _))
+ }
+ }
+}
+
+impl<T: Stackable> ExactSizeIterator for IntoIter<T> {}
+
+pub struct StackRef<T: Stackable>(Opaque, PhantomData<T>);
+
+unsafe impl<T: Stackable + Send> Send for StackRef<T> {}
+unsafe impl<T: Stackable + Sync> Sync for StackRef<T> {}
+
+impl<T: Stackable> ForeignTypeRef for StackRef<T> {
+ type CType = T::StackType;
+}
+
+impl<T: Stackable> StackRef<T> {
+ fn as_stack(&self) -> *mut OPENSSL_STACK {
+ self.as_ptr() as *mut _
+ }
+
+ /// Returns the number of items in the stack.
+ pub fn len(&self) -> usize {
+ unsafe { OPENSSL_sk_num(self.as_stack()) as usize }
+ }
+
+ /// Determines if the stack is empty.
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ pub fn iter(&self) -> Iter<'_, T> {
+ Iter {
+ stack: self,
+ idxs: 0..self.len() as LenType,
+ }
+ }
+
+ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
+ IterMut {
+ idxs: 0..self.len() as LenType,
+ stack: self,
+ }
+ }
+
+ /// Returns a reference to the element at the given index in the
+ /// stack or `None` if the index is out of bounds
+ pub fn get(&self, idx: usize) -> Option<&T::Ref> {
+ unsafe {
+ if idx >= self.len() {
+ return None;
+ }
+
+ Some(T::Ref::from_ptr(self._get(idx)))
+ }
+ }
+
+ /// Returns a mutable reference to the element at the given index in the
+ /// stack or `None` if the index is out of bounds
+ pub fn get_mut(&mut self, idx: usize) -> Option<&mut T::Ref> {
+ unsafe {
+ if idx >= self.len() {
+ return None;
+ }
+
+ Some(T::Ref::from_ptr_mut(self._get(idx)))
+ }
+ }
+
+ /// Pushes a value onto the top of the stack.
+ pub fn push(&mut self, data: T) -> Result<(), ErrorStack> {
+ unsafe {
+ cvt(OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _) as c_int)?;
+ mem::forget(data);
+ Ok(())
+ }
+ }
+
+ /// Removes the last element from the stack and returns it.
+ pub fn pop(&mut self) -> Option<T> {
+ unsafe {
+ let ptr = OPENSSL_sk_pop(self.as_stack());
+ T::from_ptr_opt(ptr as *mut _)
+ }
+ }
+
+ unsafe fn _get(&self, idx: usize) -> *mut T::CType {
+ OPENSSL_sk_value(self.as_stack(), idx as LenType) as *mut _
+ }
+}
+
+impl<T: Stackable> Index<usize> for StackRef<T> {
+ type Output = T::Ref;
+
+ fn index(&self, index: usize) -> &T::Ref {
+ self.get(index).unwrap()
+ }
+}
+
+impl<T: Stackable> IndexMut<usize> for StackRef<T> {
+ fn index_mut(&mut self, index: usize) -> &mut T::Ref {
+ self.get_mut(index).unwrap()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef<T> {
+ type Item = &'a T::Ref;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> {
+ self.iter()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a mut StackRef<T> {
+ type Item = &'a mut T::Ref;
+ type IntoIter = IterMut<'a, T>;
+
+ fn into_iter(self) -> IterMut<'a, T> {
+ self.iter_mut()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a Stack<T> {
+ type Item = &'a T::Ref;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> {
+ self.iter()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack<T> {
+ type Item = &'a mut T::Ref;
+ type IntoIter = IterMut<'a, T>;
+
+ fn into_iter(self) -> IterMut<'a, T> {
+ self.iter_mut()
+ }
+}
+
+/// An iterator over the stack's contents.
+pub struct Iter<'a, T: Stackable> {
+ stack: &'a StackRef<T>,
+ idxs: Range<LenType>,
+}
+
+impl<'a, T: Stackable> Iterator for Iter<'a, T> {
+ type Item = &'a T::Ref;
+
+ fn next(&mut self) -> Option<&'a T::Ref> {
+ unsafe {
+ self.idxs
+ .next()
+ .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _))
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.idxs.size_hint()
+ }
+}
+
+impl<'a, T: Stackable> DoubleEndedIterator for Iter<'a, T> {
+ fn next_back(&mut self) -> Option<&'a T::Ref> {
+ unsafe {
+ self.idxs
+ .next_back()
+ .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _))
+ }
+ }
+}
+
+impl<'a, T: Stackable> ExactSizeIterator for Iter<'a, T> {}
+
+/// A mutable iterator over the stack's contents.
+pub struct IterMut<'a, T: Stackable> {
+ stack: &'a mut StackRef<T>,
+ idxs: Range<LenType>,
+}
+
+impl<'a, T: Stackable> Iterator for IterMut<'a, T> {
+ type Item = &'a mut T::Ref;
+
+ fn next(&mut self) -> Option<&'a mut T::Ref> {
+ unsafe {
+ self.idxs
+ .next()
+ .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _))
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.idxs.size_hint()
+ }
+}
+
+impl<'a, T: Stackable> DoubleEndedIterator for IterMut<'a, T> {
+ fn next_back(&mut self) -> Option<&'a mut T::Ref> {
+ unsafe {
+ self.idxs
+ .next_back()
+ .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _))
+ }
+ }
+}
+
+impl<'a, T: Stackable> ExactSizeIterator for IterMut<'a, T> {}