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