use std::{
fmt,
ops::Deref,
os::fd::{IntoRawFd, OwnedFd},
ptr,
rc::{Rc, Weak},
};
use crate::{
core::CoreRc,
loop_::{IsLoopRc, Loop},
properties::PropertiesBox,
Error,
};
use super::{Context, ContextBox};
struct ContextRcInner {
context: ContextBox<'static>,
_loop: Box<dyn AsRef<Loop>>,
}
impl fmt::Debug for ContextRcInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ContextRcInner")
.field("context", &self.context)
.finish()
}
}
#[derive(Clone, Debug)]
pub struct ContextRc {
inner: Rc<ContextRcInner>,
}
impl ContextRc {
pub fn new<T: IsLoopRc>(loop_: &T, properties: Option<PropertiesBox>) -> Result<Self, Error> {
let loop_: Box<dyn AsRef<Loop>> = Box::new(loop_.clone());
let props = properties
.map_or(ptr::null(), |props| props.into_raw())
.cast_mut();
unsafe {
let raw = ptr::NonNull::new(pw_sys::pw_context_new(
(*loop_).as_ref().as_raw_ptr(),
props,
0,
))
.ok_or(Error::CreationFailed)?;
let context: ContextBox<'static> = ContextBox::from_raw(raw);
Ok(ContextRc {
inner: Rc::new(ContextRcInner {
context,
_loop: loop_,
}),
})
}
}
pub fn downgrade(&self) -> ContextWeak {
let weak = Rc::downgrade(&self.inner);
ContextWeak { weak }
}
pub fn connect_rc(&self, properties: Option<PropertiesBox>) -> Result<CoreRc, Error> {
let properties = properties.map_or(ptr::null_mut(), |p| p.into_raw());
unsafe {
let core = pw_sys::pw_context_connect(self.as_raw_ptr(), properties, 0);
let ptr = ptr::NonNull::new(core).ok_or(Error::CreationFailed)?;
Ok(CoreRc::from_raw(ptr, self.clone()))
}
}
pub fn connect_fd_rc(
&self,
fd: OwnedFd,
properties: Option<PropertiesBox>,
) -> Result<CoreRc, Error> {
let properties = properties.map_or(ptr::null_mut(), |p| p.into_raw());
unsafe {
let raw_fd = fd.into_raw_fd();
let core = pw_sys::pw_context_connect_fd(self.as_raw_ptr(), raw_fd, properties, 0);
let ptr = ptr::NonNull::new(core).ok_or(Error::CreationFailed)?;
Ok(CoreRc::from_raw(ptr, self.clone()))
}
}
}
impl std::ops::Deref for ContextRc {
type Target = Context;
fn deref(&self) -> &Self::Target {
self.inner.context.deref()
}
}
impl std::convert::AsRef<Context> for ContextRc {
fn as_ref(&self) -> &Context {
self.deref()
}
}
pub struct ContextWeak {
weak: Weak<ContextRcInner>,
}
impl ContextWeak {
pub fn upgrade(&self) -> Option<ContextRc> {
self.weak.upgrade().map(|inner| ContextRc { inner })
}
}