1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::borrow::Cow; |
4 | |
5 | use glib::{prelude::*, subclass::prelude::*, translate::*}; |
6 | |
7 | use super::prelude::*; |
8 | use crate::{Device, DeviceProvider, LoggableError}; |
9 | |
10 | #[derive (Debug, Clone)] |
11 | pub struct DeviceProviderMetadata { |
12 | long_name: Cow<'static, str>, |
13 | classification: Cow<'static, str>, |
14 | description: Cow<'static, str>, |
15 | author: Cow<'static, str>, |
16 | additional: Cow<'static, [(Cow<'static, str>, Cow<'static, str>)]>, |
17 | } |
18 | |
19 | impl DeviceProviderMetadata { |
20 | pub fn new(long_name: &str, classification: &str, description: &str, author: &str) -> Self { |
21 | Self { |
22 | long_name: Cow::Owned(long_name.into()), |
23 | classification: Cow::Owned(classification.into()), |
24 | description: Cow::Owned(description.into()), |
25 | author: Cow::Owned(author.into()), |
26 | additional: Cow::Borrowed(&[]), |
27 | } |
28 | } |
29 | |
30 | pub fn with_additional( |
31 | long_name: &str, |
32 | classification: &str, |
33 | description: &str, |
34 | author: &str, |
35 | additional: &[(&str, &str)], |
36 | ) -> Self { |
37 | Self { |
38 | long_name: Cow::Owned(long_name.into()), |
39 | classification: Cow::Owned(classification.into()), |
40 | description: Cow::Owned(description.into()), |
41 | author: Cow::Owned(author.into()), |
42 | additional: additional |
43 | .iter() |
44 | .copied() |
45 | .map(|(key, value)| (Cow::Owned(key.into()), Cow::Owned(value.into()))) |
46 | .collect(), |
47 | } |
48 | } |
49 | |
50 | pub const fn with_cow( |
51 | long_name: Cow<'static, str>, |
52 | classification: Cow<'static, str>, |
53 | description: Cow<'static, str>, |
54 | author: Cow<'static, str>, |
55 | additional: Cow<'static, [(Cow<'static, str>, Cow<'static, str>)]>, |
56 | ) -> Self { |
57 | Self { |
58 | long_name, |
59 | classification, |
60 | description, |
61 | author, |
62 | additional, |
63 | } |
64 | } |
65 | } |
66 | |
67 | pub trait DeviceProviderImpl: DeviceProviderImplExt + GstObjectImpl + Send + Sync { |
68 | fn metadata() -> Option<&'static DeviceProviderMetadata> { |
69 | None |
70 | } |
71 | |
72 | fn probe(&self) -> Vec<Device> { |
73 | self.parent_probe() |
74 | } |
75 | |
76 | fn start(&self) -> Result<(), LoggableError> { |
77 | self.parent_start() |
78 | } |
79 | |
80 | fn stop(&self) { |
81 | self.parent_stop() |
82 | } |
83 | } |
84 | |
85 | mod sealed { |
86 | pub trait Sealed {} |
87 | impl<T: super::DeviceProviderImplExt> Sealed for T {} |
88 | } |
89 | |
90 | pub trait DeviceProviderImplExt: sealed::Sealed + ObjectSubclass { |
91 | fn parent_probe(&self) -> Vec<Device> { |
92 | unsafe { |
93 | let data = Self::type_data(); |
94 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceProviderClass; |
95 | if let Some(f) = (*parent_class).probe { |
96 | FromGlibPtrContainer::from_glib_full(f(self |
97 | .obj() |
98 | .unsafe_cast_ref::<DeviceProvider>() |
99 | .to_glib_none() |
100 | .0)) |
101 | } else { |
102 | Vec::new() |
103 | } |
104 | } |
105 | } |
106 | |
107 | fn parent_start(&self) -> Result<(), LoggableError> { |
108 | unsafe { |
109 | let data = Self::type_data(); |
110 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceProviderClass; |
111 | let f = (*parent_class).start.ok_or_else(|| { |
112 | loggable_error!(crate::CAT_RUST, "Parent function `start` is not defined" ) |
113 | })?; |
114 | result_from_gboolean!( |
115 | f(self |
116 | .obj() |
117 | .unsafe_cast_ref::<DeviceProvider>() |
118 | .to_glib_none() |
119 | .0), |
120 | crate::CAT_RUST, |
121 | "Failed to start the device provider using the parent function" |
122 | ) |
123 | } |
124 | } |
125 | |
126 | fn parent_stop(&self) { |
127 | unsafe { |
128 | let data = Self::type_data(); |
129 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceProviderClass; |
130 | if let Some(f) = (*parent_class).stop { |
131 | f(self |
132 | .obj() |
133 | .unsafe_cast_ref::<DeviceProvider>() |
134 | .to_glib_none() |
135 | .0); |
136 | } |
137 | } |
138 | } |
139 | } |
140 | |
141 | impl<T: DeviceProviderImpl> DeviceProviderImplExt for T {} |
142 | |
143 | unsafe impl<T: DeviceProviderImpl> IsSubclassable<T> for DeviceProvider { |
144 | fn class_init(klass: &mut glib::Class<Self>) { |
145 | Self::parent_class_init::<T>(klass); |
146 | let klass = klass.as_mut(); |
147 | klass.probe = Some(device_provider_probe::<T>); |
148 | klass.start = Some(device_provider_start::<T>); |
149 | klass.stop = Some(device_provider_stop::<T>); |
150 | |
151 | unsafe { |
152 | if let Some(metadata) = T::metadata() { |
153 | ffi::gst_device_provider_class_set_metadata( |
154 | klass, |
155 | metadata.long_name.to_glib_none().0, |
156 | metadata.classification.to_glib_none().0, |
157 | metadata.description.to_glib_none().0, |
158 | metadata.author.to_glib_none().0, |
159 | ); |
160 | |
161 | for (key, value) in metadata.additional.iter() { |
162 | ffi::gst_device_provider_class_add_metadata( |
163 | klass, |
164 | key.to_glib_none().0, |
165 | value.to_glib_none().0, |
166 | ); |
167 | } |
168 | } |
169 | } |
170 | } |
171 | } |
172 | |
173 | unsafe extern "C" fn device_provider_probe<T: DeviceProviderImpl>( |
174 | ptr: *mut ffi::GstDeviceProvider, |
175 | ) -> *mut glib::ffi::GList { |
176 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
177 | let imp: &T = instance.imp(); |
178 | |
179 | imp.probe().to_glib_full() |
180 | } |
181 | |
182 | unsafe extern "C" fn device_provider_start<T: DeviceProviderImpl>( |
183 | ptr: *mut ffi::GstDeviceProvider, |
184 | ) -> glib::ffi::gboolean { |
185 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
186 | let imp: &T = instance.imp(); |
187 | |
188 | matchbool imp.start() { |
189 | Ok(()) => true, |
190 | Err(err: LoggableError) => { |
191 | err.log_with_imp(imp); |
192 | false |
193 | } |
194 | } |
195 | .into_glib() |
196 | } |
197 | |
198 | unsafe extern "C" fn device_provider_stop<T: DeviceProviderImpl>(ptr: *mut ffi::GstDeviceProvider) { |
199 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
200 | let imp: &T = instance.imp(); |
201 | |
202 | imp.stop(); |
203 | } |
204 | |