pipewire/loop_/rc.rs
1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4use std::{
5 ops::Deref,
6 ptr,
7 rc::{Rc, Weak},
8};
9
10use super::{Loop, LoopBox};
11use crate::Error;
12
13/// Trait implemented by objects that implement a `pw_loop` and are reference counted in some way.
14///
15/// # Safety
16///
17/// The [`Loop`] returned by the implementation of `AsRef<Loop>` must remain valid as long as any clone
18/// of the trait implementor is still alive.
19pub unsafe trait IsLoopRc: Clone + AsRef<Loop> + 'static {}
20
21#[derive(Debug)]
22struct LoopRcInner {
23 loop_: LoopBox,
24}
25
26/// Reference counting smart pointer providing shared ownership of a PipeWire [loop](super).
27///
28/// For the non-owning variant, see [`LoopWeak`].
29/// For unique ownership, see [`LoopBox`].
30///
31/// For an explanation of these, see [Smart pointers to PipeWire objects](crate#smart-pointers-to-pipewire-objects).
32#[derive(Clone, Debug)]
33pub struct LoopRc {
34 inner: Rc<LoopRcInner>,
35}
36
37impl LoopRc {
38 /// Create a new [`LoopRc`].
39 pub fn new(properties: Option<&spa::utils::dict::DictRef>) -> Result<Self, Error> {
40 let loop_ = LoopBox::new(properties)?;
41
42 Ok(Self {
43 inner: Rc::new(LoopRcInner { loop_ }),
44 })
45 }
46
47 /// Create a new [`LoopRc`] from a raw [`pw_loop`](`pw_sys::pw_loop`), taking ownership of it.
48 ///
49 /// # Safety
50 /// The provided pointer must point to a valid, well aligned [`pw_loop`](`pw_sys::pw_loop`).
51 ///
52 /// The raw loop should not be manually destroyed or moved, as the new [`LoopRc`] takes ownership of it.
53 pub unsafe fn from_raw(ptr: ptr::NonNull<pw_sys::pw_loop>) -> Self {
54 let loop_ = LoopBox::from_raw(ptr);
55
56 Self {
57 inner: Rc::new(LoopRcInner { loop_ }),
58 }
59 }
60
61 pub fn downgrade(&self) -> LoopWeak {
62 let weak = Rc::downgrade(&self.inner);
63 LoopWeak { weak }
64 }
65}
66
67// Safety: The inner pw_loop is guaranteed to remain valid while any clone of the `LoopRc` is held,
68// because we use an internal Rc to keep it alive.
69unsafe impl IsLoopRc for LoopRc {}
70
71impl Deref for LoopRc {
72 type Target = Loop;
73
74 fn deref(&self) -> &Self::Target {
75 self.inner.loop_.deref()
76 }
77}
78
79impl std::convert::AsRef<Loop> for LoopRc {
80 fn as_ref(&self) -> &Loop {
81 self.deref()
82 }
83}
84
85/// Non-owning reference to a [loop](super) managed by [`LoopRc`].
86///
87/// The loop can be accessed by calling [`upgrade`](Self::upgrade).
88pub struct LoopWeak {
89 weak: Weak<LoopRcInner>,
90}
91
92impl LoopWeak {
93 pub fn upgrade(&self) -> Option<LoopRc> {
94 self.weak.upgrade().map(|inner| LoopRc { inner })
95 }
96}