// Copyright (c) 2023 Huawei Device Co., Ltd. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use core::borrow::Borrow; use core::marker::PhantomData; use core::mem::forget; use core::ops::{Deref, DerefMut, Range}; use libc::c_int; use super::ffi::stack::{ OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_pop, OPENSSL_sk_value, OPENSSL_STACK, }; use crate::c_openssl::foreign::{Foreign, ForeignRef, ForeignRefWrapper}; pub(crate) trait Stackof: Foreign { type StackType; } pub(crate) struct Stack(*mut T::StackType); pub(crate) struct StackRef(ForeignRefWrapper, PhantomData); unsafe impl Send for Stack {} unsafe impl Sync for Stack {} unsafe impl Send for StackRef {} unsafe impl Sync for StackRef {} impl Deref for Stack { type Target = StackRef; fn deref(&self) -> &StackRef { unsafe { StackRef::from_ptr(self.0) } } } impl DerefMut for Stack { fn deref_mut(&mut self) -> &mut StackRef { unsafe { StackRef::from_ptr_mut(self.0) } } } impl AsRef> for Stack { fn as_ref(&self) -> &StackRef { self } } impl Borrow> for Stack { fn borrow(&self) -> &StackRef { self } } impl Drop for Stack { fn drop(&mut self) { unsafe { while self.pop().is_some() {} OPENSSL_sk_free(self.0 as *mut _) } } } pub(crate) struct StackRefIter<'a, T: Stackof> where T: 'a, { stack: &'a StackRef, index: Range, } impl<'a, T: Stackof> Iterator for StackRefIter<'a, T> { type Item = &'a T::Ref; fn next(&mut self) -> Option<&'a T::Ref> { unsafe { self.index .next() .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) } } fn size_hint(&self) -> (usize, Option) { self.index.size_hint() } } impl StackRef { #[allow(clippy::len_without_is_empty)] pub(crate) fn len(&self) -> usize { unsafe { OPENSSL_sk_num(self.as_stack()) as usize } } pub(crate) fn pop(&mut self) -> Option { unsafe { let ptr = OPENSSL_sk_pop(self.as_stack()); match ptr.is_null() { true => None, false => Some(T::from_ptr(ptr as *mut _)), } } } } impl ForeignRef for StackRef { type CStruct = T::StackType; } impl StackRef { fn as_stack(&self) -> *mut OPENSSL_STACK { self.as_ptr() as *mut _ } } impl Foreign for Stack { type CStruct = T::StackType; type Ref = StackRef; fn from_ptr(ptr: *mut Self::CStruct) -> Self { Stack(ptr) } fn as_ptr(&self) -> *mut Self::CStruct { self.0 } } pub(crate) struct IntoStackIter { stack: *mut T::StackType, index: Range, } impl Iterator for IntoStackIter { type Item = T; fn next(&mut self) -> Option { unsafe { self.index .next() .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _)) } } } impl Drop for IntoStackIter { fn drop(&mut self) { unsafe { while self.next().is_some() {} OPENSSL_sk_free(self.stack as *mut _); } } } impl IntoIterator for Stack { type Item = T; type IntoIter = IntoStackIter; fn into_iter(self) -> IntoStackIter { let it = IntoStackIter { stack: self.0, index: 0..self.len() as c_int, }; forget(self); it } }