1use std::{ffi::c_int, ptr};
4
5use crate::{ffi, Action};
6use glib::translate::*;
7
8#[derive(Debug)]
9#[repr(transparent)]
10#[doc(alias = "GstValidateActionParameter")]
11pub struct ActionParameter(pub(crate) ffi::GstValidateActionParameter);
12impl Drop for ActionParameter {
13 fn drop(&mut self) {
14 unsafe {
15 if let Some(free_fn) = self.0.free {
16 (free_fn)(self as *const _ as glib::ffi::gpointer);
17 }
18 }
19 }
20}
21
22fn into_glib_content(mut t: Vec<ActionParameter>) -> *mut ffi::GstValidateActionParameter {
23 assert_initialized_main_thread!();
24 if t.is_empty() {
25 return ptr::null_mut();
26 }
27
28 unsafe {
29 let size = std::mem::size_of::<ffi::GstValidateActionParameter>() * (t.len() + 1);
30 let v_ptr = glib::ffi::g_malloc0(size) as *mut ffi::GstValidateActionParameter;
31
32 ptr::copy_nonoverlapping(
33 t.as_ptr() as *const ffi::GstValidateActionParameter,
34 v_ptr,
35 t.len(),
36 );
37
38 t.set_len(0);
40
41 v_ptr
42 }
43}
44
45unsafe extern "C" fn action_parameter_free(param: glib::ffi::gpointer) {
46 let param = param as *mut ffi::GstValidateActionParameter;
47
48 glib::ffi::g_free((*param).name as *mut _);
49 glib::ffi::g_free((*param).description as *mut _);
50 glib::ffi::g_free((*param).def as *mut _);
51 glib::ffi::g_free((*param).possible_variables as *mut _);
52 glib::ffi::g_free((*param).types as *mut _);
53}
54
55pub struct ActionParameterBuilder<'a> {
56 name: &'a str,
57 description: &'a str,
58 possible_variables: Vec<String>,
59 mandatory: bool,
60 default_value: Option<&'a str>,
61 types: Vec<String>,
62}
63
64impl<'a> ActionParameterBuilder<'a> {
65 pub fn new(name: &'a str, description: &'a str) -> Self {
66 assert_initialized_main_thread!();
67
68 Self {
69 name,
70 description,
71 possible_variables: Default::default(),
72 mandatory: false,
73 default_value: None,
74 types: Default::default(),
75 }
76 }
77
78 pub fn add_possible_variable(mut self, possible_variable: &str) -> Self {
84 self.possible_variables.push(possible_variable.to_owned());
85 self
86 }
87
88 pub fn add_possible_variable_if(self, possible_variable: &str, predicate: bool) -> Self {
89 if predicate {
90 self.add_possible_variable(possible_variable)
91 } else {
92 self
93 }
94 }
95
96 pub fn add_possible_variable_if_some(self, possible_variable: Option<&str>) -> Self {
97 if let Some(possible_variable) = possible_variable {
98 self.add_possible_variable(possible_variable)
99 } else {
100 self
101 }
102 }
103
104 pub fn mandatory(mut self) -> Self {
105 self.mandatory = true;
106 self
107 }
108
109 pub fn default_value(mut self, default_value: &'a str) -> Self {
110 self.default_value = Some(default_value);
111 self
112 }
113
114 pub fn default_value_if(self, default_value: &'a str, predicate: bool) -> Self {
115 if predicate {
116 self.default_value(default_value)
117 } else {
118 self
119 }
120 }
121
122 pub fn default_value_if_some(self, default_value: Option<&'a str>) -> Self {
123 if let Some(default_value) = default_value {
124 self.default_value(default_value)
125 } else {
126 self
127 }
128 }
129
130 pub fn add_type(mut self, types: &str) -> Self {
137 self.types.push(types.to_owned());
138 self
139 }
140
141 pub fn add_type_if(self, types: &str, predicate: bool) -> Self {
142 if predicate {
143 self.add_type(types)
144 } else {
145 self
146 }
147 }
148
149 pub fn add_type_if_some(self, types: Option<&str>) -> Self {
150 if let Some(types) = types {
151 self.add_type(types)
152 } else {
153 self
154 }
155 }
156
157 pub fn build(self) -> ActionParameter {
158 let types = if self.types.is_empty() {
159 ptr::null()
160 } else {
161 self.types.join("\n").to_glib_full()
162 };
163 let possible_variables = if self.possible_variables.is_empty() {
164 ptr::null()
165 } else {
166 self.possible_variables.join("\n").to_glib_full()
167 };
168 ActionParameter(ffi::GstValidateActionParameter {
169 name: self.name.to_glib_full(),
170 description: self.description.to_glib_full(),
171 mandatory: self.mandatory.into_glib(),
172 def: self.default_value.to_glib_full(),
173 possible_variables,
174 types,
175 free: Some(action_parameter_free),
176 _gst_reserved: [ptr::null_mut(); 3],
177 })
178 }
179}
180
181type ActionFunction = dyn Fn(&crate::Scenario, &mut crate::Action) -> Result<crate::ActionSuccess, crate::ActionError>
182 + Sync
183 + Send
184 + 'static;
185
186unsafe extern "C" fn destroy_notify(ptr: glib::ffi::gpointer) {
187 let _ = Box::from_raw(ptr as *mut Box<ActionFunction>);
188}
189
190pub struct ActionTypeBuilder<'a> {
191 type_name: &'a str,
192 implementer_namespace: Option<&'a str>,
193 description: Option<&'a str>,
194 parameters: Vec<ActionParameter>,
195 flags: crate::ActionTypeFlags,
196 function: Box<ActionFunction>,
197}
198
199impl<'a> ActionTypeBuilder<'a> {
200 pub fn new<
201 F: Fn(
202 &crate::Scenario,
203 &mut crate::Action,
204 ) -> Result<crate::ActionSuccess, crate::ActionError>
205 + Send
206 + Sync
207 + 'static,
208 >(
209 type_name: &'a str,
210 func: F,
211 ) -> Self {
212 Self {
213 type_name,
214 implementer_namespace: None,
215 description: None,
216 parameters: Vec::new(),
217 flags: crate::ActionTypeFlags::empty(),
218 function: Box::new(func),
219 }
220 }
221
222 pub fn implementer_namespace(mut self, implementer_namespace: &'a str) -> Self {
223 self.implementer_namespace = Some(implementer_namespace);
224 self
225 }
226
227 pub fn implementer_namespace_if(
228 mut self,
229 implementer_namespace: &'a str,
230 predicate: bool,
231 ) -> Self {
232 if predicate {
233 self.implementer_namespace = Some(implementer_namespace);
234 self
235 } else {
236 self
237 }
238 }
239
240 pub fn implementer_namespace_if_some(self, implementer_namespace: Option<&'a str>) -> Self {
241 if let Some(implementer_namespace) = implementer_namespace {
242 self.implementer_namespace(implementer_namespace)
243 } else {
244 self
245 }
246 }
247
248 pub fn description(mut self, description: &'a str) -> Self {
249 self.description = Some(description);
250 self
251 }
252
253 pub fn description_if(mut self, description: &'a str, predicate: bool) -> Self {
254 if predicate {
255 self.description = Some(description);
256 self
257 } else {
258 self
259 }
260 }
261
262 pub fn description_if_some(self, description: Option<&'a str>) -> Self {
263 if let Some(description) = description {
264 self.description(description)
265 } else {
266 self
267 }
268 }
269
270 pub fn parameter(mut self, parameter: ActionParameter) -> Self {
271 self.parameters.push(parameter);
272 self
273 }
274
275 pub fn parameter_if(mut self, parameter: ActionParameter, predicate: bool) -> Self {
276 if predicate {
277 self.parameters.push(parameter);
278 self
279 } else {
280 self
281 }
282 }
283
284 pub fn parameter_if_some(self, parameter: Option<ActionParameter>) -> Self {
285 if let Some(parameter) = parameter {
286 self.parameter(parameter)
287 } else {
288 self
289 }
290 }
291
292 pub fn flags(mut self, flags: crate::ActionTypeFlags) -> Self {
293 self.flags |= flags;
294 self
295 }
296
297 pub fn flags_if(mut self, flags: crate::ActionTypeFlags, predicate: bool) -> Self {
298 if predicate {
299 self.flags |= flags;
300 self
301 } else {
302 self
303 }
304 }
305
306 pub fn flags_if_some(self, flags: Option<crate::ActionTypeFlags>) -> Self {
307 if let Some(flags) = flags {
308 self.flags(flags)
309 } else {
310 self
311 }
312 }
313
314 pub fn build(self) -> crate::ActionType {
315 static QUARK_ACTION_TYPE_FUNC: std::sync::OnceLock<glib::Quark> =
316 std::sync::OnceLock::new();
317
318 let quark_action_type_func =
319 QUARK_ACTION_TYPE_FUNC.get_or_init(|| glib::Quark::from_str("rs-action-type-function"));
320
321 unsafe extern "C" fn execute_func_trampoline(
322 scenario: *mut ffi::GstValidateScenario,
323 mut action_ptr: *mut ffi::GstValidateAction,
324 ) -> c_int {
325 let action_type = ffi::gst_validate_get_action_type((*action_ptr).type_);
326 let scenario = from_glib_borrow(scenario);
327
328 let func: &ActionFunction = &*(gst::ffi::gst_mini_object_get_qdata(
329 action_type as *mut gst::ffi::GstMiniObject,
330 QUARK_ACTION_TYPE_FUNC.get().unwrap().into_glib(),
331 ) as *const Box<ActionFunction>);
332
333 let original_ptr = action_ptr;
336 let action = Action::from_glib_ptr_borrow_mut(&mut action_ptr);
337 let res = (*func)(&scenario, action);
338
339 debug_assert_eq!(action.as_ptr(), original_ptr);
340 match res {
341 Err(crate::ActionError::Error(ref err)) => {
342 action.report_error(err);
343 ffi::GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED
344 }
345 Ok(v) => v.into_glib(),
346 }
347 }
348
349 unsafe {
350 let params = into_glib_content(self.parameters);
351 let action_type = ffi::gst_validate_register_action_type(
352 self.type_name.to_glib_none().0,
353 self.implementer_namespace
354 .unwrap_or("validaters")
355 .to_glib_none()
356 .0,
357 Some(execute_func_trampoline),
358 params,
359 self.description.to_glib_none().0,
360 self.flags.into_glib(),
361 );
362
363 glib::ffi::g_free(params as *mut _);
367
368 let f = self.function;
369
370 gst::ffi::gst_mini_object_set_qdata(
371 action_type as *mut gst::ffi::GstMiniObject,
372 quark_action_type_func.into_glib(),
373 Box::into_raw(Box::new(f)) as *mut _,
374 Some(destroy_notify),
375 );
376
377 from_glib_none(action_type)
378 }
379 }
380}
381
382pub trait ActionTypeExtManual: 'static {
383 #[doc(alias = "gst_validate_get_action_type")]
384 fn find(name: &str) -> Option<crate::ActionType>;
385}
386
387impl ActionTypeExtManual for crate::ActionType {
388 fn find(name: &str) -> Option<crate::ActionType> {
389 assert_initialized_main_thread!();
390 unsafe {
391 let action_type = ffi::gst_validate_get_action_type(name.to_glib_none().0);
392
393 if action_type.is_null() {
394 None
395 } else {
396 Some(from_glib_full(action_type))
397 }
398 }
399 }
400}