use std::io::{self, Error as IoError};
use std::ptr::NonNull;
use std::sync::Arc;
use super::context::Context;
use crate::bindings::*;
use crate::utils::interop::from_c_ret;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub(crate) struct IbvPd(Option<NonNull<ibv_pd>>);
impl IbvPd {
pub unsafe fn dealloc(self) -> io::Result<()> {
let ret = ibv_dealloc_pd(self.as_ptr());
from_c_ret(ret)
}
}
impl_ibv_wrapper_traits!(ibv_pd, IbvPd);
struct PdInner {
ctx: Context,
pd: IbvPd,
}
impl Drop for PdInner {
fn drop(&mut self) {
unsafe { self.pd.dealloc() }.expect("cannot dealloc PD on drop");
}
}
#[derive(Clone)]
pub struct Pd {
pd: IbvPd,
inner: Arc<PdInner>,
}
impl Pd {
pub fn new(ctx: &Context) -> io::Result<Self> {
let pd = unsafe { ibv_alloc_pd(ctx.as_raw()) };
let pd = NonNull::new(pd).ok_or_else(IoError::last_os_error)?;
let pd = IbvPd::from(pd);
Ok(Self {
inner: Arc::new(PdInner {
ctx: ctx.clone(),
pd,
}),
pd,
})
}
#[inline]
pub fn as_raw(&self) -> *mut ibv_pd {
self.pd.as_ptr()
}
#[inline]
pub fn context(&self) -> &Context {
&self.inner.ctx
}
pub fn leak(mut self) -> Result<*mut ibv_pd, Self> {
let mut inner = {
let inner = Arc::try_unwrap(self.inner);
match inner {
Ok(inner) => inner,
Err(inner) => {
self.inner = inner;
return Err(self);
}
}
};
let pd = inner.pd.0.take().unwrap();
Ok(pd.as_ptr())
}
}