From 3bdefa987a0d36bbf77687f2376f4b29f0a20814 Mon Sep 17 00:00:00 2001 From: Lionel Flandrin Date: Mon, 31 Oct 2016 23:49:38 +0100 Subject: Implement a generic Stack API to deal with OpenSSL stacks --- openssl/src/stack.rs | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 openssl/src/stack.rs (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs new file mode 100644 index 00000000..2cc53b5f --- /dev/null +++ b/openssl/src/stack.rs @@ -0,0 +1,319 @@ +use std::ops::{Deref, DerefMut, Index, IndexMut}; +use std::iter; +use std::borrow::Borrow; +use std::convert::AsRef; + +#[cfg(ossl110)] +use libc::c_int; + +use ffi; +use types::{OpenSslType, Ref}; + +/// Trait implemented by stackable types. This must *only* be +/// implemented on opaque types that can be directly casted into their +/// `CType`. +pub trait Stackable: OpenSslType { + /// 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(*mut T::StackType); + +impl Stack { + /// Return a new Stack, taking ownership of the handle + pub unsafe fn from_ptr(stack: *mut T::StackType) -> Stack { + Stack(stack) + } +} + +impl Drop for Stack { + #[cfg(ossl10x)] + fn drop(&mut self) { + unsafe { + loop { + let ptr = ffi::sk_pop(self.as_stack()); + + if ptr.is_null() { + break; + } + + // Build the owned version of the object just to run + // its `drop` implementation and delete the item. + T::from_ptr(ptr as *mut _); + } + + ffi::sk_free(self.0 as *mut _); + } + } + + #[cfg(ossl110)] + fn drop(&mut self) { + unsafe { + loop { + let ptr = ffi::OPENSSL_sk_pop(self.as_stack()); + + if ptr.is_null() { + break; + } + + // Build the owned version of the object just to run + // its `drop` implementation and delete the item. + T::from_ptr(ptr as *mut _); + } + + ffi::OPENSSL_sk_free(self.0 as *mut _); + } + } +} + +impl AsRef>> for Stack { + fn as_ref(&self) -> &Ref> { + &*self + } +} + +impl Borrow>> for Stack { + fn borrow(&self) -> &Ref> { + &*self + } +} + +unsafe impl OpenSslType for Stack { + type CType = T::StackType; + + unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack { + Stack(ptr) + } + + fn as_ptr(&self) -> *mut T::StackType { + self.0 + } +} + +impl Deref for Stack { + type Target = Ref>; + + fn deref(&self) -> &Ref> { + unsafe { Ref::from_ptr(self.0) } + } +} + +impl DerefMut for Stack { + fn deref_mut(&mut self) -> &mut ::types::Ref> { + unsafe { Ref::from_ptr_mut(self.0) } + } +} + +impl Ref> { + /// OpenSSL stack types are just a (kinda) typesafe wrapper around + /// a `_STACK` object. We can therefore safely cast it and access + /// the `_STACK` members without having to worry about the real + /// layout of `T::StackType`. + /// + /// If that sounds unsafe then keep in mind that's exactly how the + /// OpenSSL 1.1.0 new C stack code works. + #[cfg(ossl10x)] + fn as_stack(&self) -> *mut ffi::_STACK { + self.as_ptr() as *mut _ + } + + /// OpenSSL 1.1.0 replaced the stack macros with a functions and + /// only exposes an opaque OPENSSL_STACK struct + /// publicly. + #[cfg(ossl110)] + fn as_stack(&self) -> *mut ffi::OPENSSL_STACK { + self.as_ptr() as *mut _ + } + + /// Returns the number of items in the stack + pub fn len(&self) -> usize { + self._len() + } + + #[cfg(ossl10x)] + fn _len(&self) -> usize { + unsafe { (*self.as_stack()).num as usize } + } + + #[cfg(ossl110)] + fn _len(&self) -> usize { + unsafe { ffi::OPENSSL_sk_num(self.as_stack()) as usize } + } + + pub fn iter(&self) -> Iter { + // Unfortunately we can't simply convert the stack into a + // slice and use that because OpenSSL 1.1.0 doesn't directly + // expose the stack data (we have to use `OPENSSL_sk_value` + // instead). We have to rewrite the entire iteration framework + // instead. + + Iter { + stack: self, + pos: 0, + } + } + + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + stack: self, + pos: 0, + } + } + + /// 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<&Ref> { + if idx >= self.len() { + return None; + } + + unsafe { + let r = Ref::from_ptr(self._get(idx)); + + Some(r) + } + } + + /// 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 Ref> { + if idx >= self.len() { + return None; + } + + unsafe { + Some(Ref::from_ptr_mut(self._get(idx))) + } + } + + #[cfg(ossl10x)] + unsafe fn _get(&self, idx: usize) -> *mut T::CType { + *(*self.as_stack()).data.offset(idx as isize) as *mut _ + } + + #[cfg(ossl110)] + unsafe fn _get(&self, idx: usize) -> *mut T::CType { + ffi::OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ + } +} + +impl Index for Ref> { + type Output = Ref; + + fn index(&self, index: usize) -> &Ref { + self.get(index).unwrap() + } +} + +impl IndexMut for Ref> { + fn index_mut(&mut self, index: usize) -> &mut Ref { + self.get_mut(index).unwrap() + } +} + +impl<'a, T: Stackable> iter::IntoIterator for &'a Ref> { + type Item = &'a Ref; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T: Stackable> iter::IntoIterator for &'a mut Ref> { + type Item = &'a mut 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 { + type Item = &'a 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 { + type Item = &'a mut 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> + where T: 'a { + stack: &'a Ref>, + pos: usize, +} + +impl<'a, T: Stackable> iter::Iterator for Iter<'a, T> { + type Item = &'a Ref; + + fn next(&mut self) -> Option<&'a Ref> { + let n = self.stack.get(self.pos); + + if n.is_some() { + self.pos += 1; + } + + n + } + + fn size_hint(&self) -> (usize, Option) { + let rem = self.stack.len() - self.pos; + + (rem, Some(rem)) + } +} + +impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> { +} + +/// A mutable iterator over the stack's contents. +pub struct IterMut<'a, T: Stackable + 'a> { + stack: &'a mut Ref>, + pos: usize, +} + +impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> { + type Item = &'a mut Ref; + + fn next(&mut self) -> Option<&'a mut Ref> { + if self.pos >= self.stack.len() { + None + } else { + // Rust won't allow us to get a mutable reference into + // `stack` in this situation since it can't statically + // guarantee that we won't return several references to + // the same object, so we have to use unsafe code for + // mutable iterators. + let n = unsafe { + Some(Ref::from_ptr_mut(self.stack._get(self.pos))) + }; + + self.pos += 1; + + n + } + } + + fn size_hint(&self) -> (usize, Option) { + let rem = self.stack.len() - self.pos; + + (rem, Some(rem)) + } +} + +impl<'a, T: Stackable> iter::ExactSizeIterator for IterMut<'a, T> { +} -- cgit v1.2.3 From 79c51d5e517ffe40e01c34577667c0a242a5f6ba Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 1 Nov 2016 19:12:38 -0700 Subject: Clean up stack destructor --- openssl/src/stack.rs | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index 2cc53b5f..bb1ddfda 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -9,12 +9,19 @@ use libc::c_int; use ffi; use types::{OpenSslType, Ref}; -/// Trait implemented by stackable types. This must *only* be -/// implemented on opaque types that can be directly casted into their -/// `CType`. +#[cfg(ossl10x)] +use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free}; +#[cfg(ossl110)] +use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free}; + +/// Trait implemented by types which can be placed in a stack. +/// +/// Like `OpenSslType`, it should not be implemented for any type outside +/// of this crate. pub trait Stackable: OpenSslType { - /// C stack type for this element. Generally called - /// `stack_st_{ELEMENT_TYPE}`, normally hidden by the + /// 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; } @@ -30,30 +37,10 @@ impl Stack { } impl Drop for Stack { - #[cfg(ossl10x)] - fn drop(&mut self) { - unsafe { - loop { - let ptr = ffi::sk_pop(self.as_stack()); - - if ptr.is_null() { - break; - } - - // Build the owned version of the object just to run - // its `drop` implementation and delete the item. - T::from_ptr(ptr as *mut _); - } - - ffi::sk_free(self.0 as *mut _); - } - } - - #[cfg(ossl110)] fn drop(&mut self) { unsafe { loop { - let ptr = ffi::OPENSSL_sk_pop(self.as_stack()); + let ptr = OPENSSL_sk_pop(self.as_stack()); if ptr.is_null() { break; @@ -64,7 +51,7 @@ impl Drop for Stack { T::from_ptr(ptr as *mut _); } - ffi::OPENSSL_sk_free(self.0 as *mut _); + OPENSSL_sk_free(self.0 as *mut _); } } } -- cgit v1.2.3 From c776534ad4c89a23870aafb83709a25bc558fad0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 1 Nov 2016 19:25:40 -0700 Subject: Clean up stack --- openssl/src/stack.rs | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index bb1ddfda..e48ebe77 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -2,17 +2,16 @@ use std::ops::{Deref, DerefMut, Index, IndexMut}; use std::iter; use std::borrow::Borrow; use std::convert::AsRef; - -#[cfg(ossl110)] use libc::c_int; use ffi; use types::{OpenSslType, Ref}; #[cfg(ossl10x)] -use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free}; +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}; #[cfg(ossl110)] -use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free}; +use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value}; /// Trait implemented by types which can be placed in a stack. /// @@ -117,17 +116,7 @@ impl Ref> { /// Returns the number of items in the stack pub fn len(&self) -> usize { - self._len() - } - - #[cfg(ossl10x)] - fn _len(&self) -> usize { - unsafe { (*self.as_stack()).num as usize } - } - - #[cfg(ossl110)] - fn _len(&self) -> usize { - unsafe { ffi::OPENSSL_sk_num(self.as_stack()) as usize } + unsafe { OPENSSL_sk_num(self.as_stack()) as usize } } pub fn iter(&self) -> Iter { @@ -176,14 +165,9 @@ impl Ref> { } } - #[cfg(ossl10x)] - unsafe fn _get(&self, idx: usize) -> *mut T::CType { - *(*self.as_stack()).data.offset(idx as isize) as *mut _ - } - - #[cfg(ossl110)] unsafe fn _get(&self, idx: usize) -> *mut T::CType { - ffi::OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ + assert!(idx <= c_int::max_value() as usize); + OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ } } -- cgit v1.2.3 From d5a9a239f688f3820db6d61ed77467152dfe72cf Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 1 Nov 2016 19:36:08 -0700 Subject: More minor cleanup --- openssl/src/stack.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index e48ebe77..368b6e07 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -142,31 +142,28 @@ impl Ref> { /// 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<&Ref> { - if idx >= self.len() { - return None; - } - unsafe { - let r = Ref::from_ptr(self._get(idx)); + if idx >= self.len() { + return None; + } - Some(r) + Some(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 Ref> { - if idx >= self.len() { - return None; - } - unsafe { + if idx >= self.len() { + return None; + } + Some(Ref::from_ptr_mut(self._get(idx))) } } unsafe fn _get(&self, idx: usize) -> *mut T::CType { - assert!(idx <= c_int::max_value() as usize); OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ } } -- cgit v1.2.3 From 01ae978db0dc8620b2cc754c0d5cf94a68c1f549 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 4 Nov 2016 16:32:20 -0700 Subject: Get rid of Ref There's unfortunately a rustdoc bug that causes all methods implemented for any Ref to be inlined in the deref methods section :( --- openssl/src/stack.rs | 82 ++++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 38 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index 368b6e07..ad208377 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -2,10 +2,12 @@ use std::ops::{Deref, DerefMut, Index, IndexMut}; use std::iter; use std::borrow::Borrow; use std::convert::AsRef; +use std::marker::PhantomData; use libc::c_int; use ffi; -use types::{OpenSslType, Ref}; +use types::{OpenSslType, OpenSslTypeRef}; +use util::Opaque; #[cfg(ossl10x)] use ffi::{sk_pop as OPENSSL_sk_pop,sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, @@ -55,45 +57,49 @@ impl Drop for Stack { } } -impl AsRef>> for Stack { - fn as_ref(&self) -> &Ref> { +impl AsRef> for Stack { + fn as_ref(&self) -> &StackRef { &*self } } -impl Borrow>> for Stack { - fn borrow(&self) -> &Ref> { +impl Borrow> for Stack { + fn borrow(&self) -> &StackRef { &*self } } -unsafe impl OpenSslType for Stack { +impl OpenSslType for Stack { type CType = T::StackType; + type Ref = StackRef; unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack { Stack(ptr) } - - fn as_ptr(&self) -> *mut T::StackType { - self.0 - } } impl Deref for Stack { - type Target = Ref>; + type Target = StackRef; - fn deref(&self) -> &Ref> { - unsafe { Ref::from_ptr(self.0) } + fn deref(&self) -> &StackRef { + unsafe { StackRef::from_ptr(self.0) } } } impl DerefMut for Stack { - fn deref_mut(&mut self) -> &mut ::types::Ref> { - unsafe { Ref::from_ptr_mut(self.0) } + fn deref_mut(&mut self) -> &mut StackRef { + unsafe { StackRef::from_ptr_mut(self.0) } } } -impl Ref> { +pub struct StackRef(Opaque, PhantomData); + +impl OpenSslTypeRef for StackRef { + type CType = T::StackType; +} + + +impl StackRef { /// OpenSSL stack types are just a (kinda) typesafe wrapper around /// a `_STACK` object. We can therefore safely cast it and access /// the `_STACK` members without having to worry about the real @@ -141,25 +147,25 @@ impl Ref> { /// 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<&Ref> { + pub fn get(&self, idx: usize) -> Option<&T::Ref> { unsafe { if idx >= self.len() { return None; } - Some(Ref::from_ptr(self._get(idx))) + 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 Ref> { + pub fn get_mut(&mut self, idx: usize) -> Option<&mut T::Ref> { unsafe { if idx >= self.len() { return None; } - Some(Ref::from_ptr_mut(self._get(idx))) + Some(T::Ref::from_ptr_mut(self._get(idx))) } } @@ -168,22 +174,22 @@ impl Ref> { } } -impl Index for Ref> { - type Output = Ref; +impl Index for StackRef { + type Output = T::Ref; - fn index(&self, index: usize) -> &Ref { + fn index(&self, index: usize) -> &T::Ref { self.get(index).unwrap() } } -impl IndexMut for Ref> { - fn index_mut(&mut self, index: usize) -> &mut Ref { +impl IndexMut for StackRef { + fn index_mut(&mut self, index: usize) -> &mut T::Ref { self.get_mut(index).unwrap() } } -impl<'a, T: Stackable> iter::IntoIterator for &'a Ref> { - type Item = &'a Ref; +impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef { + type Item = &'a T::Ref; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Iter<'a, T> { @@ -191,8 +197,8 @@ impl<'a, T: Stackable> iter::IntoIterator for &'a Ref> { } } -impl<'a, T: Stackable> iter::IntoIterator for &'a mut Ref> { - type Item = &'a mut Ref; +impl<'a, T: Stackable> iter::IntoIterator for &'a mut StackRef { + type Item = &'a mut T::Ref; type IntoIter = IterMut<'a, T>; fn into_iter(self) -> IterMut<'a, T> { @@ -201,7 +207,7 @@ impl<'a, T: Stackable> iter::IntoIterator for &'a mut Ref> { } impl<'a, T: Stackable> iter::IntoIterator for &'a Stack { - type Item = &'a Ref; + type Item = &'a T::Ref; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Iter<'a, T> { @@ -210,7 +216,7 @@ impl<'a, T: Stackable> iter::IntoIterator for &'a Stack { } impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack { - type Item = &'a mut Ref; + type Item = &'a mut T::Ref; type IntoIter = IterMut<'a, T>; fn into_iter(self) -> IterMut<'a, T> { @@ -221,14 +227,14 @@ impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack { /// An iterator over the stack's contents. pub struct Iter<'a, T: Stackable> where T: 'a { - stack: &'a Ref>, + stack: &'a StackRef, pos: usize, } impl<'a, T: Stackable> iter::Iterator for Iter<'a, T> { - type Item = &'a Ref; + type Item = &'a T::Ref; - fn next(&mut self) -> Option<&'a Ref> { + fn next(&mut self) -> Option<&'a T::Ref> { let n = self.stack.get(self.pos); if n.is_some() { @@ -250,14 +256,14 @@ impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> { /// A mutable iterator over the stack's contents. pub struct IterMut<'a, T: Stackable + 'a> { - stack: &'a mut Ref>, + stack: &'a mut StackRef, pos: usize, } impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> { - type Item = &'a mut Ref; + type Item = &'a mut T::Ref; - fn next(&mut self) -> Option<&'a mut Ref> { + fn next(&mut self) -> Option<&'a mut T::Ref> { if self.pos >= self.stack.len() { None } else { @@ -267,7 +273,7 @@ impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> { // the same object, so we have to use unsafe code for // mutable iterators. let n = unsafe { - Some(Ref::from_ptr_mut(self.stack._get(self.pos))) + Some(T::Ref::from_ptr_mut(self.stack._get(self.pos))) }; self.pos += 1; -- cgit v1.2.3 From f15c817c2d1fad288fe0f88d4e3995df4aa4a477 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 5 Nov 2016 10:54:17 -0700 Subject: Rustfmt --- openssl/src/stack.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index ad208377..318791b8 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -10,8 +10,8 @@ use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; #[cfg(ossl10x)] -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}; +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}; #[cfg(ossl110)] use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value}; @@ -226,7 +226,8 @@ impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack { /// An iterator over the stack's contents. pub struct Iter<'a, T: Stackable> - where T: 'a { + where T: 'a +{ stack: &'a StackRef, pos: usize, } @@ -251,8 +252,7 @@ impl<'a, T: Stackable> iter::Iterator for Iter<'a, T> { } } -impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> { -} +impl<'a, T: Stackable> iter::ExactSizeIterator for Iter<'a, T> {} /// A mutable iterator over the stack's contents. pub struct IterMut<'a, T: Stackable + 'a> { @@ -272,9 +272,7 @@ impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> { // guarantee that we won't return several references to // the same object, so we have to use unsafe code for // mutable iterators. - let n = unsafe { - Some(T::Ref::from_ptr_mut(self.stack._get(self.pos))) - }; + let n = unsafe { Some(T::Ref::from_ptr_mut(self.stack._get(self.pos))) }; self.pos += 1; @@ -289,5 +287,4 @@ impl<'a, T: Stackable> iter::Iterator for IterMut<'a, T> { } } -impl<'a, T: Stackable> iter::ExactSizeIterator for IterMut<'a, T> { -} +impl<'a, T: Stackable> iter::ExactSizeIterator for IterMut<'a, T> {} -- cgit v1.2.3 From 398ab2fbc4f8c254633541a9c0e46b688be14668 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 5 Nov 2016 13:01:54 -0700 Subject: Add a consuming iterator for Stacks --- openssl/src/stack.rs | 91 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 21 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index 318791b8..8359f785 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -4,16 +4,16 @@ use std::borrow::Borrow; use std::convert::AsRef; use std::marker::PhantomData; use libc::c_int; +use std::mem; -use ffi; use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; #[cfg(ossl10x)] 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}; + sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK}; #[cfg(ossl110)] -use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value}; +use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK}; /// Trait implemented by types which can be placed in a stack. /// @@ -57,6 +57,20 @@ impl Drop for Stack { } } +impl iter::IntoIterator for Stack { + type IntoIter = IntoIter; + type Item = T; + + fn into_iter(self) -> IntoIter { + let it = IntoIter { + stack: self.0, + idx: 0, + }; + mem::forget(self); + it + } +} + impl AsRef> for Stack { fn as_ref(&self) -> &StackRef { &*self @@ -92,31 +106,66 @@ impl DerefMut for Stack { } } +pub struct IntoIter { + stack: *mut T::StackType, + idx: c_int, +} + +impl IntoIter { + fn stack_len(&self) -> c_int { + unsafe { OPENSSL_sk_num(self.stack as *mut _) } + } + + unsafe fn get(&mut self, i: c_int) -> T { + let ptr = OPENSSL_sk_value(self.stack as *mut _, i); + T::from_ptr(ptr as *mut _) + } +} + +impl Drop for IntoIter { + fn drop(&mut self) { + unsafe { + for i in self.idx..self.stack_len() { + self.get(i); + } + + OPENSSL_sk_free(self.stack as *mut _); + } + } +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + if self.idx == self.stack_len() { + None + } else { + let idx = self.idx; + self.idx += 1; + let v = self.get(idx); + Some(v) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = (self.stack_len() - self.idx) as usize; + (size, Some(size)) + } +} + +impl ExactSizeIterator for IntoIter {} + pub struct StackRef(Opaque, PhantomData); impl OpenSslTypeRef for StackRef { type CType = T::StackType; } - impl StackRef { - /// OpenSSL stack types are just a (kinda) typesafe wrapper around - /// a `_STACK` object. We can therefore safely cast it and access - /// the `_STACK` members without having to worry about the real - /// layout of `T::StackType`. - /// - /// If that sounds unsafe then keep in mind that's exactly how the - /// OpenSSL 1.1.0 new C stack code works. - #[cfg(ossl10x)] - fn as_stack(&self) -> *mut ffi::_STACK { - self.as_ptr() as *mut _ - } - - /// OpenSSL 1.1.0 replaced the stack macros with a functions and - /// only exposes an opaque OPENSSL_STACK struct - /// publicly. - #[cfg(ossl110)] - fn as_stack(&self) -> *mut ffi::OPENSSL_STACK { + fn as_stack(&self) -> *mut OPENSSL_STACK { self.as_ptr() as *mut _ } -- cgit v1.2.3 From ac36d542fd6de8e174cf4d70e38144da47412027 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 5 Nov 2016 13:10:50 -0700 Subject: Simplify destructor a bit --- openssl/src/stack.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index 8359f785..c56c8230 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -125,10 +125,7 @@ impl IntoIter { impl Drop for IntoIter { fn drop(&mut self) { unsafe { - for i in self.idx..self.stack_len() { - self.get(i); - } - + while let Some(_) = self.next() {} OPENSSL_sk_free(self.stack as *mut _); } } -- cgit v1.2.3 From 52feaae59f91c4de368a7942519488aa3beed6f9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 5 Nov 2016 13:15:14 -0700 Subject: More cleanup --- openssl/src/stack.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index c56c8230..50694919 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -115,11 +115,6 @@ impl IntoIter { fn stack_len(&self) -> c_int { unsafe { OPENSSL_sk_num(self.stack as *mut _) } } - - unsafe fn get(&mut self, i: c_int) -> T { - let ptr = OPENSSL_sk_value(self.stack as *mut _, i); - T::from_ptr(ptr as *mut _) - } } impl Drop for IntoIter { @@ -139,10 +134,9 @@ impl Iterator for IntoIter { if self.idx == self.stack_len() { None } else { - let idx = self.idx; + let ptr = OPENSSL_sk_value(self.stack as *mut _, self.idx); self.idx += 1; - let v = self.get(idx); - Some(v) + Some(T::from_ptr(ptr as *mut _)) } } } -- cgit v1.2.3 From ed69d6b0370bd033e78accf6d7a397de25b4ca05 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 5 Nov 2016 13:40:53 -0700 Subject: Add Stack::pop --- openssl/src/stack.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'openssl/src/stack.rs') diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index 50694919..dae42ca8 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -40,18 +40,7 @@ impl Stack { impl Drop for Stack { fn drop(&mut self) { unsafe { - loop { - let ptr = OPENSSL_sk_pop(self.as_stack()); - - if ptr.is_null() { - break; - } - - // Build the owned version of the object just to run - // its `drop` implementation and delete the item. - T::from_ptr(ptr as *mut _); - } - + while let Some(_) = self.pop() {} OPENSSL_sk_free(self.0 as *mut _); } } @@ -209,6 +198,18 @@ impl StackRef { } } + /// Removes the last element from the stack and returns it. + pub fn pop(&mut self) -> Option { + unsafe { + let ptr = OPENSSL_sk_pop(self.as_stack()); + if ptr.is_null() { + None + } else { + Some(T::from_ptr(ptr as *mut _)) + } + } + } + unsafe fn _get(&self, idx: usize) -> *mut T::CType { OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ } -- cgit v1.2.3