From 992105b49f44625376b34c1c987f934e1c44104b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 7 Jul 2017 16:04:54 +0300 Subject: [PATCH] Implement basic GstStructure bindings --- Gir_Gst.toml | 16 +- gstreamer/src/auto/device.rs | 16 - gstreamer/src/auto/element.rs | 4 +- gstreamer/src/auto/functions.rs | 6 +- gstreamer/src/auto/plugin.rs | 17 +- gstreamer/src/lib.rs | 2 + gstreamer/src/message.rs | 81 +++-- gstreamer/src/structure.rs | 509 ++++++++++++++++++++++++++++++++ 8 files changed, 582 insertions(+), 69 deletions(-) create mode 100644 gstreamer/src/structure.rs diff --git a/Gir_Gst.toml b/Gir_Gst.toml index ec4d43a88..52b2c677f 100644 --- a/Gir_Gst.toml +++ b/Gir_Gst.toml @@ -37,7 +37,6 @@ generate = [ "Gst.URIError", "Gst.StructureChangeType", "Gst.StreamStatusType", - "Gst.Device", "Gst.DeviceMonitor", "Gst.DeviceProvider", "Gst.DeviceProviderFactory", @@ -52,6 +51,7 @@ generate = [ manual = [ "GLib.Error", "Gst.Message", + "Gst.Structure", ] [[object]] @@ -160,6 +160,20 @@ name = "Gst.ElementFactory" status = "generate" trait = false +[[object]] +name = "Gst.Device" +status = "generate" + [[object.function]] + name = "get_properties" + # Structure is not a GObject + ignore = true + + [[object.property]] + name = "properties" + # Structure is not a GObject + ignore = true + + [[object]] name = "Gst.Object" status = "generate" diff --git a/gstreamer/src/auto/device.rs b/gstreamer/src/auto/device.rs index bdad07244..25f38a187 100644 --- a/gstreamer/src/auto/device.rs +++ b/gstreamer/src/auto/device.rs @@ -35,8 +35,6 @@ pub trait DeviceExt { fn get_display_name(&self) -> Option; - //fn get_properties(&self) -> /*Ignored*/Option; - fn has_classes(&self, classes: &str) -> bool; fn has_classesv(&self, classes: &[&str]) -> bool; @@ -49,8 +47,6 @@ pub trait DeviceExt { fn get_property_display_name(&self) -> Option; - //fn get_property_properties(&self) -> /*Ignored*/Option; - fn connect_removed(&self, f: F) -> u64; } @@ -79,10 +75,6 @@ impl + IsA> DeviceExt for O { } } - //fn get_properties(&self) -> /*Ignored*/Option { - // unsafe { TODO: call ffi::gst_device_get_properties() } - //} - fn has_classes(&self, classes: &str) -> bool { unsafe { from_glib(ffi::gst_device_has_classes(self.to_glib_none().0, classes.to_glib_none().0)) @@ -125,14 +117,6 @@ impl + IsA> DeviceExt for O { value.get() } - //fn get_property_properties(&self) -> /*Ignored*/Option { - // let mut value = Value::from(None::<&/*Ignored*/Structure>); - // unsafe { - // gobject_ffi::g_object_get_property(self.to_glib_none().0, "properties".to_glib_none().0, value.to_glib_none_mut().0); - // } - // value.get() - //} - fn connect_removed(&self, f: F) -> u64 { unsafe { let f: Box_> = Box_::new(Box_::new(f)); diff --git a/gstreamer/src/auto/element.rs b/gstreamer/src/auto/element.rs index 7c860b1c5..4fcbb7d91 100644 --- a/gstreamer/src/auto/element.rs +++ b/gstreamer/src/auto/element.rs @@ -146,7 +146,7 @@ pub trait ElementExt { //fn message_full<'a, 'b, P: Into>, Q: Into>>(&self, type_: /*Ignored*/MessageType, domain: /*Ignored*/glib::Quark, code: i32, text: P, debug: Q, file: &str, function: &str, line: i32); //#[cfg(feature = "v1_10")] - //fn message_full_with_details<'a, 'b, P: Into>, Q: Into>>(&self, type_: /*Ignored*/MessageType, domain: /*Ignored*/glib::Quark, code: i32, text: P, debug: Q, file: &str, function: &str, line: i32, structure: /*Ignored*/&mut Structure); + //fn message_full_with_details<'a, 'b, P: Into>, Q: Into>>(&self, type_: /*Ignored*/MessageType, domain: /*Ignored*/glib::Quark, code: i32, text: P, debug: Q, file: &str, function: &str, line: i32, structure: &mut Structure); fn no_more_pads(&self); @@ -394,7 +394,7 @@ impl + IsA> ElementExt for O { //} //#[cfg(feature = "v1_10")] - //fn message_full_with_details<'a, 'b, P: Into>, Q: Into>>(&self, type_: /*Ignored*/MessageType, domain: /*Ignored*/glib::Quark, code: i32, text: P, debug: Q, file: &str, function: &str, line: i32, structure: /*Ignored*/&mut Structure) { + //fn message_full_with_details<'a, 'b, P: Into>, Q: Into>>(&self, type_: /*Ignored*/MessageType, domain: /*Ignored*/glib::Quark, code: i32, text: P, debug: Q, file: &str, function: &str, line: i32, structure: &mut Structure) { // unsafe { TODO: call ffi::gst_element_message_full_with_details() } //} diff --git a/gstreamer/src/auto/functions.rs b/gstreamer/src/auto/functions.rs index e882b3e59..4f386a31b 100644 --- a/gstreamer/src/auto/functions.rs +++ b/gstreamer/src/auto/functions.rs @@ -224,7 +224,7 @@ pub fn is_initialized() -> bool { } } -//pub fn make_element_message_details(name: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> /*Ignored*/Option { +//pub fn make_element_message_details(name: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Option { // unsafe { TODO: call ffi::gst_make_element_message_details() } //} @@ -641,7 +641,7 @@ pub fn util_uint64_scale_round(val: u64, num: u64, denom: u64) -> u64 { // unsafe { TODO: call ffi::gst_value_get_int_range_step() } //} -//pub fn value_get_structure(value: /*Ignored*/&glib::Value) -> /*Ignored*/Option { +//pub fn value_get_structure(value: /*Ignored*/&glib::Value) -> Option { // unsafe { TODO: call ffi::gst_value_get_structure() } //} @@ -717,7 +717,7 @@ pub fn util_uint64_scale_round(val: u64, num: u64, denom: u64) -> u64 { // unsafe { TODO: call ffi::gst_value_set_int_range_step() } //} -//pub fn value_set_structure(value: /*Ignored*/&mut glib::Value, structure: /*Ignored*/&Structure) { +//pub fn value_set_structure(value: /*Ignored*/&mut glib::Value, structure: &Structure) { // unsafe { TODO: call ffi::gst_value_set_structure() } //} diff --git a/gstreamer/src/auto/plugin.rs b/gstreamer/src/auto/plugin.rs index 59e8cfaa9..5d6594f81 100644 --- a/gstreamer/src/auto/plugin.rs +++ b/gstreamer/src/auto/plugin.rs @@ -3,6 +3,7 @@ use Error; use Object; +use Structure; use ffi; use glib::translate::*; use std::ptr; @@ -24,9 +25,11 @@ impl Plugin { // unsafe { TODO: call ffi::gst_plugin_add_dependency_simple() } //} - //pub fn get_cache_data(&self) -> /*Ignored*/Option { - // unsafe { TODO: call ffi::gst_plugin_get_cache_data() } - //} + pub fn get_cache_data(&self) -> Option { + unsafe { + from_glib_none(ffi::gst_plugin_get_cache_data(self.to_glib_none().0)) + } + } pub fn get_description(&self) -> Option { unsafe { @@ -88,9 +91,11 @@ impl Plugin { } } - //pub fn set_cache_data(&self, cache_data: /*Ignored*/&mut Structure) { - // unsafe { TODO: call ffi::gst_plugin_set_cache_data() } - //} + pub fn set_cache_data(&self, cache_data: &mut Structure) { + unsafe { + ffi::gst_plugin_set_cache_data(self.to_glib_none().0, cache_data.to_glib_full()); + } + } pub fn list_free(list: &[Plugin]) { unsafe { diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 82c2c2850..9c70776cf 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -47,6 +47,8 @@ pub use miniobject::GstRc; pub mod message; pub use message::Message; pub use message::MessageView; +pub mod structure; +pub use structure::Structure; mod element; mod bin; diff --git a/gstreamer/src/message.rs b/gstreamer/src/message.rs index 7c0854468..47612495f 100644 --- a/gstreamer/src/message.rs +++ b/gstreamer/src/message.rs @@ -723,9 +723,10 @@ macro_rules! message_builder_generic_impl { } } - pub fn build(self) -> Message { + pub fn build(mut self) -> Message { unsafe { - let msg = $new_fn(&self, self.src.to_glib_none().0); + let src = self.src.to_glib_none().0; + let msg = $new_fn(&mut self, src); if let Some(seqnum) = self.seqnum { ffi::gst_message_set_seqnum(msg, seqnum); } @@ -776,7 +777,7 @@ impl<'a> ErrorBuilder<'a> { // TODO details - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_error(src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_error(src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0)); } pub struct WarningBuilder<'a> { @@ -802,7 +803,7 @@ impl<'a> WarningBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_warning(src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_warning(src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0)); } pub struct InfoBuilder<'a> { @@ -830,7 +831,7 @@ impl<'a> InfoBuilder<'a> { // TODO details - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_warning(src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_warning(src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0)); } pub struct TagBuilder<'a> { @@ -874,7 +875,7 @@ impl<'a> BufferingBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| { + message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_buffering(src, s.percent); if let Some((mode, avg_in, avg_out, buffering_left)) = s.stats { @@ -903,7 +904,7 @@ impl<'a> StateChangedBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_state_changed(src, s.old.to_glib(), s.new.to_glib(), s.pending.to_glib())); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_state_changed(src, s.old.to_glib(), s.new.to_glib(), s.pending.to_glib())); } pub struct StateDirtyBuilder<'a> { @@ -947,7 +948,7 @@ impl<'a> StepDoneBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_step_done(src, s.format.to_glib(), s.amount, s.rate, s.flush.to_glib(), s.intermediate.to_glib(), s.duration, s.eos.to_glib())); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_step_done(src, s.format.to_glib(), s.amount, s.rate, s.flush.to_glib(), s.intermediate.to_glib(), s.duration, s.eos.to_glib())); } pub struct ClockProvideBuilder<'a> { @@ -966,7 +967,7 @@ impl<'a> ClockProvideBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_clock_provide(src, s.clock.to_glib_none().0, s.ready.to_glib())); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_clock_provide(src, s.clock.to_glib_none().0, s.ready.to_glib())); } pub struct ClockLostBuilder<'a> { @@ -983,7 +984,7 @@ impl<'a> ClockLostBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_clock_lost(src, s.clock.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_clock_lost(src, s.clock.to_glib_none().0)); } pub struct NewClockBuilder<'a> { @@ -1000,7 +1001,7 @@ impl<'a> NewClockBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_new_clock(src, s.clock.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_new_clock(src, s.clock.to_glib_none().0)); } pub struct StructureChangeBuilder<'a> { @@ -1021,7 +1022,7 @@ impl<'a> StructureChangeBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_structure_change(src, s.type_.to_glib(), s.owner.to_glib_none().0, s.busy.to_glib())); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_structure_change(src, s.type_.to_glib(), s.owner.to_glib_none().0, s.busy.to_glib())); } pub struct StreamStatusBuilder<'a> { @@ -1049,7 +1050,7 @@ impl<'a> StreamStatusBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| { + message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_stream_status(src, s.type_.to_glib(), s.owner.to_glib_none().0); if let Some(status_object) = s.status_object { ffi::gst_message_set_stream_status_object(msg, status_object.to_glib_none().0); @@ -1058,40 +1059,38 @@ impl<'a> StreamStatusBuilder<'a> { }); } -// TODO Structure pub struct ApplicationBuilder<'a> { src: Option<&'a Object>, seqnum: Option, - structure: (), + structure: Option<::Structure>, } impl<'a> ApplicationBuilder<'a> { - pub fn new(structure: () /* &'a Structure */) -> Self { + pub fn new(structure: ::Structure) -> Self { Self { src: None, seqnum: None, - structure: structure, + structure: Some(structure), } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_application(src, ptr::null_mut() /*s.structure.to_glib_full()*/)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_application(src, s.structure.take().unwrap().into_ptr())); } -// TODO Structure pub struct ElementBuilder<'a> { src: Option<&'a Object>, seqnum: Option, - structure: (), + structure: Option<::Structure>, } impl<'a> ElementBuilder<'a> { - pub fn new(structure: () /* &'a Structure */) -> Self { + pub fn new(structure: ::Structure) -> Self { Self { src: None, seqnum: None, - structure: structure, + structure: Some(structure), } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_element(src, ptr::null_mut() /*s.structure.to_glib_full()*/)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_element(src, s.structure.take().unwrap().into_ptr())); } pub struct SegmentStartBuilder<'a> { @@ -1110,7 +1109,7 @@ impl<'a> SegmentStartBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_segment_start(src, s.format.to_glib(), s.position)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_segment_start(src, s.format.to_glib(), s.position)); } pub struct SegmentDoneBuilder<'a> { @@ -1129,7 +1128,7 @@ impl<'a> SegmentDoneBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_segment_done(src, s.format.to_glib(), s.position)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_segment_done(src, s.format.to_glib(), s.position)); } pub struct DurationChangedBuilder<'a> { @@ -1191,7 +1190,7 @@ impl<'a> AsyncDoneBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_async_done(src, s.running_time)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_async_done(src, s.running_time)); } pub struct RequestStateBuilder<'a> { @@ -1208,7 +1207,7 @@ impl<'a> RequestStateBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_request_state(src, s.state.to_glib())); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_request_state(src, s.state.to_glib())); } pub struct StepStartBuilder<'a> { @@ -1235,7 +1234,7 @@ impl<'a> StepStartBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_step_start(src, s.active.to_glib(), s.format.to_glib(), s.amount, s.rate, s.flush.to_glib(), s.intermediate.to_glib())); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_step_start(src, s.active.to_glib(), s.format.to_glib(), s.amount, s.rate, s.flush.to_glib(), s.intermediate.to_glib())); } pub struct QosBuilder<'a> { @@ -1278,7 +1277,7 @@ impl<'a> QosBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| { + message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_qos(src, s.live.to_glib(), s.running_time, s.stream_time, s.timestamp, s.duration); if let Some((jitter, proportion, quality)) = s.values { ffi::gst_message_set_qos_values(msg, jitter, proportion, quality); @@ -1322,7 +1321,7 @@ impl<'a> ProgressBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_progress(src, s.type_.to_glib(), s.code.to_glib_none().0, s.text.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_progress(src, s.type_.to_glib(), s.code.to_glib_none().0, s.text.to_glib_none().0)); } // TODO Toc @@ -1342,7 +1341,7 @@ impl<'a> TocBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_toc(src, ptr::null_mut() /*s.structure.to_glib_full()*/, s.updated.to_glib())); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_toc(src, ptr::null_mut() /*s.structure.to_glib_full()*/, s.updated.to_glib())); } pub struct ResetTimeBuilder<'a> { @@ -1359,7 +1358,7 @@ impl<'a> ResetTimeBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_reset_time(src, s.running_time)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_reset_time(src, s.running_time)); } pub struct StreamStartBuilder<'a> { @@ -1383,7 +1382,7 @@ impl<'a> StreamStartBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| { + message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_stream_start(src); if let Some(group_id) = s.group_id { ffi::gst_message_set_group_id(msg, group_id); @@ -1406,7 +1405,7 @@ impl<'a> NeedContextBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_need_context(src, s.context_type.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_need_context(src, s.context_type.to_glib_none().0)); } // TODO Context @@ -1424,7 +1423,7 @@ impl<'a> HaveContextBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_have_context(src, ptr::null_mut() /*s.context.to_glib_full().0*/)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_have_context(src, ptr::null_mut() /*s.context.to_glib_full().0*/)); } pub struct DeviceAddedBuilder<'a> { @@ -1441,7 +1440,7 @@ impl<'a> DeviceAddedBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_device_added(src, s.device.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_device_added(src, s.device.to_glib_none().0)); } pub struct DeviceRemovedBuilder<'a> { @@ -1458,7 +1457,7 @@ impl<'a> DeviceRemovedBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_device_removed(src, s.device.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_device_removed(src, s.device.to_glib_none().0)); } pub struct PropertyNotifyBuilder<'a> { @@ -1478,7 +1477,7 @@ impl<'a> PropertyNotifyBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_property_notify(src, s.property_name.to_glib_none().0, mut_override(s.value.to_glib_none().0))); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_property_notify(src, s.property_name.to_glib_none().0, mut_override(s.value.to_glib_none().0))); } pub struct StreamCollectionBuilder<'a> { @@ -1497,7 +1496,7 @@ impl<'a> StreamCollectionBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_stream_collection(src, s.collection.to_glib_none().0)); + message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_stream_collection(src, s.collection.to_glib_none().0)); } pub struct StreamsSelectedBuilder<'a> { @@ -1526,7 +1525,7 @@ impl<'a> StreamsSelectedBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| { + message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_streams_selected(src, s.collection.to_glib_none().0); if let Some(streams) = s.streams { for stream in streams { @@ -1566,7 +1565,7 @@ impl<'a> RedirectBuilder<'a> { } } - message_builder_generic_impl!(|s: &Self, src| { + message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_redirect(src, s.location.to_glib_none().0, ptr::null_mut(), ptr::null_mut()); if let Some(entries) = s.entries { for &(location, tag_list, entry_struct) in entries { diff --git a/gstreamer/src/structure.rs b/gstreamer/src/structure.rs new file mode 100644 index 000000000..13a121e0f --- /dev/null +++ b/gstreamer/src/structure.rs @@ -0,0 +1,509 @@ +// Copyright (C) 2016-2017 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::ptr; +use std::mem; +use std::ffi::{CStr, CString}; +use std::ops::{Deref, DerefMut}; +use std::borrow::{Borrow, ToOwned, BorrowMut}; +use std::marker::PhantomData; + +use glib; +use glib::translate::{from_glib, from_glib_full, from_glib_none, Stash, StashMut, ToGlibPtr, ToGlibPtrMut, FromGlibPtrNone, FromGlibPtrBorrow, FromGlibPtrFull}; +use glib::value::{Value, ToValue, FromValueOptional}; +use ffi; +use glib_ffi; + +pub struct Structure(*mut StructureRef, PhantomData, bool); + +impl Structure { + pub fn new_empty(name: &str) -> Structure { + Structure( + unsafe { ffi::gst_structure_new_empty(name.to_glib_none().0) as *mut StructureRef }, + PhantomData, + false, + ) + } + + pub fn new(name: &str, values: &[(&str, &Value)]) -> Structure { + let mut structure = Structure::new_empty(name); + + for &(f, v) in values { + structure.set_value(f, v.clone()); + } + + structure + } + + pub fn from_string(s: &str) -> Option { + unsafe { + let structure = ffi::gst_structure_from_string(s.to_glib_none().0, ptr::null_mut()); + if structure.is_null() { + None + } else { + Some(Structure(structure as *mut StructureRef, PhantomData, false)) + } + } + } + + pub unsafe fn into_ptr(self) -> *mut ffi::GstStructure { + let ptr = self.0 as *mut StructureRef as *mut ffi::GstStructure; + mem::forget(self); + + ptr + } +} + +impl Deref for Structure { + type Target = StructureRef; + + fn deref(&self) -> &StructureRef { + unsafe { &*self.0 } + } +} + +impl DerefMut for Structure { + fn deref_mut(&mut self) -> &mut StructureRef { + unsafe { &mut *self.0 } + } +} + +impl AsRef for Structure { + fn as_ref(&self) -> &StructureRef { + self.deref() + } +} + +impl AsMut for Structure { + fn as_mut(&mut self) -> &mut StructureRef { + self.deref_mut() + } +} + +impl Clone for Structure { + fn clone(&self) -> Self { + Structure( + unsafe { ffi::gst_structure_copy(&(*self.0).0) as *mut StructureRef }, + PhantomData, + false, + ) + } +} + +impl Drop for Structure { + fn drop(&mut self) { + if !self.2 { + unsafe { ffi::gst_structure_free(&mut (*self.0).0) } + } + } +} + +impl fmt::Debug for Structure { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.to_string()) + } +} + +impl PartialEq for Structure { + fn eq(&self, other: &Structure) -> bool { + self.as_ref().eq(other) + } +} + +impl PartialEq for Structure { + fn eq(&self, other: &StructureRef) -> bool { + self.as_ref().eq(other) + } +} + +impl Eq for Structure {} + +impl Borrow for Structure { + fn borrow(&self) -> &StructureRef { + unsafe { &*self.0 } + } +} + +impl BorrowMut for Structure { + fn borrow_mut(&mut self) -> &mut StructureRef { + unsafe { &mut *self.0 } + } +} + +impl ToOwned for StructureRef { + type Owned = Structure; + + fn to_owned(&self) -> Structure { + Structure( + unsafe { ffi::gst_structure_copy(&self.0) as *mut StructureRef }, + PhantomData, + false, + ) + } +} + +impl<'a> ToGlibPtr<'a, *const ffi::GstStructure> for Structure { + type Storage = &'a Self; + + fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstStructure, Self> { + Stash(unsafe { &(*self.0).0 }, self) + } + + fn to_glib_full(&self) -> *const ffi::GstStructure { + unsafe { + ffi::gst_structure_copy(&(*self.0).0) + } + } +} + +impl<'a> ToGlibPtr<'a, *mut ffi::GstStructure> for Structure { + type Storage = &'a Self; + + fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstStructure, Self> { + Stash(unsafe { &mut (*self.0).0 }, self) + } + + fn to_glib_full(&self) -> *mut ffi::GstStructure { + unsafe { + ffi::gst_structure_copy(&(*self.0).0) + } + } +} + +impl<'a> ToGlibPtrMut<'a, *mut ffi::GstStructure> for Structure { + type Storage = &'a mut Self; + + fn to_glib_none_mut(&'a mut self) -> StashMut<*mut ffi::GstStructure, Self> { + StashMut(unsafe { &mut (*self.0).0 }, self) + } +} + +impl FromGlibPtrNone<*const ffi::GstStructure> for Structure { + unsafe fn from_glib_none(ptr: *const ffi::GstStructure) -> Self { + Structure( + ffi::gst_structure_copy(ptr) as *mut StructureRef, + PhantomData, + false, + ) + } +} + +impl FromGlibPtrNone<*mut ffi::GstStructure> for Structure { + unsafe fn from_glib_none(ptr: *mut ffi::GstStructure) -> Self { + Structure( + ffi::gst_structure_copy(ptr) as *mut StructureRef, + PhantomData, + false, + ) + } +} + +impl FromGlibPtrFull<*const ffi::GstStructure> for Structure { + unsafe fn from_glib_full(ptr: *const ffi::GstStructure) -> Self { + Structure( + ptr as *mut StructureRef, + PhantomData, + false, + ) + } +} + +impl FromGlibPtrFull<*mut ffi::GstStructure> for Structure { + unsafe fn from_glib_full(ptr: *mut ffi::GstStructure) -> Self { + Structure( + ptr as *mut StructureRef, + PhantomData, + false, + ) + } +} + +impl FromGlibPtrBorrow<*const ffi::GstStructure> for Structure { + unsafe fn from_glib_borrow(ptr: *const ffi::GstStructure) -> Self { + Structure( + ptr as *mut StructureRef, + PhantomData, + true, + ) + } +} + +impl FromGlibPtrBorrow<*mut ffi::GstStructure> for Structure { + unsafe fn from_glib_borrow(ptr: *mut ffi::GstStructure) -> Self { + Structure( + ptr as *mut StructureRef, + PhantomData, + true, + ) + } +} + +#[repr(C)] +pub struct StructureRef(ffi::GstStructure); + +impl StructureRef { + pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstStructure) -> &'a StructureRef { + assert!(!ptr.is_null()); + + &*(ptr as *mut StructureRef) + } + + pub unsafe fn from_glib_borrow_mut<'a>(ptr: *mut ffi::GstStructure) -> &'a mut StructureRef { + assert!(!ptr.is_null()); + + &mut *(ptr as *mut StructureRef) + } + + pub fn to_string(&self) -> String { + unsafe { + from_glib_full(ffi::gst_structure_to_string(&self.0)) + } + } + + pub fn get<'a, T: FromValueOptional<'a>>(&'a self, name: &str) -> Option { + self.get_value(name).and_then(|v| v.get()) + } + + pub fn get_value<'a>(&'a self, name: &str) -> Option<&Value> { + unsafe { + let name_cstr = CString::new(name).unwrap(); + + let value = ffi::gst_structure_get_value(&self.0, name_cstr.as_ptr()); + + if value.is_null() { + return None; + } + + Some(&*(value as *const Value)) + } + } + + pub fn set(&mut self, name: &str, value: T) { + let value = value.to_value(); + self.set_value(name, value); + } + + pub fn set_value(&mut self, name: &str, mut value: Value) { + unsafe { + let name_cstr = CString::new(name).unwrap(); + ffi::gst_structure_take_value(&mut self.0, name_cstr.as_ptr(), value.to_glib_none_mut().0); + mem::forget(value); + } + } + + pub fn get_name(&self) -> &str { + unsafe { + CStr::from_ptr(ffi::gst_structure_get_name(&self.0)).to_str().unwrap() + } + } + + pub fn has_field(&self, field: &str) -> bool { + unsafe { + from_glib(ffi::gst_structure_has_field(&self.0, field.to_glib_none().0)) + } + } + + pub fn remove_field(&mut self, field: &str) { + unsafe { + ffi::gst_structure_remove_field(&mut self.0, field.to_glib_none().0); + } + } + + pub fn remove_all_fields(&mut self) { + unsafe { + ffi::gst_structure_remove_all_fields(&mut self.0); + } + } + + pub fn fields(&self) -> FieldIterator { + FieldIterator::new(self) + } + + pub fn iter(&self) -> Iter { + Iter::new(self) + } + + fn get_nth_field_name(&self, idx: u32) -> Option<&str> { + unsafe { + let field_name = ffi::gst_structure_nth_field_name(&self.0, idx); + if field_name.is_null() { + return None; + } + + Some(CStr::from_ptr(field_name).to_str().unwrap()) + } + } + + fn n_fields(&self) -> u32 { + unsafe { ffi::gst_structure_n_fields(&self.0) as u32 } + } + + // TODO: Various operations +} + +impl fmt::Debug for StructureRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.to_string()) + } +} + +impl PartialEq for StructureRef { + fn eq(&self, other: &StructureRef) -> bool { + unsafe { from_glib(ffi::gst_structure_is_equal(&self.0, &other.0)) } + } +} + +impl Eq for StructureRef {} + +pub struct FieldIterator<'a> { + structure: &'a StructureRef, + idx: u32, + n_fields: u32, +} + +impl<'a> FieldIterator<'a> { + pub fn new(structure: &'a StructureRef) -> FieldIterator<'a> { + let n_fields = structure.n_fields(); + + FieldIterator { + structure: structure, + idx: 0, + n_fields: n_fields, + } + } +} + +impl<'a> Iterator for FieldIterator<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + if self.idx >= self.n_fields { + return None; + } + + if let Some(field_name) = self.structure.get_nth_field_name(self.idx) { + self.idx += 1; + Some(field_name) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.idx == self.n_fields { + return (0, Some(0)); + } + + let remaining = (self.n_fields - self.idx) as usize; + + (remaining, Some(remaining)) + } +} + +impl<'a> DoubleEndedIterator for FieldIterator<'a> { + fn next_back(&mut self) -> Option { + if self.idx == self.n_fields { + return None; + } + + self.n_fields -= 1; + if let Some(field_name) = self.structure.get_nth_field_name(self.n_fields) { + Some(field_name) + } else { + None + } + } +} + +impl<'a> ExactSizeIterator for FieldIterator<'a> {} + +pub struct Iter<'a> { + iter: FieldIterator<'a>, +} + +impl<'a> Iter<'a> { + pub fn new(structure: &'a StructureRef) -> Iter<'a> { + Iter { iter: FieldIterator::new(structure) } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = (&'a str, &'a Value); + + fn next(&mut self) -> Option<(&'a str, &'a Value)> { + if let Some(f) = self.iter.next() { + let v = self.iter.structure.get_value(f); + Some((f, v.unwrap())) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> DoubleEndedIterator for Iter<'a> { + fn next_back(&mut self) -> Option { + if let Some(f) = self.iter.next_back() { + let v = self.iter.structure.get_value(f); + Some((f, v.unwrap())) + } else { + None + } + } +} + +impl<'a> ExactSizeIterator for Iter<'a> {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn new_set_get() { + ::init().unwrap(); + + let mut s = Structure::new_empty("test"); + assert_eq!(s.get_name(), "test"); + + s.set("f1", "abc"); + s.set("f2", String::from("bcd")); + s.set("f3", 123i32); + + assert_eq!(s.get::<&str>("f1").unwrap(), "abc"); + assert_eq!(s.get::<&str>("f2").unwrap(), "bcd"); + assert_eq!(s.get::("f3").unwrap(), 123i32); + + assert_eq!(s.fields().collect::>(), vec!["f1", "f2", "f3"]); + /* + assert_eq!( + s.iter() + .map(|(f, v)| (f, v.clone())) + .collect::>(), + vec![ + ("f1", "abc".into()), + ("f2","bcd".into()), + ("f3", 123i32.into()), + ] + ); + + let s2 = Structure::new( + "test", + &[ + ("f1", "abc".into()), + ("f2", "bcd".into()), + ("f3", 123i32.into()), + ], + ); + assert_eq!(s, s2); +*/ + } +}