1pub mod dict;
4mod direction;
5pub use direction::*;
6pub mod hook;
7pub mod list;
8pub mod result;
9
10use bitflags::bitflags;
11use std::{
12 ffi::CStr,
13 fmt::{self, Debug, Formatter, Write},
14 os::raw::c_uint,
15};
16
17pub(crate) fn fmt_pascal_case(f: &mut Formatter<'_>, s: &str) -> fmt::Result {
18 for part in s.split(|c: char| c == ':' || c.is_whitespace()) {
19 if part.is_empty() {
20 continue;
21 }
22
23 let mut chars = part.chars();
24 if let Some(first) = chars.next() {
25 f.write_char(first.to_ascii_uppercase())?;
26 f.write_str(chars.as_str())?;
27 }
28 }
29
30 Ok(())
31}
32
33pub use spa_sys::spa_fraction as Fraction;
34pub use spa_sys::spa_point as Point;
35pub use spa_sys::spa_rectangle as Rectangle;
36pub use spa_sys::spa_region as Region;
37
38use crate::pod::CanonicalFixedSizedPod;
39
40#[derive(Debug, Copy, Clone, Eq, PartialEq)]
42pub struct Id(pub u32);
43
44#[derive(Debug, Copy, Clone, Eq, PartialEq)]
46#[repr(transparent)]
47pub struct Fd(pub i64);
48
49#[derive(Debug, Eq, PartialEq, Clone)]
50pub struct Choice<T: CanonicalFixedSizedPod>(pub ChoiceFlags, pub ChoiceEnum<T>);
52
53bitflags! {
54 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
56 pub struct ChoiceFlags: u32 {
57 #[doc(hidden)]
59 const _FAKE = 1;
60 }
61}
62
63#[derive(Debug, PartialEq, Eq, Clone)]
64pub enum ChoiceEnum<T: CanonicalFixedSizedPod> {
66 None(T),
68 Range {
70 default: T,
72 min: T,
74 max: T,
76 },
77 Step {
79 default: T,
81 min: T,
83 max: T,
85 step: T,
87 },
88 Enum {
90 default: T,
92 alternatives: Vec<T>,
94 },
95 Flags {
97 default: T,
99 flags: Vec<T>,
101 },
102}
103
104#[derive(Copy, Clone, PartialEq, Eq)]
105pub struct SpaTypes(pub c_uint);
106
107#[allow(non_upper_case_globals)]
108impl SpaTypes {
109 pub const None: Self = Self(spa_sys::SPA_TYPE_None);
111 pub const Bool: Self = Self(spa_sys::SPA_TYPE_Bool);
112 pub const Id: Self = Self(spa_sys::SPA_TYPE_Id);
113 pub const Int: Self = Self(spa_sys::SPA_TYPE_Int);
114 pub const Long: Self = Self(spa_sys::SPA_TYPE_Long);
115 pub const Float: Self = Self(spa_sys::SPA_TYPE_Float);
116 pub const Double: Self = Self(spa_sys::SPA_TYPE_Double);
117 pub const String: Self = Self(spa_sys::SPA_TYPE_String);
118 pub const Bytes: Self = Self(spa_sys::SPA_TYPE_Bytes);
119 pub const Rectangle: Self = Self(spa_sys::SPA_TYPE_Rectangle);
120 pub const Fraction: Self = Self(spa_sys::SPA_TYPE_Fraction);
121 pub const Bitmap: Self = Self(spa_sys::SPA_TYPE_Bitmap);
122 pub const Array: Self = Self(spa_sys::SPA_TYPE_Array);
123 pub const Struct: Self = Self(spa_sys::SPA_TYPE_Struct);
124 pub const Object: Self = Self(spa_sys::SPA_TYPE_Object);
125 pub const Sequence: Self = Self(spa_sys::SPA_TYPE_Sequence);
126 pub const Pointer: Self = Self(spa_sys::SPA_TYPE_Pointer);
127 pub const Fd: Self = Self(spa_sys::SPA_TYPE_Fd);
128 pub const Choice: Self = Self(spa_sys::SPA_TYPE_Choice);
129 pub const Pod: Self = Self(spa_sys::SPA_TYPE_Pod);
130
131 pub const PointerBuffer: Self = Self(spa_sys::SPA_TYPE_POINTER_Buffer);
133 pub const PointerMeta: Self = Self(spa_sys::SPA_TYPE_POINTER_Meta);
134 pub const PointerDict: Self = Self(spa_sys::SPA_TYPE_POINTER_Dict);
135
136 pub const EventDevice: Self = Self(spa_sys::SPA_TYPE_EVENT_Device);
138 pub const EventNode: Self = Self(spa_sys::SPA_TYPE_EVENT_Node);
139
140 pub const CommandDevice: Self = Self(spa_sys::SPA_TYPE_COMMAND_Device);
142 pub const CommandNode: Self = Self(spa_sys::SPA_TYPE_COMMAND_Node);
143
144 pub const ObjectParamPropInfo: Self = Self(spa_sys::SPA_TYPE_OBJECT_PropInfo);
146 pub const ObjectParamProps: Self = Self(spa_sys::SPA_TYPE_OBJECT_Props);
147 pub const ObjectParamFormat: Self = Self(spa_sys::SPA_TYPE_OBJECT_Format);
148 pub const ObjectParamBuffers: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamBuffers);
149 pub const ObjectParamMeta: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamMeta);
150 pub const ObjectParamIO: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamIO);
151 pub const ObjectParamProfile: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamProfile);
152 pub const ObjectParamPortConfig: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamPortConfig);
153 pub const ObjectParamRoute: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamRoute);
154 pub const ObjectProfiler: Self = Self(spa_sys::SPA_TYPE_OBJECT_Profiler);
155 pub const ObjectParamLatency: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamLatency);
156 pub const ObjectParamProcessLatency: Self = Self(spa_sys::SPA_TYPE_OBJECT_ParamProcessLatency);
157
158 pub const VendorPipeWire: Self = Self(spa_sys::SPA_TYPE_VENDOR_PipeWire);
160
161 pub const VendorOther: Self = Self(spa_sys::SPA_TYPE_VENDOR_Other);
162
163 pub fn from_raw(raw: c_uint) -> Self {
165 Self(raw)
166 }
167
168 pub fn as_raw(&self) -> c_uint {
170 self.0
171 }
172}
173
174impl Debug for SpaTypes {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match *self {
177 SpaTypes::VendorPipeWire => f.write_str("SpaTypes::VendorPipeWire"),
178 SpaTypes::VendorOther => f.write_str("SpaTypes::VendorOther"),
179 _ => {
180 let c_str = unsafe {
181 let c_buf =
182 spa_sys::spa_debug_type_find_name(spa_sys::spa_types, self.as_raw());
183 if c_buf.is_null() {
184 return f.write_str("Unknown");
185 }
186 CStr::from_ptr(c_buf)
187 };
188 let replaced = c_str
189 .to_string_lossy()
190 .replace("Spa:Pointer", "Pointer")
191 .replace("Spa:Pod:Object:Event", "Event")
192 .replace("Spa:Pod:Object:Command", "Command")
193 .replace("Spa:Pod:Object", "Object")
194 .replace("Spa:Pod:", "")
195 .replace("Spa:", "")
196 .replace(':', " ");
197 f.write_str("SpaTypes::")?;
198 fmt_pascal_case(f, &replaced)
199 }
200 }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn test_fmt_pascal_case() {
210 fn format_pascal(s: &str) -> String {
211 struct PascalCase<'a>(&'a str);
212 impl<'a> std::fmt::Display for PascalCase<'a> {
213 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
214 fmt_pascal_case(f, self.0)
215 }
216 }
217 format!("{}", PascalCase(s))
218 }
219
220 assert_eq!(format_pascal("hello"), "Hello");
221 assert_eq!(format_pascal("hello:world"), "HelloWorld");
222 assert_eq!(format_pascal("hello world"), "HelloWorld");
223 assert_eq!(format_pascal("hello:world test"), "HelloWorldTest");
224 assert_eq!(format_pascal("Hello:World"), "HelloWorld");
225 assert_eq!(format_pascal("hello::world test"), "HelloWorldTest");
226 assert_eq!(format_pascal(":hello world: "), "HelloWorld");
227 assert_eq!(format_pascal("a:b c"), "ABC");
228 assert_eq!(format_pascal("foo:bar:baz"), "FooBarBaz");
229 assert_eq!(format_pascal("fOo:bAr"), "FOoBAr");
230 assert_eq!(
231 format_pascal("Spa:Pod:Object:Param:Format"),
232 "SpaPodObjectParamFormat"
233 );
234 assert_eq!(format_pascal(""), "");
235 assert_eq!(format_pascal("::: "), "");
236 }
237
238 #[test]
239 #[cfg_attr(miri, ignore)]
240 fn debug_format() {
241 assert_eq!("SpaTypes::None", format!("{:?}", SpaTypes::None));
242 assert_eq!(
243 "SpaTypes::PointerBuffer",
244 format!("{:?}", SpaTypes::PointerBuffer)
245 );
246 assert_eq!(
247 "SpaTypes::EventDevice",
248 format!("{:?}", SpaTypes::EventDevice)
249 );
250 assert_eq!(
251 "SpaTypes::CommandDevice",
252 format!("{:?}", SpaTypes::CommandDevice)
253 );
254 assert_eq!(
255 "SpaTypes::ObjectParamPropInfo",
256 format!("{:?}", SpaTypes::ObjectParamPropInfo)
257 );
258 assert_eq!(
259 "SpaTypes::ObjectProfiler",
260 format!("{:?}", SpaTypes::ObjectProfiler)
261 );
262 assert_eq!(
263 "SpaTypes::ObjectParamProcessLatency",
264 format!("{:?}", SpaTypes::ObjectParamProcessLatency)
265 );
266 assert_eq!(
267 "SpaTypes::VendorPipeWire",
268 format!("{:?}", SpaTypes::VendorPipeWire)
269 );
270 assert_eq!(
271 "SpaTypes::VendorOther",
272 format!("{:?}", SpaTypes::VendorOther)
273 );
274 }
275}