1use crate::{calls, types::*, Internal, Result};
2use core::mem::{ManuallyDrop, MaybeUninit};
3use std::os::unix::io::RawFd;
4
5pub struct Value<C: AsRef<QueryExtCtrl>> {
7 ctrl: C,
8 data: Internal<ExtControl>,
9}
10
11impl<C: AsRef<QueryExtCtrl>> From<C> for Value<C> {
12 fn from(ctrl: C) -> Self {
13 let data = Internal::<ExtControl>::new(ctrl.as_ref());
14
15 Self { ctrl, data }
16 }
17}
18
19impl<C: AsRef<QueryExtCtrl>> core::ops::Deref for Value<C> {
20 type Target = C;
21 fn deref(&self) -> &Self::Target {
22 &self.ctrl
23 }
24}
25
26impl<C: AsRef<QueryExtCtrl>> Value<C> {
27 pub fn control(&self) -> &C {
28 &self.ctrl
29 }
30
31 pub fn try_ref<T: RefValue<ExtControl>>(&self) -> Option<&T> {
32 T::try_ref(&self.data, self.ctrl.as_ref())
33 }
34
35 pub fn try_mut<T: MutValue<ExtControl>>(&mut self) -> Option<&mut T> {
36 T::try_mut(&mut self.data, self.ctrl.as_ref())
37 }
38}
39
40impl<C: AsRef<QueryExtCtrl>> Drop for Value<C> {
41 fn drop(&mut self) {
42 if self.ctrl.as_ref().has_payload() {
43 self.data.del();
44 }
45 }
46}
47
48impl AsRef<QueryExtCtrl> for QueryExtCtrl {
49 fn as_ref(&self) -> &Self {
50 self
51 }
52}
53
54impl<C: AsRef<QueryExtCtrl>> GetValue for Value<C> {
55 fn get(&mut self, fd: RawFd) -> Result<()> {
57 let ctrls = MaybeUninit::<ExtControls>::zeroed();
58
59 unsafe_call!({
60 let mut ctrls = ctrls.assume_init();
61
62 ctrls.count = 1;
63 ctrls.controls = self.data.as_mut() as *mut _;
64
65 calls::g_ext_ctrls(fd, &mut ctrls as *mut _)
66 })?;
67
68 Ok(())
69 }
70}
71
72impl<C: AsRef<QueryExtCtrl>> SetValue for Value<C> {
73 fn set(&self, fd: RawFd) -> Result<()> {
75 let req = MaybeUninit::<ExtControls>::zeroed();
76
77 unsafe_call!({
78 let mut req = req.assume_init();
79
80 req.count = 1;
81 req.controls = self.data.as_ref() as *const _ as *mut _;
82
83 calls::s_ext_ctrls(fd, &mut req as *mut _)
84 })?;
85
86 Ok(())
87 }
88}
89
90impl Internal<ExtControl> {
91 pub fn new(ctrl: &QueryExtCtrl) -> Self {
92 let data = MaybeUninit::<ExtControl>::zeroed();
93 let size = ctrl.size();
94
95 let ptr = if ctrl.has_payload() {
96 let mut data = Vec::<u8>::with_capacity(size as _);
97 let ptr = data.as_mut_ptr();
98 let _ = ManuallyDrop::new(data);
99 ptr
100 } else {
101 core::ptr::null_mut()
102 };
103
104 let data = unsafe {
105 let mut data = data.assume_init();
106
107 data.union_.ptr = ptr as _;
108
109 data.id = ctrl.id;
110 data.size = size;
111
112 data
113 };
114
115 Self(data)
116 }
117
118 pub fn del(&mut self) {
119 unsafe {
120 let _ = Vec::from_raw_parts(self.union_.ptr as *mut u8, 0, self.size as _);
121 }
123 }
124}
125
126impl RefValue<ExtControl> for str {
127 fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
128 if matches!(ctrl.type_, CtrlType::String) && ctrl.has_payload() {
129 unsafe { core::ffi::CStr::from_ptr(data.union_.string as _) }
130 .to_str()
131 .ok()
132 } else {
133 None
134 }
135 }
136}
137
138pub trait IsPlainCtrlData {
140 const TYPES: &'static [CtrlType];
142}
143
144macro_rules! value_impl {
145 ($($type:ty: $($ctrl_type:ident)*,)*) => {
146 $(
147 impl IsPlainCtrlData for $type {
148 const TYPES: &'static [CtrlType] = &[ $(CtrlType::$ctrl_type,)* ];
149 }
150 )*
151 };
152}
153
154value_impl! {
155 i32: Integer,
156 bool: Boolean,
157 i64: Integer64,
158 CtrlClass: CtrlClass,
159 u8: U8 BitMask Menu IntegerMenu,
160 u16: U16 BitMask Menu IntegerMenu,
161 u32: U32 BitMask Menu IntegerMenu,
162 Area: Area,
163 Hdr10CllInfo: Hdr10CllInfo,
164 Hdr10MasteringDisplay: Hdr10MasteringDisplay,
165 H264Sps: H264Sps,
166 H264Pps: H264Pps,
167 H264ScalingMatrix: H264ScalingMatrix,
168 H264SliceParams: H264SliceParams,
169 H264DecodeParams: H264DecodeParams,
170 H264PredWeights: H264PredWeights,
171 FwhtParams: FwhtParams,
172 Mpeg2Quantisation: Mpeg2Quantisation,
174 Mpeg2Sequence: Mpeg2Sequence,
175 Mpeg2Picture: Mpeg2Picture,
176 Vp9CompressedHdr: Vp9CompressedHdr,
177 Vp9Frame: Vp9Frame,
178}
179
180pub trait RefValue<T> {
181 fn try_ref<'a>(data: &'a T, ctrl: &QueryExtCtrl) -> Option<&'a Self>;
183}
184
185pub trait MutValue<T> {
186 fn try_mut<'a>(data: &'a mut T, ctrl: &QueryExtCtrl) -> Option<&'a mut Self>;
188}
189
190pub trait GetValue {
191 fn get(&mut self, fd: RawFd) -> Result<()>;
193}
194
195pub trait SetValue {
196 fn set(&self, fd: RawFd) -> Result<()>;
198}
199
200impl<T: IsPlainCtrlData> RefValue<ExtControl> for T {
201 fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
202 if T::TYPES.contains(&ctrl.type_) {
203 if ctrl.has_payload() {
204 if core::mem::size_of::<T>() as u32 <= data.size {
205 return Some(unsafe { &*(data.union_.ptr as *const _) });
206 }
207 } else if core::mem::size_of::<T>() <= core::mem::size_of::<ExtControlUnion>() {
208 return Some(unsafe { &*(&data.union_.value as *const _ as *const _) });
209 }
210 }
211 None
212 }
213}
214
215impl<T: IsPlainCtrlData> MutValue<ExtControl> for T {
216 fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
217 if T::TYPES.contains(&ctrl.type_) {
218 if ctrl.has_payload() {
219 if core::mem::size_of::<T>() as u32 <= data.size {
220 return Some(unsafe { &mut *(data.union_.ptr as *mut _) });
221 }
222 } else if core::mem::size_of::<T>() <= core::mem::size_of::<ExtControlUnion>() {
223 return Some(unsafe { &mut *(&mut data.union_.value as *mut _ as *mut _) });
224 }
225 }
226 None
227 }
228}
229
230impl<const N: usize, T: IsPlainCtrlData> RefValue<ExtControl> for [T; N] {
231 fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
232 if T::TYPES.contains(&ctrl.type_)
233 && ctrl.has_payload()
234 && core::mem::size_of::<Self>() as u32 <= data.size
235 {
236 Some(unsafe { &*(data.union_.ptr as *const _) })
237 } else {
238 None
239 }
240 }
241}
242
243impl<const N: usize, T: IsPlainCtrlData> MutValue<ExtControl> for [T; N] {
244 fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
245 if T::TYPES.contains(&ctrl.type_)
246 && ctrl.has_payload()
247 && core::mem::size_of::<Self>() as u32 <= data.size
248 {
249 Some(unsafe { &mut *(data.union_.ptr as *mut _) })
250 } else {
251 None
252 }
253 }
254}
255
256impl<const N: usize, const M: usize, T: IsPlainCtrlData> RefValue<ExtControl> for [[T; N]; M] {
257 fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
258 if T::TYPES.contains(&ctrl.type_)
259 && ctrl.has_payload()
260 && core::mem::size_of::<Self>() as u32 <= data.size
261 {
262 Some(unsafe { &*(data.union_.ptr as *const _) })
263 } else {
264 None
265 }
266 }
267}
268
269impl<const N: usize, const M: usize, T: IsPlainCtrlData> MutValue<ExtControl> for [[T; N]; M] {
270 fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
271 if T::TYPES.contains(&ctrl.type_)
272 && ctrl.has_payload()
273 && core::mem::size_of::<Self>() as u32 <= data.size
274 {
275 Some(unsafe { &mut *(data.union_.ptr as *mut _) })
276 } else {
277 None
278 }
279 }
280}
281
282impl<const N: usize, const M: usize, const L: usize, T: IsPlainCtrlData> RefValue<ExtControl>
283 for [[[T; N]; M]; L]
284{
285 fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
286 if T::TYPES.contains(&ctrl.type_)
287 && ctrl.has_payload()
288 && core::mem::size_of::<Self>() as u32 <= data.size
289 {
290 Some(unsafe { &*(data.union_.ptr as *const _) })
291 } else {
292 None
293 }
294 }
295}
296
297impl<const N: usize, const M: usize, const L: usize, T: IsPlainCtrlData> MutValue<ExtControl>
298 for [[[T; N]; M]; L]
299{
300 fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
301 if T::TYPES.contains(&ctrl.type_)
302 && ctrl.has_payload()
303 && core::mem::size_of::<Self>() as u32 <= data.size
304 {
305 Some(unsafe { &mut *(data.union_.ptr as *mut _) })
306 } else {
307 None
308 }
309 }
310}
311
312impl<const N: usize, const M: usize, const L: usize, const O: usize, T: IsPlainCtrlData>
313 RefValue<ExtControl> for [[[[T; N]; M]; L]; O]
314{
315 fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
316 if T::TYPES.contains(&ctrl.type_)
317 && ctrl.has_payload()
318 && core::mem::size_of::<Self>() as u32 <= data.size
319 {
320 Some(unsafe { &*(data.union_.ptr as *const _) })
321 } else {
322 None
323 }
324 }
325}
326
327impl<const N: usize, const M: usize, const L: usize, const O: usize, T: IsPlainCtrlData>
328 MutValue<ExtControl> for [[[[T; N]; M]; L]; O]
329{
330 fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
331 if T::TYPES.contains(&ctrl.type_)
332 && ctrl.has_payload()
333 && core::mem::size_of::<Self>() as u32 <= data.size
334 {
335 Some(unsafe { &mut *(data.union_.ptr as *mut _) })
336 } else {
337 None
338 }
339 }
340}
341
342pub struct Values<C: AsRef<QueryExtCtrl>> {
344 ctrls: Vec<C>,
345 datas: Vec<Internal<ExtControl>>,
346}
347
348impl<C: AsRef<QueryExtCtrl>> FromIterator<C> for Values<C> {
349 fn from_iter<T: IntoIterator<Item = C>>(iter: T) -> Self {
350 let mut ctrls = Vec::new();
351 let mut datas = Vec::new();
352
353 for ctrl in iter {
354 datas.push(Internal::<ExtControl>::new(ctrl.as_ref()));
355 ctrls.push(ctrl);
356 }
357
358 Self { ctrls, datas }
359 }
360}
361
362impl<C: AsRef<QueryExtCtrl>> Drop for Values<C> {
363 fn drop(&mut self) {
364 for index in 0..self.len() {
365 let ctrl = &self.ctrls[index];
366 let data = &mut self.datas[index];
367 if ctrl.as_ref().has_payload() {
368 Internal::from(data).del();
369 }
370 }
371 }
372}
373
374impl<C: AsRef<QueryExtCtrl>> Values<C> {
375 pub fn len(&self) -> usize {
377 self.ctrls.len()
378 }
379
380 pub fn is_empty(&self) -> bool {
382 self.ctrls.is_empty()
383 }
384
385 pub fn controls(&self) -> &[C] {
387 &self.ctrls
388 }
389
390 pub fn try_ref<T: RefValue<ExtControl>>(&self, index: usize) -> Option<&T> {
392 if index < self.ctrls.len() {
393 T::try_ref(&self.datas[index], self.ctrls[index].as_ref())
394 } else {
395 None
396 }
397 }
398
399 pub fn try_mut<T: MutValue<ExtControl>>(&mut self, index: usize) -> Option<&mut T> {
401 if index < self.ctrls.len() {
402 T::try_mut(&mut self.datas[index], self.ctrls[index].as_ref())
403 } else {
404 None
405 }
406 }
407}
408
409impl<C: AsRef<QueryExtCtrl>> GetValue for Values<C> {
410 fn get(&mut self, fd: RawFd) -> Result<()> {
412 let ctrls = MaybeUninit::<ExtControls>::zeroed();
413
414 unsafe_call!({
415 let mut ctrls = ctrls.assume_init();
416
417 ctrls.count = self.ctrls.len() as _;
418 ctrls.controls = self.datas.as_mut_ptr() as _;
419
420 calls::g_ext_ctrls(fd, &mut ctrls).map(|_| ())
421 })
422 }
423}
424
425impl<C: AsRef<QueryExtCtrl>> SetValue for Values<C> {
426 fn set(&self, fd: RawFd) -> Result<()> {
428 let ctrls = MaybeUninit::<ExtControls>::zeroed();
429
430 unsafe_call!({
431 let mut ctrls = ctrls.assume_init();
432
433 ctrls.count = self.ctrls.len() as _;
434 ctrls.controls = self.datas.as_ptr() as _;
435
436 calls::s_ext_ctrls(fd, &mut ctrls).map(|_| ())
437 })
438 }
439}