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#[derive(Clone, Debug)]
38pub struct ContextRc {
39    inner: Rc<ContextRcInner>,
40}
41
42impl ContextRc {
43    pub fn new<T: IsLoopRc>(loop_: &T, properties: Option<PropertiesBox>) -> Result<Self, Error> {
44        let loop_: Box<dyn AsRef<Loop>> = Box::new(loop_.clone());
45        let props = properties
46            .map_or(ptr::null(), |props| props.into_raw())
47            .cast_mut();
48
49        unsafe {
50            let raw = ptr::NonNull::new(pw_sys::pw_context_new(
51                (*loop_).as_ref().as_raw_ptr(),
52                props,
53                0,
54            ))
55            .ok_or(Error::CreationFailed)?;
56
57            let context: ContextBox<'static> = ContextBox::from_raw(raw);
58
59            Ok(ContextRc {
60                inner: Rc::new(ContextRcInner {
61                    context,
62                    _loop: loop_,
63                }),
64            })
65        }
66    }
67
68    // TODO: from_raw()
69
70    pub fn downgrade(&self) -> ContextWeak {
71        let weak = Rc::downgrade(&self.inner);
72        ContextWeak { weak }
73    }
74
75    pub fn connect_rc(&self, properties: Option<PropertiesBox>) -> Result<CoreRc, Error> {
76        let properties = properties.map_or(ptr::null_mut(), |p| p.into_raw());
77
78        unsafe {
79            let core = pw_sys::pw_context_connect(self.as_raw_ptr(), properties, 0);
80            let ptr = ptr::NonNull::new(core).ok_or(Error::CreationFailed)?;
81
82            Ok(CoreRc::from_raw(ptr, self.clone()))
83        }
84    }
85
86    pub fn connect_fd_rc(
87        &self,
88        fd: OwnedFd,
89        properties: Option<PropertiesBox>,
90    ) -> Result<CoreRc, Error> {
91        let properties = properties.map_or(ptr::null_mut(), |p| p.into_raw());
92
93        unsafe {
94            let raw_fd = fd.into_raw_fd();
95            let core = pw_sys::pw_context_connect_fd(self.as_raw_ptr(), raw_fd, properties, 0);
96            let ptr = ptr::NonNull::new(core).ok_or(Error::CreationFailed)?;
97
98            Ok(CoreRc::from_raw(ptr, self.clone()))
99        }
100    }
101}
102
103impl std::ops::Deref for ContextRc {
104    type Target = Context;
105
106    fn deref(&self) -> &Self::Target {
107        self.inner.context.deref()
108    }
109}
110
111impl std::convert::AsRef<Context> for ContextRc {
112    fn as_ref(&self) -> &Context {
113        self.deref()
114    }
115}
116
117pub struct ContextWeak {
118    weak: Weak<ContextRcInner>,
119}
120
121impl ContextWeak {
122    pub fn upgrade(&self) -> Option<ContextRc> {
123        self.weak.upgrade().map(|inner| ContextRc { inner })
124    }
125}