diff --git a/gst-gir-files b/gst-gir-files index ae0d1447f..8dd059f42 160000 --- a/gst-gir-files +++ b/gst-gir-files @@ -1 +1 @@ -Subproject commit ae0d1447f5204ddf882ff08d2163b299db5da228 +Subproject commit 8dd059f42a8da104b53baf82bf5f5d2596176627 diff --git a/gstreamer-validate/Cargo.toml b/gstreamer-validate/Cargo.toml index ed944492d..d49724d79 100644 --- a/gstreamer-validate/Cargo.toml +++ b/gstreamer-validate/Cargo.toml @@ -22,6 +22,7 @@ bitflags = "1.0" [dev-dependencies] gir-format-check = "0.1" +tempfile = "3" [features] default = [] diff --git a/gstreamer-validate/Gir.toml b/gstreamer-validate/Gir.toml index aadefd7f4..fa744503f 100644 --- a/gstreamer-validate/Gir.toml +++ b/gstreamer-validate/Gir.toml @@ -17,7 +17,6 @@ external_libraries = [ ] generate = [ - "GstValidate.Action", "GstValidate.Reporter", "GstValidate.BinMonitor", "GstValidate.Monitor", @@ -31,6 +30,8 @@ generate = [ "GstValidate.ReportLevel", "GstValidate.IssueFlags", "GstValidate.IssueId", + "GstValidate.ActionTypeFlags", + "GstValidate.ActionType", ] manual = [ @@ -48,6 +49,7 @@ manual = [ "Gst.Format", "Gst.SeekFlags", "Gst.SeekType", + "GstValidate.Action", ] [[object]] diff --git a/gstreamer-validate/src/action.rs b/gstreamer-validate/src/action.rs new file mode 100644 index 000000000..802340e95 --- /dev/null +++ b/gstreamer-validate/src/action.rs @@ -0,0 +1,65 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::prelude::*; +use glib::translate::*; + +use crate::ActionType; +use crate::Scenario; + +gst::mini_object_wrapper!(Action, ActionRef, ffi::GstValidateAction, || { + ffi::gst_validate_action_get_type() +}); + +impl ActionRef { + pub fn structure(&self) -> &gst::StructureRef { + unsafe { + let action = &self.0 as *const ffi::GstValidateAction; + + gst::StructureRef::from_glib_borrow((*action).structure) + } + } + + pub fn structure_mut(&mut self) -> &mut gst::StructureRef { + unsafe { + let action = &mut self.0 as *mut ffi::GstValidateAction; + + gst::StructureRef::from_glib_borrow_mut((*action).structure) + } + } +} + +impl Action { + #[doc(alias = "gst_validate_action_new")] + pub fn new( + scenario: Option<&impl IsA>, + action_type: &ActionType, + structure: &gst::StructureRef, + add_to_lists: bool, + ) -> Action { + assert_initialized_main_thread!(); + unsafe { + from_glib_full(ffi::gst_validate_action_new( + scenario.map(|p| p.as_ref()).to_glib_none().0, + action_type.to_glib_none().0, + structure.as_mut_ptr(), + add_to_lists.into_glib(), + )) + } + } + + #[doc(alias = "gst_validate_execute_action")] + pub fn execute(&self) -> Result { + unsafe { + let action: *mut ffi::GstValidateAction = self.to_glib_none().0; + let action_type = ffi::gst_validate_get_action_type((*action).type_); + + let res = ffi::gst_validate_execute_action(action_type, action); + + if let Some(v) = crate::ActionSuccess::from_value(res) { + Ok(v) + } else { + Err(crate::ActionError::from_value(res)) + } + } + } +} diff --git a/gstreamer-validate/src/action_type.rs b/gstreamer-validate/src/action_type.rs new file mode 100644 index 000000000..55effae62 --- /dev/null +++ b/gstreamer-validate/src/action_type.rs @@ -0,0 +1,318 @@ +use std::{ffi::c_int, ptr}; + +use glib::once_cell::sync::Lazy; +use glib::translate::*; + +static QUARK_ACTION_TYPE_FUNC: Lazy = + Lazy::new(|| glib::Quark::from_str("rs-action-type-function")); + +#[derive(Debug)] +#[repr(transparent)] +#[doc(alias = "GstValidateActionParameter")] +pub struct ActionParameter(pub(crate) ffi::GstValidateActionParameter); +impl Drop for ActionParameter { + fn drop(&mut self) { + unsafe { + if let Some(free_fn) = self.0.free { + (free_fn)(self as *const _ as glib::ffi::gpointer); + } + } + } +} + +fn into_glib_content(mut t: Vec) -> *mut ffi::GstValidateActionParameter { + assert_initialized_main_thread!(); + if t.is_empty() { + return ptr::null_mut(); + } + + unsafe { + let size = std::mem::size_of::() * (t.len() + 1); + let v_ptr = glib::ffi::g_malloc0(size) as *mut ffi::GstValidateActionParameter; + + ptr::copy_nonoverlapping( + t.as_ptr() as *const ffi::GstValidateActionParameter, + v_ptr, + t.len(), + ); + + // C side is owning the memory now + t.set_len(0); + + v_ptr + } +} + +unsafe extern "C" fn action_parameter_free(param: glib::ffi::gpointer) { + let param = param as *mut ffi::GstValidateActionParameter; + + glib::ffi::g_free((*param).name as *mut _); + glib::ffi::g_free((*param).description as *mut _); + glib::ffi::g_free((*param).def as *mut _); + glib::ffi::g_free((*param).possible_variables as *mut _); + glib::ffi::g_free((*param).types as *mut _); +} + +pub struct ActionParameterBuilder<'a> { + name: &'a str, + description: &'a str, + possible_variables: Vec, + mandatory: bool, + default_value: Option<&'a str>, + types: Vec, +} + +impl<'a> ActionParameterBuilder<'a> { + pub fn new(name: &'a str, description: &'a str) -> Self { + assert_initialized_main_thread!(); + + Self { + name, + description, + possible_variables: Default::default(), + mandatory: false, + default_value: None, + types: Default::default(), + } + } + + // rustdoc-stripper-ignore-next + /// The name of the variables that can be used to compute the value of the + /// parameter. For example for the start value of a seek action, we will + /// accept to take 'duration' which will be replace by the total duration of + /// the stream on which the action is executed. + pub fn add_possible_variable(mut self, possible_variables: &str) -> Self { + self.possible_variables.push(possible_variables.to_owned()); + self + } + + pub fn mandatory(mut self) -> Self { + self.mandatory = true; + self + } + + pub fn default_value(mut self, default_value: &'a str) -> Self { + self.default_value = Some(default_value); + self + } + + // rustdoc-stripper-ignore-next + /// The types the parameter can take described as a string. + /// + /// NOTE: The types should end with `(GstClockTime)` if + /// its final type is a GstClockTime, this way it will be processed when + /// preparing the actions. + pub fn add_type(mut self, types: &str) -> Self { + self.types.push(types.to_owned()); + self + } + + pub fn build(self) -> ActionParameter { + let types = if self.types.is_empty() { + ptr::null() + } else { + self.types.join("\n").to_glib_full() + }; + let possible_variables = if self.possible_variables.is_empty() { + ptr::null() + } else { + self.possible_variables.join("\n").to_glib_full() + }; + ActionParameter(ffi::GstValidateActionParameter { + name: self.name.to_glib_full(), + description: self.description.to_glib_full(), + mandatory: self.mandatory.into_glib(), + def: self.default_value.to_glib_full(), + possible_variables, + types, + free: Some(action_parameter_free), + _gst_reserved: [ptr::null_mut(); 3], + }) + } +} + +type ActionFunction = dyn Fn(&crate::Scenario, &mut crate::ActionRef) -> Result + + Sync + + Send + + 'static; + +unsafe extern "C" fn destroy_notify(ptr: glib::ffi::gpointer) { + let _ = Box::from_raw(ptr as *mut Box); +} + +pub struct ActionTypeBuilder<'a> { + type_name: &'a str, + implementer_namespace: Option<&'a str>, + description: Option<&'a str>, + parameters: Vec, + flags: crate::ActionTypeFlags, + function: Box, +} + +impl<'a> ActionTypeBuilder<'a> { + pub fn new< + F: Fn( + &crate::Scenario, + &mut crate::ActionRef, + ) -> Result + + Send + + Sync + + 'static, + >( + type_name: &'a str, + func: F, + ) -> Self { + Self { + type_name, + implementer_namespace: None, + description: None, + parameters: Vec::new(), + flags: crate::ActionTypeFlags::empty(), + function: Box::new(func), + } + } + + pub fn implementer_namespace(mut self, implementer_namespace: &'a str) -> Self { + self.implementer_namespace = Some(implementer_namespace); + self + } + + pub fn description(mut self, description: &'a str) -> Self { + self.description = Some(description); + self + } + + pub fn parameter(mut self, parameter: ActionParameter) -> Self { + self.parameters.push(parameter); + self + } + + pub fn flags(mut self, flags: crate::ActionTypeFlags) -> Self { + self.flags |= flags; + self + } + + pub fn build(self) -> crate::ActionType { + unsafe extern "C" fn execute_func_trampoline( + scenario: *mut ffi::GstValidateScenario, + action: *mut ffi::GstValidateAction, + ) -> c_int { + let action_type = ffi::gst_validate_get_action_type((*action).type_); + let scenario = from_glib_borrow(scenario); + let action = crate::ActionRef::from_mut_ptr(action as *mut ffi::GstValidateAction); + + let func: &ActionFunction = &*(gst::ffi::gst_mini_object_get_qdata( + action_type as *mut gst::ffi::GstMiniObject, + QUARK_ACTION_TYPE_FUNC.into_glib(), + ) as *const Box); + + (*func)(&scenario, action).into_glib() + } + + unsafe { + let params = into_glib_content(self.parameters); + let action_type = ffi::gst_validate_register_action_type( + self.type_name.to_glib_none().0, + self.implementer_namespace + .unwrap_or("validaters") + .to_glib_none() + .0, + Some(execute_func_trampoline), + params, + self.description.to_glib_none().0, + self.flags.into_glib(), + ); + + // gst_validate_register_action_type() takes ownership of the content + // of the params array but not of the container itself so we need to + // free it manually. + glib::ffi::g_free(params as *mut _); + + let f = self.function; + + gst::ffi::gst_mini_object_set_qdata( + action_type as *mut gst::ffi::GstMiniObject, + QUARK_ACTION_TYPE_FUNC.into_glib(), + Box::into_raw(Box::new(f)) as *mut _, + Some(destroy_notify), + ); + + from_glib_none(action_type) + } + } +} + +#[cfg(test)] +mod tests { + use std::{ + io::Write, + sync::{Arc, Mutex}, + }; + + #[test] + fn test_action_types() { + gst::init().unwrap(); + crate::init(); + + let failling_action_type = crate::ActionTypeBuilder::new("fails", |_, action| { + action.structure_mut().set("called", true); + + Err(crate::ActionError::Error) + }) + .build(); + + let called = Arc::new(Mutex::new(false)); + let succeeding_action_type = crate::ActionTypeBuilder::new( + "succeeds", + glib::clone!(@strong called => move |_, _action| { + *called.lock().unwrap() = true; + + Ok(crate::ActionSuccess::Ok) + }), + ) + .parameter( + crate::ActionParameterBuilder::new("always", "Does the action always succeeds") + .add_type("boolean") + .default_value("true") + .build(), + ) + .build(); + + // Write scenario to temporary file + let mut file = tempfile::NamedTempFile::new().unwrap(); + file.write_all(b"succeeds").unwrap(); + + let runner = crate::Runner::new(); + let pipeline = gst::Pipeline::new(None); + let scenario = + crate::Scenario::factory_create(&runner, &pipeline, file.path().to_str().unwrap()) + .unwrap(); + + let action = crate::Action::new( + Some(&scenario), + &succeeding_action_type, + gst::Structure::builder("succeeds").build().as_ref(), + false, + ); + + assert!(!*called.lock().unwrap()); + action.execute().expect("Failed to execute action"); + assert!(*called.lock().unwrap()); + + let action = crate::Action::new( + Some(&scenario), + &failling_action_type, + gst::Structure::builder("fails").build().as_ref(), + false, + ); + + assert!(action.structure().get::("called").is_err()); + action.execute().expect_err("Action should have failed"); + assert_eq!(action.structure().get::("called"), Ok(true)); + + crate::ActionParameterBuilder::new("unused", "Verify unused param are properly cleaned") + .default_value("true") + .add_possible_variable("position") + .build(); + } +} diff --git a/gstreamer-validate/src/auto/action.rs b/gstreamer-validate/src/auto/action.rs deleted file mode 100644 index 45b5b2922..000000000 --- a/gstreamer-validate/src/auto/action.rs +++ /dev/null @@ -1,47 +0,0 @@ -// This file was generated by gir (https://github.com/gtk-rs/gir) -// from gir-files (https://github.com/gtk-rs/gir-files) -// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) -// DO NOT EDIT - -use crate::Scenario; -use glib::translate::*; - -glib::wrapper! { - #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Action(Shared); - - match fn { - ref => |ptr| ffi::gst_validate_action_ref(ptr), - unref => |ptr| ffi::gst_validate_action_unref(ptr), - type_ => || ffi::gst_validate_action_get_type(), - } -} - -impl Action { - //#[doc(alias = "gst_validate_action_new")] - //pub fn new(scenario: Option<&impl IsA>, action_type: /*Ignored*/&mut ActionType, structure: &mut gst::Structure, add_to_lists: bool) -> Action { - // unsafe { TODO: call ffi:gst_validate_action_new() } - //} - - #[doc(alias = "gst_validate_action_get_scenario")] - #[doc(alias = "get_scenario")] - pub fn scenario(&self) -> Option { - unsafe { from_glib_full(ffi::gst_validate_action_get_scenario(self.to_glib_none().0)) } - } - - #[doc(alias = "gst_validate_action_set_done")] - pub fn set_done(&self) { - unsafe { - ffi::gst_validate_action_set_done(self.to_glib_none().0); - } - } - - //#[doc(alias = "gst_validate_action_get_clocktime")] - //#[doc(alias = "get_clocktime")] - //pub fn clocktime(scenario: &impl IsA, action: &Action, name: &str) -> Option { - // unsafe { TODO: call ffi:gst_validate_action_get_clocktime() } - //} -} - -unsafe impl Send for Action {} -unsafe impl Sync for Action {} diff --git a/gstreamer-validate/src/auto/action_type.rs b/gstreamer-validate/src/auto/action_type.rs new file mode 100644 index 000000000..8051325e4 --- /dev/null +++ b/gstreamer-validate/src/auto/action_type.rs @@ -0,0 +1,18 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) +// DO NOT EDIT + +glib::wrapper! { + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct ActionType(Boxed); + + match fn { + copy => |ptr| glib::gobject_ffi::g_boxed_copy(ffi::gst_validate_action_type_get_type(), ptr as *mut _) as *mut ffi::GstValidateActionType, + free => |ptr| glib::gobject_ffi::g_boxed_free(ffi::gst_validate_action_type_get_type(), ptr as *mut _), + type_ => || ffi::gst_validate_action_type_get_type(), + } +} + +unsafe impl Send for ActionType {} +unsafe impl Sync for ActionType {} diff --git a/gstreamer-validate/src/auto/flags.rs b/gstreamer-validate/src/auto/flags.rs index c202d83bf..eb4d56a84 100644 --- a/gstreamer-validate/src/auto/flags.rs +++ b/gstreamer-validate/src/auto/flags.rs @@ -6,6 +6,110 @@ use bitflags::bitflags; use glib::{translate::*, value::FromValue, value::ToValue, StaticType, Type}; +bitflags! { + #[doc(alias = "GstValidateActionTypeFlags")] + pub struct ActionTypeFlags: u32 { + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_NONE")] + const NONE = ffi::GST_VALIDATE_ACTION_TYPE_NONE as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_CONFIG")] + const CONFIG = ffi::GST_VALIDATE_ACTION_TYPE_CONFIG as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_ASYNC")] + const ASYNC = ffi::GST_VALIDATE_ACTION_TYPE_ASYNC as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_NON_BLOCKING")] + const NON_BLOCKING = ffi::GST_VALIDATE_ACTION_TYPE_NON_BLOCKING as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_INTERLACED")] + const INTERLACED = ffi::GST_VALIDATE_ACTION_TYPE_INTERLACED as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION")] + const CAN_EXECUTE_ON_ADDITION = ffi::GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK")] + const NEEDS_CLOCK = ffi::GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL")] + const NO_EXECUTION_NOT_FATAL = ffi::GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL")] + const CAN_BE_OPTIONAL = ffi::GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE")] + const DOESNT_NEED_PIPELINE = ffi::GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG")] + const HANDLED_IN_CONFIG = ffi::GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG as _; + #[doc(alias = "GST_VALIDATE_ACTION_TYPE_CHECK")] + const CHECK = ffi::GST_VALIDATE_ACTION_TYPE_CHECK as _; + } +} + +#[doc(hidden)] +impl IntoGlib for ActionTypeFlags { + type GlibType = ffi::GstValidateActionTypeFlags; + + #[inline] + fn into_glib(self) -> ffi::GstValidateActionTypeFlags { + self.bits() + } +} + +#[doc(hidden)] +impl FromGlib for ActionTypeFlags { + #[inline] + unsafe fn from_glib(value: ffi::GstValidateActionTypeFlags) -> Self { + skip_assert_initialized!(); + Self::from_bits_truncate(value) + } +} + +impl StaticType for ActionTypeFlags { + #[inline] + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_validate_action_type_flags_get_type()) } + } +} + +impl glib::HasParamSpec for ActionTypeFlags { + type ParamSpec = glib::ParamSpecFlags; + type SetValue = Self; + type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; + + fn param_spec_builder() -> Self::BuilderFn { + |name| Self::ParamSpec::builder(name) + } +} + +impl glib::value::ValueType for ActionTypeFlags { + type Type = Self; +} + +unsafe impl<'a> FromValue<'a> for ActionTypeFlags { + type Checker = glib::value::GenericValueTypeChecker; + + #[inline] + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) + } +} + +impl ToValue for ActionTypeFlags { + #[inline] + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + #[inline] + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +impl From for glib::Value { + #[inline] + fn from(v: ActionTypeFlags) -> Self { + skip_assert_initialized!(); + ToValue::to_value(&v) + } +} + bitflags! { #[doc(alias = "GstValidateIssueFlags")] pub struct IssueFlags: u32 { diff --git a/gstreamer-validate/src/auto/mod.rs b/gstreamer-validate/src/auto/mod.rs index a9b80d27e..a7c43d788 100644 --- a/gstreamer-validate/src/auto/mod.rs +++ b/gstreamer-validate/src/auto/mod.rs @@ -27,8 +27,8 @@ pub use self::runner::Runner; mod scenario; pub use self::scenario::Scenario; -mod action; -pub use self::action::Action; +mod action_type; +pub use self::action_type::ActionType; mod issue; pub use self::issue::Issue; @@ -41,6 +41,7 @@ pub use self::enums::ReportLevel; pub use self::enums::ReportingDetails; mod flags; +pub use self::flags::ActionTypeFlags; pub use self::flags::IssueFlags; mod alias; diff --git a/gstreamer-validate/src/enums.rs b/gstreamer-validate/src/enums.rs new file mode 100644 index 000000000..2a71a1975 --- /dev/null +++ b/gstreamer-validate/src/enums.rs @@ -0,0 +1,149 @@ +use glib::translate::*; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[repr(i32)] +pub enum ActionSuccess { + Ok = ffi::GST_VALIDATE_EXECUTE_ACTION_OK, + Async = ffi::GST_VALIDATE_EXECUTE_ACTION_ASYNC, + NonBlocking = ffi::GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING, + InProgress = ffi::GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS, + Done = ffi::GST_VALIDATE_EXECUTE_ACTION_DONE, +} + +impl ActionSuccess { + pub fn from_value(value: impl Into) -> Option { + skip_assert_initialized!(); + Some(match value.into() { + ffi::GST_VALIDATE_EXECUTE_ACTION_OK => ActionSuccess::Ok, + ffi::GST_VALIDATE_EXECUTE_ACTION_ASYNC => ActionSuccess::Async, + ffi::GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING => ActionSuccess::NonBlocking, + ffi::GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS => ActionSuccess::InProgress, + ffi::GST_VALIDATE_EXECUTE_ACTION_DONE => ActionSuccess::Done, + _ => return None, + }) + } +} + +impl IntoGlib for ActionSuccess { + type GlibType = ffi::GstValidateActionReturn; + + #[inline] + fn into_glib(self) -> ffi::GstValidateActionReturn { + skip_assert_initialized!(); + self as ffi::GstValidateActionReturn + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[repr(i32)] +pub enum ActionError { + Error = ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR, + ErrorReported = ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, + None = ffi::GST_VALIDATE_EXECUTE_ACTION_NONE, +} + +impl ActionError { + pub fn from_value(value: impl Into) -> Self { + skip_assert_initialized!(); + match value.into() { + ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR => ActionError::Error, + ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED => ActionError::ErrorReported, + ffi::GST_VALIDATE_EXECUTE_ACTION_NONE => ActionError::None, + _ => ActionError::Error, + } + } +} + +impl IntoGlib for ActionError { + type GlibType = ffi::GstValidateActionReturn; + + #[inline] + fn into_glib(self) -> ffi::GstValidateActionReturn { + self as ffi::GstValidateActionReturn + } +} + +#[must_use] +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[doc(alias = "GstValidateActionReturn")] +#[repr(i32)] +pub enum ActionReturn { + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_ERROR")] + Error = ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR, + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_OK")] + Ok = ffi::GST_VALIDATE_EXECUTE_ACTION_OK, + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_ASYNC")] + Async = ffi::GST_VALIDATE_EXECUTE_ACTION_ASYNC, + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING")] + NonBlocking = ffi::GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING, + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED")] + ErrorReported = ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS")] + InProgress = ffi::GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS, + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_NONE")] + None = ffi::GST_VALIDATE_EXECUTE_ACTION_NONE, + #[doc(alias = "GST_VALIDATE_EXECUTE_ACTION_DONE")] + Done = ffi::GST_VALIDATE_EXECUTE_ACTION_DONE, +} + +#[doc(hidden)] +impl IntoGlib for ActionReturn { + type GlibType = ffi::GstValidateActionReturn; + + #[inline] + fn into_glib(self) -> ffi::GstValidateActionReturn { + self as ffi::GstValidateActionReturn + } +} + +#[doc(hidden)] +impl FromGlib for ActionReturn { + #[inline] + unsafe fn from_glib(value: ffi::GstValidateActionReturn) -> Self { + skip_assert_initialized!(); + + if !(ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR..=ffi::GST_VALIDATE_EXECUTE_ACTION_DONE) + .contains(&value) + { + ActionReturn::Error + } else { + std::mem::transmute(value) + } + } +} + +impl TryFromGlib for ActionSuccess { + type Error = ActionError; + + #[inline] + unsafe fn try_from_glib( + val: ffi::GstValidateActionReturn, + ) -> Result { + skip_assert_initialized!(); + ActionReturn::from_glib(val).into_result() + } +} + +impl ActionReturn { + #[inline] + pub fn into_result(self) -> Result { + match self { + Self::Error | Self::ErrorReported | Self::None => { + Err(unsafe { std::mem::transmute(self) }) + } + _ => Ok(unsafe { std::mem::transmute(self) }), + } + } + + #[inline] + pub fn from_error(v: ActionError) -> Self { + skip_assert_initialized!(); + unsafe { std::mem::transmute(v) } + } + + #[inline] + pub fn from_ok(v: ActionSuccess) -> Self { + skip_assert_initialized!(); + unsafe { std::mem::transmute(v) } + } +} diff --git a/gstreamer-validate/src/functions.rs b/gstreamer-validate/src/functions.rs index 772ed4927..f8636530d 100644 --- a/gstreamer-validate/src/functions.rs +++ b/gstreamer-validate/src/functions.rs @@ -31,7 +31,6 @@ pub fn setup_test_file(test_file: &str, use_fakesinks: bool) -> gst::Structure { #[cfg(test)] mod tests { - #[test] fn test_init() { gst::init().unwrap(); diff --git a/gstreamer-validate/src/lib.rs b/gstreamer-validate/src/lib.rs index 60bd8c2c9..3934a6bf3 100644 --- a/gstreamer-validate/src/lib.rs +++ b/gstreamer-validate/src/lib.rs @@ -41,6 +41,15 @@ pub use crate::auto::*; mod functions; pub use functions::*; +mod action_type; +pub use action_type::*; + +mod enums; +pub use enums::*; + +mod action; +pub use action::{Action, ActionRef}; + // Re-export all the traits in a prelude module, so that applications // can always "use gst_validate::prelude::*" without getting conflicts pub mod prelude {