libspa/buffer/
mod.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4use std::{convert::TryFrom, fmt::Debug, os::fd::RawFd};
5
6#[derive(Copy, Clone, PartialEq, Eq)]
7pub struct DataType(spa_sys::spa_data_type);
8
9#[allow(non_upper_case_globals)]
10impl DataType {
11    pub const Invalid: Self = Self(spa_sys::SPA_DATA_Invalid);
12    /// Pointer to memory, the data field in struct [`Data`] is set.
13    pub const MemPtr: Self = Self(spa_sys::SPA_DATA_MemPtr);
14    /// Generic fd, `mmap` to get to memory
15    pub const MemFd: Self = Self(spa_sys::SPA_DATA_MemFd);
16    /// Fd to `dmabuf` memory
17    pub const DmaBuf: Self = Self(spa_sys::SPA_DATA_DmaBuf);
18    /// Memory is identified with an id
19    pub const MemId: Self = Self(spa_sys::SPA_DATA_MemId);
20
21    pub fn from_raw(raw: spa_sys::spa_data_type) -> Self {
22        Self(raw)
23    }
24
25    pub fn as_raw(&self) -> spa_sys::spa_data_type {
26        self.0
27    }
28}
29
30impl std::fmt::Debug for DataType {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        let name = format!(
33            "DataType::{}",
34            match *self {
35                Self::Invalid => "Invalid",
36                Self::MemPtr => "MemPtr",
37                Self::MemFd => "MemFd",
38                Self::DmaBuf => "DmaBuf",
39                Self::MemId => "MemId",
40                _ => "Unknown",
41            }
42        );
43        f.write_str(&name)
44    }
45}
46
47bitflags::bitflags! {
48    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
49    pub struct DataFlags: u32 {
50        /// Data is readable
51        const READABLE = 1<<0;
52        /// Data is writable
53        const WRITABLE = 1<<1;
54        /// Data pointer can be changed
55        const DYNAMIC = 1<<2;
56        const READWRITE = Self::READABLE.bits() | Self::WRITABLE.bits();
57    }
58}
59
60#[repr(transparent)]
61pub struct Data(spa_sys::spa_data);
62
63impl Data {
64    pub fn as_raw(&self) -> &spa_sys::spa_data {
65        &self.0
66    }
67
68    pub fn type_(&self) -> DataType {
69        DataType::from_raw(self.0.type_)
70    }
71
72    pub fn flags(&self) -> DataFlags {
73        DataFlags::from_bits_retain(self.0.flags)
74    }
75
76    pub fn fd(&self) -> RawFd {
77        // We don't have a reliable way of checking if the fd is invalid or uninitialized, so we just return it as a RawFd.
78        // The client side will need to use unsafe if they want to manipulate the file descriptor.
79        self.0.fd as RawFd
80    }
81
82    pub fn data(&mut self) -> Option<&mut [u8]> {
83        // FIXME: For safety, perhaps only return a non-mut slice when DataFlags::WRITABLE is not set?
84        if self.0.data.is_null() {
85            None
86        } else {
87            unsafe {
88                Some(std::slice::from_raw_parts_mut(
89                    self.0.data as *mut u8,
90                    usize::try_from(self.0.maxsize).unwrap(),
91                ))
92            }
93        }
94    }
95
96    pub fn chunk(&self) -> &Chunk {
97        assert_ne!(self.0.chunk, std::ptr::null_mut());
98        unsafe {
99            let chunk: *const spa_sys::spa_chunk = self.0.chunk;
100            &*(chunk as *const Chunk)
101        }
102    }
103
104    pub fn chunk_mut(&mut self) -> &mut Chunk {
105        assert_ne!(self.0.chunk, std::ptr::null_mut());
106        unsafe {
107            let chunk: *mut spa_sys::spa_chunk = self.0.chunk;
108            &mut *(chunk as *mut Chunk)
109        }
110    }
111}
112
113impl Debug for Data {
114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115        f.debug_struct("Data")
116            .field("type", &self.type_())
117            .field("flags", &self.flags())
118            .field("fd", &self.fd())
119            .field("data", &self.0.data) // Only print the pointer here, as we don't want to print a (potentially very big) slice.
120            .field("chunk", &self.chunk())
121            .finish()
122    }
123}
124
125bitflags::bitflags! {
126    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
127    pub struct ChunkFlags: i32 {
128        /// Chunk data is corrupted in some way
129        const CORRUPTED = 1<<0;
130    }
131}
132
133#[repr(transparent)]
134pub struct Chunk(spa_sys::spa_chunk);
135
136impl Chunk {
137    pub fn as_raw(&self) -> &spa_sys::spa_chunk {
138        &self.0
139    }
140
141    pub fn size(&self) -> u32 {
142        self.0.size
143    }
144
145    pub fn size_mut(&mut self) -> &mut u32 {
146        &mut self.0.size
147    }
148
149    pub fn offset(&self) -> u32 {
150        self.0.offset
151    }
152
153    pub fn offset_mut(&mut self) -> &mut u32 {
154        &mut self.0.offset
155    }
156
157    pub fn stride(&self) -> i32 {
158        self.0.stride
159    }
160
161    pub fn stride_mut(&mut self) -> &mut i32 {
162        &mut self.0.stride
163    }
164
165    pub fn flags(&self) -> ChunkFlags {
166        ChunkFlags::from_bits_retain(self.0.flags)
167    }
168}
169
170impl Debug for Chunk {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        f.debug_struct("Chunk")
173            .field("offset", &self.offset())
174            .field("size", &self.size())
175            .field("stride", &self.stride())
176            .field("flags", &self.flags())
177            .finish()
178    }
179}