1 // Take a look at the license at the top of the repository in the LICENSE file. 2 3 use std::borrow::{Borrow, BorrowMut, ToOwned}; 4 use std::ffi::CStr; 5 use std::fmt; 6 use std::mem; 7 use std::ops::{Deref, DerefMut}; 8 use std::ptr; 9 use std::str; 10 11 use once_cell::sync::Lazy; 12 13 use glib::translate::*; 14 use glib::StaticType; 15 16 #[doc(alias = "GstCapsFeatures")] 17 pub struct CapsFeatures(ptr::NonNull<ffi::GstCapsFeatures>); 18 unsafe impl Send for CapsFeatures {} 19 unsafe impl Sync for CapsFeatures {} 20 21 impl CapsFeatures { new(features: &[&str]) -> Self22 pub fn new(features: &[&str]) -> Self { 23 assert_initialized_main_thread!(); 24 let mut f = Self::new_empty(); 25 26 for feature in features { 27 f.add(feature); 28 } 29 30 f 31 } 32 from_quarks(features: &[glib::Quark]) -> Self33 pub fn from_quarks(features: &[glib::Quark]) -> Self { 34 assert_initialized_main_thread!(); 35 let mut f = Self::new_empty(); 36 37 for feature in features { 38 f.add_from_quark(*feature); 39 } 40 41 f 42 } 43 44 #[doc(alias = "gst_caps_features_new_empty")] new_empty() -> Self45 pub fn new_empty() -> Self { 46 assert_initialized_main_thread!(); 47 unsafe { 48 CapsFeatures(ptr::NonNull::new_unchecked( 49 ffi::gst_caps_features_new_empty(), 50 )) 51 } 52 } 53 54 #[doc(alias = "gst_caps_features_new_any")] new_any() -> Self55 pub fn new_any() -> Self { 56 assert_initialized_main_thread!(); 57 unsafe { CapsFeatures(ptr::NonNull::new_unchecked(ffi::gst_caps_features_new_any())) } 58 } 59 into_ptr(self) -> *mut ffi::GstCapsFeatures60 pub unsafe fn into_ptr(self) -> *mut ffi::GstCapsFeatures { 61 let s = mem::ManuallyDrop::new(self); 62 s.0.as_ptr() 63 } 64 } 65 66 impl Deref for CapsFeatures { 67 type Target = CapsFeaturesRef; 68 deref(&self) -> &CapsFeaturesRef69 fn deref(&self) -> &CapsFeaturesRef { 70 unsafe { &*(self.0.as_ref() as *const ffi::GstCapsFeatures as *const CapsFeaturesRef) } 71 } 72 } 73 74 impl DerefMut for CapsFeatures { deref_mut(&mut self) -> &mut CapsFeaturesRef75 fn deref_mut(&mut self) -> &mut CapsFeaturesRef { 76 unsafe { &mut *(self.0.as_mut() as *mut ffi::GstCapsFeatures as *mut CapsFeaturesRef) } 77 } 78 } 79 80 impl AsRef<CapsFeaturesRef> for CapsFeatures { as_ref(&self) -> &CapsFeaturesRef81 fn as_ref(&self) -> &CapsFeaturesRef { 82 self.deref() 83 } 84 } 85 86 impl AsMut<CapsFeaturesRef> for CapsFeatures { as_mut(&mut self) -> &mut CapsFeaturesRef87 fn as_mut(&mut self) -> &mut CapsFeaturesRef { 88 self.deref_mut() 89 } 90 } 91 92 impl Clone for CapsFeatures { clone(&self) -> Self93 fn clone(&self) -> Self { 94 unsafe { 95 let ptr = ffi::gst_caps_features_copy(self.0.as_ref()); 96 assert!(!ptr.is_null()); 97 CapsFeatures(ptr::NonNull::new_unchecked(ptr)) 98 } 99 } 100 } 101 102 impl Drop for CapsFeatures { drop(&mut self)103 fn drop(&mut self) { 104 unsafe { ffi::gst_caps_features_free(self.0.as_mut()) } 105 } 106 } 107 108 impl fmt::Debug for CapsFeatures { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 110 f.debug_tuple("CapsFeatures") 111 .field(&self.to_string()) 112 .finish() 113 } 114 } 115 116 impl fmt::Display for CapsFeatures { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 118 // Need to make sure to not call ToString::to_string() here, which 119 // we have because of the Display impl. We need CapsFeaturesRef::to_string() 120 f.write_str(&CapsFeaturesRef::to_string(self.as_ref())) 121 } 122 } 123 124 impl str::FromStr for CapsFeatures { 125 type Err = glib::BoolError; 126 127 #[doc(alias = "gst_caps_features_from_string")] from_str(s: &str) -> Result<Self, Self::Err>128 fn from_str(s: &str) -> Result<Self, Self::Err> { 129 assert_initialized_main_thread!(); 130 unsafe { 131 let ptr = ffi::gst_caps_features_from_string(s.to_glib_none().0); 132 if ptr.is_null() { 133 return Err(glib::bool_error!( 134 "Failed to parse caps features from string" 135 )); 136 } 137 138 Ok(Self(ptr::NonNull::new_unchecked(ptr))) 139 } 140 } 141 } 142 143 impl Borrow<CapsFeaturesRef> for CapsFeatures { borrow(&self) -> &CapsFeaturesRef144 fn borrow(&self) -> &CapsFeaturesRef { 145 self.as_ref() 146 } 147 } 148 149 impl BorrowMut<CapsFeaturesRef> for CapsFeatures { borrow_mut(&mut self) -> &mut CapsFeaturesRef150 fn borrow_mut(&mut self) -> &mut CapsFeaturesRef { 151 self.as_mut() 152 } 153 } 154 155 impl glib::types::StaticType for CapsFeatures { static_type() -> glib::types::Type156 fn static_type() -> glib::types::Type { 157 unsafe { from_glib(ffi::gst_caps_features_get_type()) } 158 } 159 } 160 161 impl<'a> ToGlibPtr<'a, *const ffi::GstCapsFeatures> for CapsFeatures { 162 type Storage = &'a Self; 163 to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self>164 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self> { 165 unsafe { Stash(self.0.as_ref(), self) } 166 } 167 to_glib_full(&self) -> *const ffi::GstCapsFeatures168 fn to_glib_full(&self) -> *const ffi::GstCapsFeatures { 169 unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) } 170 } 171 } 172 173 impl<'a> ToGlibPtr<'a, *mut ffi::GstCapsFeatures> for CapsFeatures { 174 type Storage = &'a Self; 175 to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self>176 fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self> { 177 unsafe { 178 Stash( 179 self.0.as_ref() as *const ffi::GstCapsFeatures as *mut ffi::GstCapsFeatures, 180 self, 181 ) 182 } 183 } 184 to_glib_full(&self) -> *mut ffi::GstCapsFeatures185 fn to_glib_full(&self) -> *mut ffi::GstCapsFeatures { 186 unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) } 187 } 188 } 189 190 impl<'a> ToGlibPtrMut<'a, *mut ffi::GstCapsFeatures> for CapsFeatures { 191 type Storage = &'a mut Self; 192 to_glib_none_mut(&'a mut self) -> StashMut<*mut ffi::GstCapsFeatures, Self>193 fn to_glib_none_mut(&'a mut self) -> StashMut<*mut ffi::GstCapsFeatures, Self> { 194 unsafe { StashMut(self.0.as_mut(), self) } 195 } 196 } 197 198 impl FromGlibPtrNone<*const ffi::GstCapsFeatures> for CapsFeatures { from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self199 unsafe fn from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self { 200 assert!(!ptr.is_null()); 201 let ptr = ffi::gst_caps_features_copy(ptr); 202 assert!(!ptr.is_null()); 203 CapsFeatures(ptr::NonNull::new_unchecked(ptr)) 204 } 205 } 206 207 impl FromGlibPtrNone<*mut ffi::GstCapsFeatures> for CapsFeatures { from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self208 unsafe fn from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self { 209 assert!(!ptr.is_null()); 210 let ptr = ffi::gst_caps_features_copy(ptr); 211 assert!(!ptr.is_null()); 212 CapsFeatures(ptr::NonNull::new_unchecked(ptr)) 213 } 214 } 215 216 impl FromGlibPtrFull<*const ffi::GstCapsFeatures> for CapsFeatures { from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self217 unsafe fn from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self { 218 assert!(!ptr.is_null()); 219 CapsFeatures(ptr::NonNull::new_unchecked( 220 ptr as *mut ffi::GstCapsFeatures, 221 )) 222 } 223 } 224 225 impl FromGlibPtrFull<*mut ffi::GstCapsFeatures> for CapsFeatures { from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self226 unsafe fn from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self { 227 assert!(!ptr.is_null()); 228 CapsFeatures(ptr::NonNull::new_unchecked(ptr)) 229 } 230 } 231 232 impl glib::value::ValueType for CapsFeatures { 233 type Type = Self; 234 } 235 236 unsafe impl<'a> glib::value::FromValue<'a> for CapsFeatures { 237 type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>; 238 from_value(value: &'a glib::Value) -> Self239 unsafe fn from_value(value: &'a glib::Value) -> Self { 240 skip_assert_initialized!(); 241 from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) 242 as *mut ffi::GstCapsFeatures) 243 } 244 } 245 246 impl glib::value::ToValue for CapsFeatures { to_value(&self) -> glib::Value247 fn to_value(&self) -> glib::Value { 248 let mut value = glib::Value::for_value_type::<Self>(); 249 unsafe { 250 glib::gobject_ffi::g_value_set_boxed( 251 value.to_glib_none_mut().0, 252 ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(self).0 as *mut _, 253 ) 254 } 255 value 256 } 257 value_type(&self) -> glib::Type258 fn value_type(&self) -> glib::Type { 259 Self::static_type() 260 } 261 } 262 263 impl glib::value::ToValueOptional for CapsFeatures { to_value_optional(s: Option<&Self>) -> glib::Value264 fn to_value_optional(s: Option<&Self>) -> glib::Value { 265 skip_assert_initialized!(); 266 let mut value = glib::Value::for_value_type::<Self>(); 267 unsafe { 268 glib::gobject_ffi::g_value_set_boxed( 269 value.to_glib_none_mut().0, 270 ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(&s).0 as *mut _, 271 ) 272 } 273 value 274 } 275 } 276 277 impl GlibPtrDefault for CapsFeatures { 278 type GlibType = *mut ffi::GstCapsFeatures; 279 } 280 281 #[repr(transparent)] 282 #[doc(alias = "GstCapsFeatures")] 283 pub struct CapsFeaturesRef(ffi::GstCapsFeatures); 284 285 impl CapsFeaturesRef { from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef286 pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef { 287 assert!(!ptr.is_null()); 288 289 &*(ptr as *mut CapsFeaturesRef) 290 } 291 from_glib_borrow_mut<'a>( ptr: *mut ffi::GstCapsFeatures, ) -> &'a mut CapsFeaturesRef292 pub unsafe fn from_glib_borrow_mut<'a>( 293 ptr: *mut ffi::GstCapsFeatures, 294 ) -> &'a mut CapsFeaturesRef { 295 assert!(!ptr.is_null()); 296 297 &mut *(ptr as *mut CapsFeaturesRef) 298 } 299 as_ptr(&self) -> *const ffi::GstCapsFeatures300 pub unsafe fn as_ptr(&self) -> *const ffi::GstCapsFeatures { 301 self as *const Self as *const ffi::GstCapsFeatures 302 } 303 as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures304 pub unsafe fn as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures { 305 self as *const Self as *mut ffi::GstCapsFeatures 306 } 307 is_empty(&self) -> bool308 pub fn is_empty(&self) -> bool { 309 self.size() == 0 && !self.is_any() 310 } 311 312 #[doc(alias = "gst_caps_features_is_any")] is_any(&self) -> bool313 pub fn is_any(&self) -> bool { 314 unsafe { from_glib(ffi::gst_caps_features_is_any(self.as_ptr())) } 315 } 316 317 #[doc(alias = "gst_caps_features_contains")] contains(&self, feature: &str) -> bool318 pub fn contains(&self, feature: &str) -> bool { 319 unsafe { 320 from_glib(ffi::gst_caps_features_contains( 321 self.as_ptr(), 322 feature.to_glib_none().0, 323 )) 324 } 325 } 326 contains_quark(&self, feature: glib::Quark) -> bool327 pub fn contains_quark(&self, feature: glib::Quark) -> bool { 328 unsafe { 329 from_glib(ffi::gst_caps_features_contains_id( 330 self.as_ptr(), 331 feature.into_glib(), 332 )) 333 } 334 } 335 336 #[doc(alias = "get_size")] 337 #[doc(alias = "gst_caps_features_get_size")] size(&self) -> u32338 pub fn size(&self) -> u32 { 339 unsafe { ffi::gst_caps_features_get_size(self.as_ptr()) } 340 } 341 342 #[doc(alias = "get_nth")] 343 #[doc(alias = "gst_caps_features_get_nth")] nth(&self, idx: u32) -> Option<&str>344 pub fn nth(&self, idx: u32) -> Option<&str> { 345 if idx >= self.size() { 346 return None; 347 } 348 349 unsafe { 350 let feature = ffi::gst_caps_features_get_nth(self.as_ptr(), idx); 351 if feature.is_null() { 352 return None; 353 } 354 355 Some(CStr::from_ptr(feature).to_str().unwrap()) 356 } 357 } 358 nth_quark(&self, idx: u32) -> Option<glib::Quark>359 pub fn nth_quark(&self, idx: u32) -> Option<glib::Quark> { 360 if idx >= self.size() { 361 return None; 362 } 363 364 unsafe { 365 let feature = ffi::gst_caps_features_get_nth_id(self.as_ptr(), idx); 366 Some(from_glib(feature)) 367 } 368 } 369 370 #[doc(alias = "gst_caps_features_add")] add(&mut self, feature: &str)371 pub fn add(&mut self, feature: &str) { 372 unsafe { ffi::gst_caps_features_add(self.as_mut_ptr(), feature.to_glib_none().0) } 373 } 374 375 #[doc(alias = "gst_caps_features_remove")] remove(&mut self, feature: &str)376 pub fn remove(&mut self, feature: &str) { 377 unsafe { ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.to_glib_none().0) } 378 } 379 add_from_quark(&mut self, feature: glib::Quark)380 pub fn add_from_quark(&mut self, feature: glib::Quark) { 381 unsafe { ffi::gst_caps_features_add_id(self.as_mut_ptr(), feature.into_glib()) } 382 } 383 remove_by_quark(&mut self, feature: glib::Quark)384 pub fn remove_by_quark(&mut self, feature: glib::Quark) { 385 unsafe { ffi::gst_caps_features_remove_id(self.as_mut_ptr(), feature.into_glib()) } 386 } 387 iter(&self) -> Iter388 pub fn iter(&self) -> Iter { 389 Iter::new(self) 390 } 391 392 // This is not an equivalence relation with regards to ANY. Everything is equal to ANY 393 #[doc(alias = "gst_caps_features_is_equal")] is_equal(&self, other: &CapsFeaturesRef) -> bool394 pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool { 395 unsafe { 396 from_glib(ffi::gst_caps_features_is_equal( 397 self.as_ptr(), 398 other.as_ptr(), 399 )) 400 } 401 } 402 } 403 404 impl glib::types::StaticType for CapsFeaturesRef { static_type() -> glib::types::Type405 fn static_type() -> glib::types::Type { 406 unsafe { from_glib(ffi::gst_structure_get_type()) } 407 } 408 } 409 410 unsafe impl<'a> glib::value::FromValue<'a> for &'a CapsFeaturesRef { 411 type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>; 412 from_value(value: &'a glib::Value) -> Self413 unsafe fn from_value(value: &'a glib::Value) -> Self { 414 skip_assert_initialized!(); 415 &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const CapsFeaturesRef) 416 } 417 } 418 419 impl glib::value::ToValue for CapsFeaturesRef { to_value(&self) -> glib::Value420 fn to_value(&self) -> glib::Value { 421 let mut value = glib::Value::for_value_type::<CapsFeatures>(); 422 unsafe { 423 glib::gobject_ffi::g_value_set_boxed( 424 value.to_glib_none_mut().0, 425 self.as_mut_ptr() as *mut _, 426 ) 427 } 428 value 429 } 430 value_type(&self) -> glib::Type431 fn value_type(&self) -> glib::Type { 432 Self::static_type() 433 } 434 } 435 436 impl glib::value::ToValueOptional for CapsFeaturesRef { to_value_optional(s: Option<&Self>) -> glib::Value437 fn to_value_optional(s: Option<&Self>) -> glib::Value { 438 skip_assert_initialized!(); 439 let mut value = glib::Value::for_value_type::<CapsFeatures>(); 440 unsafe { 441 glib::gobject_ffi::g_value_set_boxed( 442 value.to_glib_none_mut().0, 443 s.map(|s| s.as_mut_ptr()).unwrap_or(ptr::null_mut()) as *mut _, 444 ) 445 } 446 value 447 } 448 } 449 450 #[derive(Debug)] 451 pub struct Iter<'a> { 452 caps_features: &'a CapsFeaturesRef, 453 idx: u32, 454 n_features: u32, 455 } 456 457 impl<'a> Iter<'a> { new(caps_features: &'a CapsFeaturesRef) -> Iter<'a>458 fn new(caps_features: &'a CapsFeaturesRef) -> Iter<'a> { 459 skip_assert_initialized!(); 460 let n_features = caps_features.size(); 461 462 Iter { 463 caps_features, 464 idx: 0, 465 n_features, 466 } 467 } 468 } 469 470 impl<'a> Iterator for Iter<'a> { 471 type Item = &'a str; 472 next(&mut self) -> Option<Self::Item>473 fn next(&mut self) -> Option<Self::Item> { 474 if self.idx >= self.n_features { 475 return None; 476 } 477 478 unsafe { 479 let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.idx); 480 if feature.is_null() { 481 return None; 482 } 483 484 self.idx += 1; 485 486 Some(CStr::from_ptr(feature).to_str().unwrap()) 487 } 488 } 489 size_hint(&self) -> (usize, Option<usize>)490 fn size_hint(&self) -> (usize, Option<usize>) { 491 if self.idx == self.n_features { 492 return (0, Some(0)); 493 } 494 495 let remaining = (self.n_features - self.idx) as usize; 496 497 (remaining, Some(remaining)) 498 } 499 } 500 501 impl<'a> DoubleEndedIterator for Iter<'a> { next_back(&mut self) -> Option<Self::Item>502 fn next_back(&mut self) -> Option<Self::Item> { 503 if self.idx == self.n_features { 504 return None; 505 } 506 507 self.n_features -= 1; 508 509 unsafe { 510 let feature = 511 ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.n_features); 512 if feature.is_null() { 513 return None; 514 } 515 516 Some(CStr::from_ptr(feature).to_str().unwrap()) 517 } 518 } 519 } 520 521 impl<'a> ExactSizeIterator for Iter<'a> {} 522 523 impl fmt::Debug for CapsFeaturesRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result524 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 525 f.debug_tuple("CapsFeatures") 526 .field(&self.to_string()) 527 .finish() 528 } 529 } 530 531 impl fmt::Display for CapsFeaturesRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result532 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 533 let s = unsafe { 534 glib::GString::from_glib_full(ffi::gst_caps_features_to_string(self.as_ptr())) 535 }; 536 f.write_str(&s) 537 } 538 } 539 540 impl ToOwned for CapsFeaturesRef { 541 type Owned = CapsFeatures; 542 to_owned(&self) -> CapsFeatures543 fn to_owned(&self) -> CapsFeatures { 544 unsafe { from_glib_full(ffi::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) } 545 } 546 } 547 548 unsafe impl Sync for CapsFeaturesRef {} 549 unsafe impl Send for CapsFeaturesRef {} 550 551 pub static CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: Lazy<&'static str> = Lazy::new(|| unsafe { 552 CStr::from_ptr(ffi::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) 553 .to_str() 554 .unwrap() 555 }); 556 pub static CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: Lazy<CapsFeatures> = 557 Lazy::new(|| CapsFeatures::new(&[*CAPS_FEATURE_MEMORY_SYSTEM_MEMORY])); 558 559 #[cfg(test)] 560 mod tests { 561 use super::*; 562 563 #[test] test_from_value_optional()564 fn test_from_value_optional() { 565 use glib::ToValue; 566 567 crate::init().unwrap(); 568 569 let a = None::<CapsFeatures>.to_value(); 570 assert!(a.get::<Option<CapsFeatures>>().unwrap().is_none()); 571 let b = glib::value::Value::from(&CapsFeatures::new_empty()); 572 assert!(b.get::<Option<CapsFeatures>>().unwrap().is_some()); 573 } 574 } 575