pipewire/context/
rc.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4use std::{
5    fmt,
6    ops::Deref,
7    os::fd::{IntoRawFd, OwnedFd},
8    ptr,
9    rc::{Rc, Weak},
10};
11
12use crate::{
13    core::CoreRc,
14    loop_::{IsLoopRc, Loop},
15    properties::PropertiesBox,
16    Error,
17};
18
19use super::{Context, ContextBox};
20
21struct ContextRcInner {
22    context: ContextBox<'static>,
23    // Store the loop here, so that the loop is not dropped before the context,
24    // which may lead to undefined behaviour. Rusts drop order of struct fields
25    // (from top to bottom) ensures that this is always destroyed _after_ the context.
26    _loop: Box<dyn AsRef<Loop>>,
27}
28
29impl fmt::Debug for ContextRcInner {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_struct("ContextRcInner")
32            .field("context", &self.context)
33            .finish()
34    }
35}
36
37/// Reference counting smart pointer providing shared ownership of a PipeWire [context](super).
38///
39/// For the non-owning variant, see [`ContextWeak`]. For unique ownership, see [`ContextBox`].
40///
41/// For an explanation of these, see [Smart pointers to PipeWire objects](crate#smart-pointers-to-pipewire-objects).
42#[derive(Clone, Debug)]
43pub struct ContextRc {
44    inner: Rc<ContextRcInner>,
45}
46
47impl ContextRc {
48    pub fn new<T: IsLoopRc>(loop_: &T, properties: Option<PropertiesBox>) -> Result<Self, Error> {
49        let loop_: Box<dyn AsRef<Loop>> = Box::new(loop_.clone());
50        let props = properties
51            .map_or(ptr::null(), |props| props.into_raw())
52            .cast_mut();
53
54        unsafe {
55            let raw = ptr::NonNull::new(pw_sys::pw_context_new(
56                (*loop_).as_ref().as_raw_ptr(),
57                props,
58                0,
59            ))
60            .ok_or(Error::CreationFailed)?;
61
62            let context: ContextBox<'static> = ContextBox::from_raw(raw);
63
64            Ok(ContextRc {
65                inner: Rc::new(ContextRcInner {
66                    context,
67                    _loop: loop_,
68                }),
69            })
70        }
71    }
72
73    // TODO: from_raw()
74
75    pub fn downgrade(&self) -> ContextWeak {
76        let weak = Rc::downgrade(&self.inner);
77        ContextWeak { weak }
78    }
79
80    pub fn connect_rc(&self, properties: Option<PropertiesBox>) -> Result<CoreRc, Error> {
81        let properties = properties.map_or(ptr::null_mut(), |p| p.into_raw());
82
83        unsafe {
84            let core = pw_sys::pw_context_connect(self.as_raw_ptr(), properties, 0);
85            let ptr = ptr::NonNull::new(core).ok_or(Error::CreationFailed)?;
86
87            Ok(CoreRc::from_raw(ptr, self.clone()))
88        }
89    }
90
91    pub fn connect_fd_rc(
92        &self,
93        fd: OwnedFd,
94        properties: Option<PropertiesBox>,
95    ) -> Result<CoreRc, Error> {
96        let properties = properties.map_or(ptr::null_mut(), |p| p.into_raw());
97
98        unsafe {
99            let raw_fd = fd.into_raw_fd();
100            let core = pw_sys::pw_context_connect_fd(self.as_raw_ptr(), raw_fd, properties, 0);
101            let ptr = ptr::NonNull::new(core).ok_or(Error::CreationFailed)?;
102
103            Ok(CoreRc::from_raw(ptr, self.clone()))
104        }
105    }
106}
107
108impl std::ops::Deref for ContextRc {
109    type Target = Context;
110
111    fn deref(&self) -> &Self::Target {
112        self.inner.context.deref()
113    }
114}
115
116impl std::convert::AsRef<Context> for ContextRc {
117    fn as_ref(&self) -> &Context {
118        self.deref()
119    }
120}
121
122/// Non-owning reference to a [context](super) managed by [`ContextRc`].
123///
124/// The context can be accessed by calling [`upgrade`](Self::upgrade).
125pub struct ContextWeak {
126    weak: Weak<ContextRcInner>,
127}
128
129impl ContextWeak {
130    pub fn upgrade(&self) -> Option<ContextRc> {
131        self.weak.upgrade().map(|inner| ContextRc { inner })
132    }
133}