1use std::ops::{Deref, DerefMut};
2
3use gst::{prelude::*, IdStr};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct ElementProperties(pub(crate) gst::Structure);
34
35impl Default for ElementProperties {
36 fn default() -> Self {
37 Self::builder_general().build()
38 }
39}
40
41impl Deref for ElementProperties {
42 type Target = gst::StructureRef;
43
44 #[inline]
45 fn deref(&self) -> &Self::Target {
46 self.0.as_ref()
47 }
48}
49
50impl From<ElementProperties> for gst::Structure {
51 #[inline]
52 fn from(e: ElementProperties) -> Self {
53 skip_assert_initialized!();
54
55 e.into_inner()
56 }
57}
58
59impl ElementProperties {
60 pub fn builder_general() -> ElementPropertiesGeneralBuilder {
66 assert_initialized_main_thread!();
67
68 ElementPropertiesGeneralBuilder {
69 structure: gst::Structure::new_empty("element-properties"),
70 }
71 }
72
73 pub fn builder_map() -> ElementPropertiesMapBuilder {
82 assert_initialized_main_thread!();
83
84 ElementPropertiesMapBuilder { map: Vec::new() }
85 }
86
87 pub fn is_general(&self) -> bool {
90 let structure_name = self.0.name();
91
92 if structure_name != "element-properties" {
93 debug_assert_eq!(structure_name, "element-properties-map");
94 return false;
95 }
96
97 true
98 }
99
100 pub fn is_map(&self) -> bool {
103 !self.is_general()
104 }
105
106 pub fn map(&self) -> Option<Vec<ElementPropertiesMapItem>> {
110 if !self.is_map() {
111 return None;
112 }
113
114 Some(
115 self.0
116 .get::<gst::List>("map")
117 .unwrap()
118 .as_slice()
119 .iter()
120 .map(|props_map| {
121 ElementPropertiesMapItem(props_map.get::<gst::Structure>().unwrap())
122 })
123 .collect::<Vec<_>>(),
124 )
125 }
126
127 #[inline]
128 pub fn into_inner(self) -> gst::Structure {
129 self.0
130 }
131}
132
133#[must_use = "The builder must be built to be used"]
134#[derive(Debug, Clone)]
135pub struct ElementPropertiesGeneralBuilder {
136 structure: gst::Structure,
137}
138
139impl ElementPropertiesGeneralBuilder {
140 pub fn field(
145 mut self,
146 property_name: impl glib::IntoGStr,
147 value: impl Into<glib::Value> + Send,
148 ) -> Self {
149 self.structure.set(property_name, value);
150 self
151 }
152
153 pub fn field_with_static(
158 mut self,
159 property_name: impl AsRef<glib::GStr> + 'static,
160 value: impl Into<glib::Value> + Send,
161 ) -> Self {
162 self.structure.set_with_static(property_name, value);
163 self
164 }
165
166 pub fn field_with_id(
171 mut self,
172 property_name: impl AsRef<IdStr>,
173 value: impl Into<glib::Value> + Send,
174 ) -> Self {
175 self.structure.set_with_id(property_name, value);
176 self
177 }
178
179 gst::impl_builder_gvalue_extra_setters!(field);
180
181 pub fn field_value(mut self, property_name: &str, value: glib::SendValue) -> Self {
182 self.structure.set_value(property_name, value);
183 self
184 }
185
186 pub fn field_value_with_static(
187 mut self,
188 property_name: impl AsRef<glib::GStr> + 'static,
189 value: glib::SendValue,
190 ) -> Self {
191 self.structure.set_value_with_static(property_name, value);
192 self
193 }
194
195 pub fn field_value_with_id(
196 mut self,
197 property_name: impl AsRef<IdStr>,
198 value: glib::SendValue,
199 ) -> Self {
200 self.structure.set_value_with_id(property_name, value);
201 self
202 }
203
204 pub fn field_value_if_some(self, property_name: &str, value: Option<glib::SendValue>) -> Self {
205 if let Some(value) = value {
206 self.field_value(property_name, value)
207 } else {
208 self
209 }
210 }
211
212 pub fn field_value_with_static_if_some(
213 self,
214 property_name: impl AsRef<glib::GStr> + 'static,
215 value: Option<glib::SendValue>,
216 ) -> Self {
217 if let Some(value) = value {
218 self.field_value_with_static(property_name, value)
219 } else {
220 self
221 }
222 }
223
224 pub fn field_value_with_id_if_some(
225 self,
226 property_name: impl AsRef<IdStr>,
227 value: Option<glib::SendValue>,
228 ) -> Self {
229 if let Some(value) = value {
230 self.field_value_with_id(property_name, value)
231 } else {
232 self
233 }
234 }
235
236 pub fn build(self) -> ElementProperties {
237 ElementProperties(self.structure)
238 }
239}
240
241#[must_use = "The builder must be built to be used"]
242#[derive(Debug, Clone)]
243pub struct ElementPropertiesMapBuilder {
244 map: Vec<glib::SendValue>,
245}
246
247impl ElementPropertiesMapBuilder {
248 pub fn item(mut self, item: ElementPropertiesMapItem) -> Self {
249 self.map.push(item.into_inner().to_send_value());
250 self
251 }
252
253 pub fn item_if(self, item: ElementPropertiesMapItem, predicate: bool) -> Self {
254 if predicate {
255 self.item(item)
256 } else {
257 self
258 }
259 }
260
261 pub fn item_if_some(self, item: Option<ElementPropertiesMapItem>) -> Self {
262 if let Some(item) = item {
263 self.item(item)
264 } else {
265 self
266 }
267 }
268
269 pub fn build(self) -> ElementProperties {
270 ElementProperties(
271 gst::Structure::builder("element-properties-map")
272 .field("map", gst::List::new(self.map))
273 .build(),
274 )
275 }
276}
277
278#[derive(Debug, Clone, PartialEq, Eq)]
297pub struct ElementPropertiesMapItem(gst::Structure);
298
299impl Deref for ElementPropertiesMapItem {
300 type Target = gst::StructureRef;
301
302 #[inline]
303 fn deref(&self) -> &Self::Target {
304 self.0.as_ref()
305 }
306}
307
308impl DerefMut for ElementPropertiesMapItem {
309 #[inline]
310 fn deref_mut(&mut self) -> &mut Self::Target {
311 self.0.deref_mut()
312 }
313}
314
315impl From<ElementPropertiesMapItem> for gst::Structure {
316 #[inline]
317 fn from(e: ElementPropertiesMapItem) -> Self {
318 skip_assert_initialized!();
319
320 e.into_inner()
321 }
322}
323
324impl ElementPropertiesMapItem {
325 pub fn builder(factory_name: &str) -> ElementPropertiesMapItemBuilder {
326 assert_initialized_main_thread!();
327
328 ElementPropertiesMapItemBuilder {
329 structure: gst::Structure::new_empty(factory_name),
330 }
331 }
332
333 #[inline]
334 pub fn into_inner(self) -> gst::Structure {
335 self.0
336 }
337}
338
339#[must_use = "The builder must be built to be used"]
340#[derive(Debug, Clone)]
341pub struct ElementPropertiesMapItemBuilder {
342 structure: gst::Structure,
343}
344
345impl ElementPropertiesMapItemBuilder {
346 pub fn field(
351 mut self,
352 property_name: impl glib::IntoGStr,
353 value: impl Into<glib::Value> + Send,
354 ) -> Self {
355 self.structure.set(property_name, value);
356 self
357 }
358
359 pub fn field_with_static(
364 mut self,
365 property_name: impl AsRef<glib::GStr> + 'static,
366 value: impl Into<glib::Value> + Send,
367 ) -> Self {
368 self.structure.set_with_static(property_name, value);
369 self
370 }
371
372 pub fn field_with_id(
377 mut self,
378 property_name: impl AsRef<IdStr>,
379 value: impl Into<glib::Value> + Send,
380 ) -> Self {
381 self.structure.set_with_id(property_name, value);
382 self
383 }
384
385 gst::impl_builder_gvalue_extra_setters!(field);
386
387 pub fn field_value(mut self, property_name: &str, value: glib::SendValue) -> Self {
388 self.structure.set_value(property_name, value);
389 self
390 }
391
392 pub fn field_value_with_static(
393 mut self,
394 property_name: impl AsRef<glib::GStr> + 'static,
395 value: glib::SendValue,
396 ) -> Self {
397 self.structure.set_value_with_static(property_name, value);
398 self
399 }
400
401 pub fn field_value_with_id(
402 mut self,
403 property_name: impl AsRef<IdStr>,
404 value: glib::SendValue,
405 ) -> Self {
406 self.structure.set_value_with_id(property_name, value);
407 self
408 }
409
410 pub fn field_value_if_some(self, property_name: &str, value: Option<glib::SendValue>) -> Self {
411 if let Some(value) = value {
412 self.field_value(property_name, value)
413 } else {
414 self
415 }
416 }
417
418 pub fn field_value_with_static_if_some(
419 self,
420 property_name: impl AsRef<glib::GStr> + 'static,
421 value: Option<glib::SendValue>,
422 ) -> Self {
423 if let Some(value) = value {
424 self.field_value_with_static(property_name, value)
425 } else {
426 self
427 }
428 }
429
430 pub fn field_value_with_id_if_some(
431 self,
432 property_name: impl AsRef<IdStr>,
433 value: Option<glib::SendValue>,
434 ) -> Self {
435 if let Some(value) = value {
436 self.field_value_with_id(property_name, value)
437 } else {
438 self
439 }
440 }
441
442 pub fn build(self) -> ElementPropertiesMapItem {
443 ElementPropertiesMapItem(self.structure)
444 }
445}
446
447#[cfg(test)]
448mod test {
449 use super::*;
450 use gst::idstr;
451
452 #[test]
453 fn element_properties_getters() {
454 gst::init().unwrap();
455
456 let elem_props_general = ElementProperties::builder_general()
457 .field("string-prop", "hi")
458 .field("boolean-prop", true)
459 .build();
460 assert!(elem_props_general.is_general());
461 assert!(!elem_props_general.is_map());
462 assert_eq!(elem_props_general.map(), None);
463
464 let elem_factory_props_map = ElementPropertiesMapItem::builder("vp8enc")
465 .field_with_id(idstr!("cq-level"), 13)
466 .field("resize-allowed", false)
467 .build();
468 let elem_props_map = ElementProperties::builder_map()
469 .item(elem_factory_props_map.clone())
470 .build();
471 assert!(elem_props_map.is_map());
472 assert!(!elem_props_map.is_general());
473 assert_eq!(elem_props_map.map(), Some(vec![elem_factory_props_map]));
474 }
475
476 #[test]
477 fn element_properties_general_builder() {
478 gst::init().unwrap();
479
480 let elem_props = ElementProperties::builder_general()
481 .field("string-prop", "hi")
482 .field("boolean-prop", true)
483 .build();
484 assert_eq!(elem_props.n_fields(), 2);
485 assert_eq!(elem_props.name(), "element-properties");
486 assert_eq!(elem_props.get::<String>("string-prop").unwrap(), "hi");
487 assert!(elem_props.get::<bool>("boolean-prop").unwrap());
488 }
489
490 #[test]
491 fn element_properties_map_builder() {
492 gst::init().unwrap();
493
494 let props_map = ElementPropertiesMapItem::builder("vp8enc")
495 .field("cq-level", 13)
496 .field("resize-allowed", false)
497 .build();
498 assert_eq!(props_map.n_fields(), 2);
499 assert_eq!(props_map.name(), "vp8enc");
500 assert_eq!(props_map.get::<i32>("cq-level").unwrap(), 13);
501 assert!(!props_map.get::<bool>("resize-allowed").unwrap());
502
503 let elem_props = ElementProperties::builder_map()
504 .item(props_map.clone())
505 .build();
506 assert_eq!(elem_props.n_fields(), 1);
507
508 let list = elem_props.map().unwrap();
509 assert_eq!(list.len(), 1);
510 assert_eq!(list.first().unwrap(), &props_map);
511 }
512}