pipewire/thread_loop/
box_.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4use std::{
5    ffi::{CStr, CString},
6    ops::Deref,
7    ptr,
8};
9
10use crate::Error;
11
12use super::ThreadLoop;
13
14#[derive(Debug)]
15pub struct ThreadLoopBox {
16    ptr: ptr::NonNull<pw_sys::pw_thread_loop>,
17}
18
19impl ThreadLoopBox {
20    /// Initialize Pipewire and create a new [`ThreadLoopBox`] with the given `name` and optional properties.
21    ///
22    /// # Safety
23    /// TODO
24    pub unsafe fn new(
25        name: Option<&str>,
26        properties: Option<&spa::utils::dict::DictRef>,
27    ) -> Result<Self, Error> {
28        let name = name.map(|name| CString::new(name).unwrap());
29
30        ThreadLoopBox::new_cstr(name.as_deref(), properties)
31    }
32
33    /// Initialize Pipewire and create a new [`ThreadLoopBox`] with the given `name` as a C string,
34    /// and optional properties.
35    ///
36    /// # Safety
37    /// TODO
38    pub unsafe fn new_cstr(
39        name: Option<&CStr>,
40        properties: Option<&spa::utils::dict::DictRef>,
41    ) -> Result<Self, Error> {
42        crate::init();
43
44        unsafe {
45            let props = properties.map_or(ptr::null(), |props| props.as_raw_ptr());
46            let name = name.map_or(ptr::null(), |p| p.as_ptr() as *const _);
47
48            let raw = pw_sys::pw_thread_loop_new(name, props);
49            let ptr = ptr::NonNull::new(raw).ok_or(Error::CreationFailed)?;
50
51            Ok(Self::from_raw(ptr))
52        }
53    }
54
55    /// Create a new thread loop from a raw [`pw_thread_loop`](`pw_sys::pw_thread_loop`), taking ownership of it.
56    ///
57    /// # Safety
58    /// The provided pointer must point to a valid, well aligned [`pw_thread_loop`](`pw_sys::pw_thread_loop`).
59    ///
60    /// The raw loop should not be manually destroyed or moved, as the new [`ThreadLoopBox`] takes ownership of it.
61    pub unsafe fn from_raw(ptr: ptr::NonNull<pw_sys::pw_thread_loop>) -> Self {
62        Self { ptr }
63    }
64
65    pub fn into_raw(self) -> std::ptr::NonNull<pw_sys::pw_thread_loop> {
66        // Use ManuallyDrop to give up ownership of the managed struct and not run the destructor.
67        std::mem::ManuallyDrop::new(self).ptr
68    }
69}
70
71impl std::ops::Deref for ThreadLoopBox {
72    type Target = ThreadLoop;
73
74    fn deref(&self) -> &Self::Target {
75        unsafe { self.ptr.cast::<ThreadLoop>().as_ref() }
76    }
77}
78
79impl AsRef<ThreadLoop> for ThreadLoopBox {
80    fn as_ref(&self) -> &ThreadLoop {
81        self.deref()
82    }
83}
84
85impl std::ops::Drop for ThreadLoopBox {
86    fn drop(&mut self) {
87        unsafe {
88            pw_sys::pw_thread_loop_destroy(self.as_raw_ptr());
89        }
90    }
91}