1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use crate::{prelude::*, spa::SpaIdTable};

glib::wrapper! {
	#[doc(alias = "WpSpaType")]
	#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
	pub struct SpaType(BoxedInline<ffi::WpSpaType>);

	match fn {
		type_ => || ffi::wp_spa_type_get_type(),
	}
}

impl SpaType {
	pub const ARRAY: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Array) };
	pub const BITMAP: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Bitmap) };
	pub const BOOL: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Bool) };
	pub const BYTES: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Bytes) };
	pub const CHOICE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Choice) };
	pub const DOUBLE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Double) };
	pub const FD: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Fd) };
	pub const FLOAT: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Float) };
	pub const FRACTION: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Fraction) };
	pub const ID: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Id) };
	pub const INT: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Int) };
	pub const LONG: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Long) };
	pub const NONE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_None) };
	pub const OBJECT: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Object) };
	pub const OBJECT_FORMAT: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_Format) };
	pub const OBJECT_PARAM_BUFFERS: Self =
		unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamBuffers) };
	pub const OBJECT_PARAM_IO: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamIO) };
	pub const OBJECT_PARAM_LATENCY: Self =
		unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamLatency) };
	pub const OBJECT_PARAM_META: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamMeta) };
	pub const OBJECT_PARAM_PORT_CONFIG: Self =
		unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamPortConfig) };
	pub const OBJECT_PARAM_PROCESS_LATENCY: Self =
		unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamProcessLatency) };
	pub const OBJECT_PARAM_PROFILE: Self =
		unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamProfile) };
	pub const OBJECT_PARAM_ROUTE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_ParamRoute) };
	pub const OBJECT_PROFILER: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_Profiler) };
	pub const OBJECT_PROP_INFO: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_PropInfo) };
	pub const OBJECT_PROPS: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_OBJECT_Props) };
	pub const POD: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Pod) };
	pub const POINTER: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Pointer) };
	pub const RECTANGLE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Rectangle) };
	pub const SEQUENCE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Sequence) };
	pub const STRING: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_String) };
	pub const STRUCT: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_Struct) };
	pub const POINTER_BUFFER: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_POINTER_Buffer) };
	pub const POINTER_DICT: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_POINTER_Dict) };
	pub const POINTER_META: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_POINTER_Meta) };
	pub const COMMAND_DEVICE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_COMMAND_Device) };
	pub const COMMAND_NODE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_COMMAND_Node) };
	pub const EVENT_DEVICE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_EVENT_Device) };
	pub const EVENT_NODE: Self = unsafe { SpaType::from_id_unchecked(libspa_sys::SPA_TYPE_EVENT_Node) };

	pub fn from_id(id: ffi::WpSpaType) -> Option<Self> {
		match id {
			ffi::WP_SPA_TYPE_INVALID => None,
			inner => Some(unsafe { Self::from_id_unchecked(inner) }),
		}
	}

	pub const unsafe fn from_id_unchecked(inner: ffi::WpSpaType) -> Self {
		Self { inner }
	}

	pub fn number(&self) -> ffi::WpSpaType {
		self.into_glib()
	}

	#[cfg(libspa_linked)]
	pub fn root_types() -> impl Iterator<Item = Self> {
		unsafe { libspa_sys::spa_types.iter().map(|ty| Self::from_id_unchecked(ty.type_)) }
	}

	#[doc(alias = "wp_spa_type_get_object_id_values_table")]
	#[doc(alias = "get_object_id_values_table")]
	pub fn object_id_values_table(&self) -> Option<SpaIdTable> {
		unsafe { from_glib(ffi::wp_spa_type_get_object_id_values_table(self.into_glib())) }
	}

	#[doc(alias = "wp_spa_type_get_values_table")]
	#[doc(alias = "get_values_table")]
	pub fn values_table(&self) -> Option<SpaIdTable> {
		unsafe { from_glib(ffi::wp_spa_type_get_values_table(self.into_glib())) }
	}

	#[doc(alias = "wp_spa_type_is_fundamental")]
	pub fn is_fundamental(&self) -> bool {
		unsafe { from_glib(ffi::wp_spa_type_is_fundamental(self.into_glib())) }
	}

	#[doc(alias = "wp_spa_type_is_id")]
	pub fn is_id(&self) -> bool {
		unsafe { from_glib(ffi::wp_spa_type_is_id(self.into_glib())) }
	}

	#[doc(alias = "wp_spa_type_is_object")]
	pub fn is_object(&self) -> bool {
		unsafe { from_glib(ffi::wp_spa_type_is_object(self.into_glib())) }
	}

	#[doc(alias = "wp_spa_type_name")]
	pub fn name(&self) -> Option<glib::GString> {
		unsafe { from_glib_none(ffi::wp_spa_type_name(self.into_glib())) }
	}

	#[doc(alias = "wp_spa_type_parent")]
	#[must_use]
	pub fn parent(&self) -> Option<SpaType> {
		unsafe { from_glib(ffi::wp_spa_type_parent(self.into_glib())) }
	}

	#[doc(alias = "wp_spa_type_from_name")]
	pub fn from_name(name: &str) -> Option<SpaType> {
		unsafe { from_glib(ffi::wp_spa_type_from_name(name.to_glib_none().0)) }
	}
}

impl TryFromGlib<ffi::WpSpaType> for SpaType {
	type Error = GlibNoneError;

	unsafe fn try_from_glib(val: ffi::WpSpaType) -> Result<Self, Self::Error> {
		Self::try_from(val)
	}
}

impl TryFrom<ffi::WpSpaType> for SpaType {
	type Error = GlibNoneError;

	fn try_from(value: ffi::WpSpaType) -> Result<Self, Self::Error> {
		Self::from_id(value).ok_or(GlibNoneError)
	}
}

impl IntoGlib for SpaType {
	type GlibType = ffi::WpSpaType;
	fn into_glib(self) -> Self::GlibType {
		self.inner
	}
}

impl fmt::Debug for SpaType {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		let mut f = f.debug_struct("SpaType");
		f.field("id", &self.into_glib());
		if let Some(name) = self.name() {
			f.field("name", &name);
		}
		f.finish()
	}
}

#[test]
#[cfg(libspa_linked)]
fn all_spa_types() {
	let types = SpaType::root_types();
	assert!(types.count() > 0);
}

#[test]
#[cfg(todo)]
fn dynamic_spa_types() {
	use crate::{Core, InitFlags};
	Core::init_with_flags(InitFlags::SPA_TYPES);
	todo!()
}