1 // Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com> 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 use std::borrow::{Borrow, BorrowMut, ToOwned}; 10 use std::ffi::CStr; 11 use std::fmt; 12 use std::marker::PhantomData; 13 use std::mem; 14 use std::ops::{Deref, DerefMut}; 15 use std::ptr; 16 use std::str; 17 18 use glib; 19 use glib::translate::{ 20 from_glib, from_glib_full, FromGlibPtrFull, FromGlibPtrNone, GlibPtrDefault, Stash, StashMut, 21 ToGlibPtr, ToGlibPtrMut, 22 }; 23 use glib_sys::gpointer; 24 use gobject_sys; 25 use gst_sys; 26 27 pub struct CapsFeatures(ptr::NonNull<CapsFeaturesRef>, PhantomData<CapsFeaturesRef>); 28 unsafe impl Send for CapsFeatures {} 29 unsafe impl Sync for CapsFeatures {} 30 31 impl CapsFeatures { new(features: &[&str]) -> Self32 pub fn new(features: &[&str]) -> Self { 33 let mut f = Self::new_empty(); 34 35 for feature in features { 36 f.add(feature); 37 } 38 39 f 40 } 41 new_empty() -> Self42 pub fn new_empty() -> Self { 43 assert_initialized_main_thread!(); 44 unsafe { 45 CapsFeatures( 46 ptr::NonNull::new_unchecked( 47 gst_sys::gst_caps_features_new_empty() as *mut CapsFeaturesRef 48 ), 49 PhantomData, 50 ) 51 } 52 } 53 new_any() -> Self54 pub fn new_any() -> Self { 55 assert_initialized_main_thread!(); 56 unsafe { 57 CapsFeatures( 58 ptr::NonNull::new_unchecked( 59 gst_sys::gst_caps_features_new_any() as *mut CapsFeaturesRef 60 ), 61 PhantomData, 62 ) 63 } 64 } 65 into_ptr(self) -> *mut gst_sys::GstCapsFeatures66 pub unsafe fn into_ptr(self) -> *mut gst_sys::GstCapsFeatures { 67 let s = mem::ManuallyDrop::new(self); 68 let ptr = s.0.as_ptr() as *mut CapsFeaturesRef as *mut gst_sys::GstCapsFeatures; 69 70 ptr 71 } 72 } 73 74 impl Deref for CapsFeatures { 75 type Target = CapsFeaturesRef; 76 deref(&self) -> &CapsFeaturesRef77 fn deref(&self) -> &CapsFeaturesRef { 78 unsafe { self.0.as_ref() } 79 } 80 } 81 82 impl DerefMut for CapsFeatures { deref_mut(&mut self) -> &mut CapsFeaturesRef83 fn deref_mut(&mut self) -> &mut CapsFeaturesRef { 84 unsafe { self.0.as_mut() } 85 } 86 } 87 88 impl AsRef<CapsFeaturesRef> for CapsFeatures { as_ref(&self) -> &CapsFeaturesRef89 fn as_ref(&self) -> &CapsFeaturesRef { 90 self.deref() 91 } 92 } 93 94 impl AsMut<CapsFeaturesRef> for CapsFeatures { as_mut(&mut self) -> &mut CapsFeaturesRef95 fn as_mut(&mut self) -> &mut CapsFeaturesRef { 96 self.deref_mut() 97 } 98 } 99 100 impl Clone for CapsFeatures { clone(&self) -> Self101 fn clone(&self) -> Self { 102 unsafe { 103 let ptr = gst_sys::gst_caps_features_copy(&self.0.as_ref().0) as *mut CapsFeaturesRef; 104 assert!(!ptr.is_null()); 105 CapsFeatures(ptr::NonNull::new_unchecked(ptr), PhantomData) 106 } 107 } 108 } 109 110 impl Drop for CapsFeatures { drop(&mut self)111 fn drop(&mut self) { 112 unsafe { gst_sys::gst_caps_features_free(&mut self.0.as_mut().0) } 113 } 114 } 115 116 impl fmt::Debug for CapsFeatures { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 118 f.debug_tuple("CapsFeatures") 119 .field(&self.to_string()) 120 .finish() 121 } 122 } 123 124 impl fmt::Display for CapsFeatures { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result125 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 126 // Need to make sure to not call ToString::to_string() here, which 127 // we have because of the Display impl. We need CapsFeaturesRef::to_string() 128 f.write_str(&CapsFeaturesRef::to_string(self.as_ref())) 129 } 130 } 131 132 impl str::FromStr for CapsFeatures { 133 type Err = glib::BoolError; 134 from_str(s: &str) -> Result<Self, glib::BoolError>135 fn from_str(s: &str) -> Result<Self, glib::BoolError> { 136 assert_initialized_main_thread!(); 137 unsafe { 138 let ptr = gst_sys::gst_caps_features_from_string(s.to_glib_none().0); 139 if ptr.is_null() { 140 return Err(glib_bool_error!( 141 "Failed to parse caps features from string" 142 )); 143 } 144 145 Ok(CapsFeatures( 146 ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef), 147 PhantomData, 148 )) 149 } 150 } 151 } 152 153 impl Borrow<CapsFeaturesRef> for CapsFeatures { borrow(&self) -> &CapsFeaturesRef154 fn borrow(&self) -> &CapsFeaturesRef { 155 unsafe { self.0.as_ref() } 156 } 157 } 158 159 impl BorrowMut<CapsFeaturesRef> for CapsFeatures { borrow_mut(&mut self) -> &mut CapsFeaturesRef160 fn borrow_mut(&mut self) -> &mut CapsFeaturesRef { 161 unsafe { self.0.as_mut() } 162 } 163 } 164 165 impl glib::types::StaticType for CapsFeatures { static_type() -> glib::types::Type166 fn static_type() -> glib::types::Type { 167 unsafe { from_glib(gst_sys::gst_caps_features_get_type()) } 168 } 169 } 170 171 impl<'a> ToGlibPtr<'a, *const gst_sys::GstCapsFeatures> for CapsFeatures { 172 type Storage = &'a Self; 173 to_glib_none(&'a self) -> Stash<'a, *const gst_sys::GstCapsFeatures, Self>174 fn to_glib_none(&'a self) -> Stash<'a, *const gst_sys::GstCapsFeatures, Self> { 175 unsafe { Stash(&self.0.as_ref().0, self) } 176 } 177 to_glib_full(&self) -> *const gst_sys::GstCapsFeatures178 fn to_glib_full(&self) -> *const gst_sys::GstCapsFeatures { 179 unsafe { gst_sys::gst_caps_features_copy(&self.0.as_ref().0) } 180 } 181 } 182 183 impl<'a> ToGlibPtr<'a, *mut gst_sys::GstCapsFeatures> for CapsFeatures { 184 type Storage = &'a Self; 185 to_glib_none(&'a self) -> Stash<'a, *mut gst_sys::GstCapsFeatures, Self>186 fn to_glib_none(&'a self) -> Stash<'a, *mut gst_sys::GstCapsFeatures, Self> { 187 unsafe { Stash(&self.0.as_ref().0 as *const _ as *mut _, self) } 188 } 189 to_glib_full(&self) -> *mut gst_sys::GstCapsFeatures190 fn to_glib_full(&self) -> *mut gst_sys::GstCapsFeatures { 191 unsafe { gst_sys::gst_caps_features_copy(&self.0.as_ref().0) } 192 } 193 } 194 195 impl<'a> ToGlibPtrMut<'a, *mut gst_sys::GstCapsFeatures> for CapsFeatures { 196 type Storage = &'a mut Self; 197 to_glib_none_mut(&'a mut self) -> StashMut<*mut gst_sys::GstCapsFeatures, Self>198 fn to_glib_none_mut(&'a mut self) -> StashMut<*mut gst_sys::GstCapsFeatures, Self> { 199 unsafe { StashMut(&mut self.0.as_mut().0, self) } 200 } 201 } 202 203 impl FromGlibPtrNone<*const gst_sys::GstCapsFeatures> for CapsFeatures { from_glib_none(ptr: *const gst_sys::GstCapsFeatures) -> Self204 unsafe fn from_glib_none(ptr: *const gst_sys::GstCapsFeatures) -> Self { 205 assert!(!ptr.is_null()); 206 let ptr = gst_sys::gst_caps_features_copy(ptr); 207 assert!(!ptr.is_null()); 208 CapsFeatures( 209 ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef), 210 PhantomData, 211 ) 212 } 213 } 214 215 impl FromGlibPtrNone<*mut gst_sys::GstCapsFeatures> for CapsFeatures { from_glib_none(ptr: *mut gst_sys::GstCapsFeatures) -> Self216 unsafe fn from_glib_none(ptr: *mut gst_sys::GstCapsFeatures) -> Self { 217 assert!(!ptr.is_null()); 218 let ptr = gst_sys::gst_caps_features_copy(ptr); 219 assert!(!ptr.is_null()); 220 CapsFeatures( 221 ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef), 222 PhantomData, 223 ) 224 } 225 } 226 227 impl FromGlibPtrFull<*const gst_sys::GstCapsFeatures> for CapsFeatures { from_glib_full(ptr: *const gst_sys::GstCapsFeatures) -> Self228 unsafe fn from_glib_full(ptr: *const gst_sys::GstCapsFeatures) -> Self { 229 assert!(!ptr.is_null()); 230 CapsFeatures( 231 ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef), 232 PhantomData, 233 ) 234 } 235 } 236 237 impl FromGlibPtrFull<*mut gst_sys::GstCapsFeatures> for CapsFeatures { from_glib_full(ptr: *mut gst_sys::GstCapsFeatures) -> Self238 unsafe fn from_glib_full(ptr: *mut gst_sys::GstCapsFeatures) -> Self { 239 assert!(!ptr.is_null()); 240 CapsFeatures( 241 ptr::NonNull::new_unchecked(ptr as *mut CapsFeaturesRef), 242 PhantomData, 243 ) 244 } 245 } 246 247 impl<'a> glib::value::FromValueOptional<'a> for CapsFeatures { from_value_optional(v: &'a glib::Value) -> Option<Self>248 unsafe fn from_value_optional(v: &'a glib::Value) -> Option<Self> { 249 <&'a CapsFeaturesRef as glib::value::FromValueOptional<'a>>::from_value_optional(v) 250 .map(ToOwned::to_owned) 251 } 252 } 253 254 impl glib::value::SetValue for CapsFeatures { set_value(v: &mut glib::Value, s: &Self)255 unsafe fn set_value(v: &mut glib::Value, s: &Self) { 256 <CapsFeaturesRef as glib::value::SetValue>::set_value(v, s.as_ref()) 257 } 258 } 259 260 impl glib::value::SetValueOptional for CapsFeatures { set_value_optional(v: &mut glib::Value, s: Option<&Self>)261 unsafe fn set_value_optional(v: &mut glib::Value, s: Option<&Self>) { 262 <CapsFeaturesRef as glib::value::SetValueOptional>::set_value_optional( 263 v, 264 s.map(|s| s.as_ref()), 265 ) 266 } 267 } 268 269 impl GlibPtrDefault for CapsFeatures { 270 type GlibType = *mut gst_sys::GstCapsFeatures; 271 } 272 273 #[repr(C)] 274 pub struct CapsFeaturesRef(gst_sys::GstCapsFeatures); 275 276 impl CapsFeaturesRef { from_glib_borrow<'a>( ptr: *const gst_sys::GstCapsFeatures, ) -> &'a CapsFeaturesRef277 pub unsafe fn from_glib_borrow<'a>( 278 ptr: *const gst_sys::GstCapsFeatures, 279 ) -> &'a CapsFeaturesRef { 280 assert!(!ptr.is_null()); 281 282 &*(ptr as *mut CapsFeaturesRef) 283 } 284 from_glib_borrow_mut<'a>( ptr: *mut gst_sys::GstCapsFeatures, ) -> &'a mut CapsFeaturesRef285 pub unsafe fn from_glib_borrow_mut<'a>( 286 ptr: *mut gst_sys::GstCapsFeatures, 287 ) -> &'a mut CapsFeaturesRef { 288 assert!(!ptr.is_null()); 289 290 &mut *(ptr as *mut CapsFeaturesRef) 291 } 292 as_ptr(&self) -> *const gst_sys::GstCapsFeatures293 pub unsafe fn as_ptr(&self) -> *const gst_sys::GstCapsFeatures { 294 self as *const Self as *const gst_sys::GstCapsFeatures 295 } 296 as_mut_ptr(&self) -> *mut gst_sys::GstCapsFeatures297 pub unsafe fn as_mut_ptr(&self) -> *mut gst_sys::GstCapsFeatures { 298 self as *const Self as *mut gst_sys::GstCapsFeatures 299 } 300 is_empty(&self) -> bool301 pub fn is_empty(&self) -> bool { 302 self.get_size() == 0 && !self.is_any() 303 } 304 is_any(&self) -> bool305 pub fn is_any(&self) -> bool { 306 unsafe { from_glib(gst_sys::gst_caps_features_is_any(self.as_ptr())) } 307 } 308 contains(&self, feature: &str) -> bool309 pub fn contains(&self, feature: &str) -> bool { 310 unsafe { 311 from_glib(gst_sys::gst_caps_features_contains( 312 self.as_ptr(), 313 feature.to_glib_none().0, 314 )) 315 } 316 } 317 get_size(&self) -> u32318 pub fn get_size(&self) -> u32 { 319 unsafe { gst_sys::gst_caps_features_get_size(self.as_ptr()) } 320 } 321 get_nth(&self, idx: u32) -> Option<&str>322 pub fn get_nth(&self, idx: u32) -> Option<&str> { 323 if idx >= self.get_size() { 324 return None; 325 } 326 327 unsafe { 328 let feature = gst_sys::gst_caps_features_get_nth(self.as_ptr(), idx); 329 if feature.is_null() { 330 return None; 331 } 332 333 Some(CStr::from_ptr(feature).to_str().unwrap()) 334 } 335 } 336 add(&mut self, feature: &str)337 pub fn add(&mut self, feature: &str) { 338 unsafe { gst_sys::gst_caps_features_add(self.as_mut_ptr(), feature.to_glib_none().0) } 339 } 340 remove(&mut self, feature: &str)341 pub fn remove(&mut self, feature: &str) { 342 unsafe { gst_sys::gst_caps_features_remove(self.as_mut_ptr(), feature.to_glib_none().0) } 343 } 344 iter(&self) -> Iter345 pub fn iter(&self) -> Iter { 346 Iter::new(self) 347 } 348 349 // This is not an equivalence relation with regards to ANY. Everything is equal to ANY is_equal(&self, other: &CapsFeaturesRef) -> bool350 pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool { 351 unsafe { 352 from_glib(gst_sys::gst_caps_features_is_equal( 353 self.as_ptr(), 354 other.as_ptr(), 355 )) 356 } 357 } 358 } 359 360 impl glib::types::StaticType for CapsFeaturesRef { static_type() -> glib::types::Type361 fn static_type() -> glib::types::Type { 362 unsafe { from_glib(gst_sys::gst_structure_get_type()) } 363 } 364 } 365 366 impl<'a> glib::value::FromValueOptional<'a> for &'a CapsFeaturesRef { from_value_optional(v: &'a glib::Value) -> Option<Self>367 unsafe fn from_value_optional(v: &'a glib::Value) -> Option<Self> { 368 let ptr = gobject_sys::g_value_get_boxed(v.to_glib_none().0); 369 if ptr.is_null() { 370 None 371 } else { 372 Some(CapsFeaturesRef::from_glib_borrow( 373 ptr as *const gst_sys::GstCapsFeatures, 374 )) 375 } 376 } 377 } 378 379 impl glib::value::SetValue for CapsFeaturesRef { set_value(v: &mut glib::Value, s: &Self)380 unsafe fn set_value(v: &mut glib::Value, s: &Self) { 381 gobject_sys::g_value_set_boxed(v.to_glib_none_mut().0, s.as_ptr() as gpointer); 382 } 383 } 384 385 impl glib::value::SetValueOptional for CapsFeaturesRef { set_value_optional(v: &mut glib::Value, s: Option<&Self>)386 unsafe fn set_value_optional(v: &mut glib::Value, s: Option<&Self>) { 387 if let Some(s) = s { 388 gobject_sys::g_value_set_boxed(v.to_glib_none_mut().0, s.as_ptr() as gpointer); 389 } else { 390 gobject_sys::g_value_set_boxed(v.to_glib_none_mut().0, ptr::null_mut()); 391 } 392 } 393 } 394 395 #[derive(Debug)] 396 pub struct Iter<'a> { 397 caps_features: &'a CapsFeaturesRef, 398 idx: u32, 399 n_features: u32, 400 } 401 402 impl<'a> Iter<'a> { new(caps_features: &'a CapsFeaturesRef) -> Iter<'a>403 fn new(caps_features: &'a CapsFeaturesRef) -> Iter<'a> { 404 skip_assert_initialized!(); 405 let n_features = caps_features.get_size(); 406 407 Iter { 408 caps_features, 409 idx: 0, 410 n_features, 411 } 412 } 413 } 414 415 impl<'a> Iterator for Iter<'a> { 416 type Item = &'a str; 417 next(&mut self) -> Option<Self::Item>418 fn next(&mut self) -> Option<Self::Item> { 419 if self.idx >= self.n_features { 420 return None; 421 } 422 423 unsafe { 424 let feature = gst_sys::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.idx); 425 if feature.is_null() { 426 return None; 427 } 428 429 self.idx += 1; 430 431 Some(CStr::from_ptr(feature).to_str().unwrap()) 432 } 433 } 434 size_hint(&self) -> (usize, Option<usize>)435 fn size_hint(&self) -> (usize, Option<usize>) { 436 if self.idx == self.n_features { 437 return (0, Some(0)); 438 } 439 440 let remaining = (self.n_features - self.idx) as usize; 441 442 (remaining, Some(remaining)) 443 } 444 } 445 446 impl<'a> DoubleEndedIterator for Iter<'a> { next_back(&mut self) -> Option<Self::Item>447 fn next_back(&mut self) -> Option<Self::Item> { 448 if self.idx == self.n_features { 449 return None; 450 } 451 452 self.n_features -= 1; 453 454 unsafe { 455 let feature = 456 gst_sys::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.n_features); 457 if feature.is_null() { 458 return None; 459 } 460 461 Some(CStr::from_ptr(feature).to_str().unwrap()) 462 } 463 } 464 } 465 466 impl<'a> ExactSizeIterator for Iter<'a> {} 467 468 impl fmt::Debug for CapsFeaturesRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result469 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 470 f.debug_tuple("CapsFeatures") 471 .field(&self.to_string()) 472 .finish() 473 } 474 } 475 476 impl fmt::Display for CapsFeaturesRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result477 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 478 let s = unsafe { 479 glib::GString::from_glib_full(gst_sys::gst_caps_features_to_string(self.as_ptr())) 480 }; 481 f.write_str(&s) 482 } 483 } 484 485 impl ToOwned for CapsFeaturesRef { 486 type Owned = CapsFeatures; 487 to_owned(&self) -> CapsFeatures488 fn to_owned(&self) -> CapsFeatures { 489 unsafe { 490 from_glib_full(gst_sys::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) 491 } 492 } 493 } 494 495 unsafe impl Sync for CapsFeaturesRef {} 496 unsafe impl Send for CapsFeaturesRef {} 497 498 lazy_static! { 499 pub static ref CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: &'static str = unsafe { 500 CStr::from_ptr(gst_sys::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) 501 .to_str() 502 .unwrap() 503 }; 504 pub static ref CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: CapsFeatures = 505 CapsFeatures::new(&[*CAPS_FEATURE_MEMORY_SYSTEM_MEMORY]); 506 } 507 508 #[cfg(test)] 509 mod tests { 510 use super::*; 511 512 #[test] test_from_value_optional()513 fn test_from_value_optional() { 514 ::init().unwrap(); 515 516 let a = glib::value::Value::from(None::<&CapsFeatures>); 517 assert!(a.get::<CapsFeatures>().unwrap().is_none()); 518 let b = glib::value::Value::from(&CapsFeatures::new_empty()); 519 assert!(b.get::<CapsFeatures>().unwrap().is_some()); 520 } 521 } 522