pipewire/thread_loop/
rc.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4use std::{
5    ffi::CStr,
6    ops::Deref,
7    ptr,
8    rc::{Rc, Weak},
9};
10
11use crate::{
12    error::Error,
13    loop_::{IsLoopRc, Loop},
14};
15
16use super::{ThreadLoop, ThreadLoopBox};
17
18#[derive(Debug)]
19struct ThreadLoopRcInner {
20    thread_loop: ThreadLoopBox,
21}
22
23#[derive(Debug, Clone)]
24pub struct ThreadLoopRc {
25    inner: Rc<ThreadLoopRcInner>,
26}
27
28impl ThreadLoopRc {
29    /// Initialize Pipewire and create a new [`ThreadLoopRc`] with the given `name` and optional properties.
30    ///
31    /// # Safety
32    /// TODO
33    pub unsafe fn new(
34        name: Option<&str>,
35        properties: Option<&spa::utils::dict::DictRef>,
36    ) -> Result<Self, Error> {
37        let thread_loop = ThreadLoopBox::new(name, properties)?;
38
39        Ok(Self::from_box(thread_loop))
40    }
41
42    /// Initialize Pipewire and create a new [`ThreadLoopRc`] with the given `name` as C string,
43    /// and optional properties.
44    ///
45    /// # Safety
46    /// TODO
47    pub unsafe fn new_cstr(
48        name: Option<&CStr>,
49        properties: Option<&spa::utils::dict::DictRef>,
50    ) -> Result<Self, Error> {
51        let thread_loop = ThreadLoopBox::new_cstr(name, properties)?;
52
53        Ok(Self::from_box(thread_loop))
54    }
55
56    /// Create a [`ThreadLoopRc`] using an existing [`ThreadLoopBox`].
57    ///
58    /// # Safety
59    /// TODO
60    pub unsafe fn from_box(thread_loop: ThreadLoopBox) -> Self {
61        Self {
62            inner: Rc::new(ThreadLoopRcInner { thread_loop }),
63        }
64    }
65
66    /// Create a new main loop from a raw [`pw_thread_loop`](`pw_sys::pw_thread_loop`), taking ownership of it.
67    ///
68    /// # Safety
69    /// The provided pointer must point to a valid, well aligned [`pw_thread_loop`](`pw_sys::pw_thread_loop`).
70    ///
71    /// The raw loop should not be manually destroyed or moved, as the new [`ThreadLoopRc`] takes ownership of it.
72    pub unsafe fn from_raw(ptr: ptr::NonNull<pw_sys::pw_thread_loop>) -> Self {
73        let thread_loop = ThreadLoopBox::from_raw(ptr);
74
75        Self {
76            inner: Rc::new(ThreadLoopRcInner { thread_loop }),
77        }
78    }
79
80    pub fn downgrade(&self) -> ThreadLoopWeak {
81        let weak = Rc::downgrade(&self.inner);
82        ThreadLoopWeak { weak }
83    }
84}
85
86// Safety: The pw_loop is guaranteed to remain valid while any clone of the `ThreadLoopRc` is held,
87//         because we use an internal Rc to keep the pw_thread_loop containing the pw_loop alive.
88unsafe impl IsLoopRc for ThreadLoopRc {}
89
90impl std::ops::Deref for ThreadLoopRc {
91    type Target = ThreadLoop;
92
93    fn deref(&self) -> &Self::Target {
94        self.inner.thread_loop.deref()
95    }
96}
97
98impl std::convert::AsRef<ThreadLoop> for ThreadLoopRc {
99    fn as_ref(&self) -> &ThreadLoop {
100        self.deref()
101    }
102}
103
104impl std::convert::AsRef<Loop> for ThreadLoopRc {
105    fn as_ref(&self) -> &Loop {
106        self.loop_()
107    }
108}
109
110pub struct ThreadLoopWeak {
111    weak: Weak<ThreadLoopRcInner>,
112}
113
114impl ThreadLoopWeak {
115    pub fn upgrade(&self) -> Option<ThreadLoopRc> {
116        self.weak.upgrade().map(|inner| ThreadLoopRc { inner })
117    }
118}