libcamera/
control.rs

1use std::{collections::HashMap, ffi::CStr, marker::PhantomData, ptr::NonNull};
2
3use libcamera_control_direction::*;
4use libcamera_sys::*;
5use num_enum::{IntoPrimitive, TryFromPrimitive};
6use thiserror::Error;
7
8use crate::{
9    control_value::{ControlType, ControlValue, ControlValueError},
10    controls::{self, ControlId},
11    properties::{self, PropertyId},
12    utils::{UniquePtr, UniquePtrTarget},
13};
14
15#[derive(Debug, Error)]
16pub enum ControlError {
17    #[error("Control id {0} not found")]
18    NotFound(u32),
19    #[error("Control value error: {0}")]
20    ValueError(#[from] ControlValueError),
21}
22
23pub trait ControlEntry:
24    Clone + Into<ControlValue> + TryFrom<ControlValue, Error = ControlValueError> + core::fmt::Debug
25{
26    const ID: u32;
27}
28
29pub trait Control: ControlEntry {}
30pub trait Property: ControlEntry {}
31
32/// Dynamic Control, which does not have strong typing.
33pub trait DynControlEntry: core::fmt::Debug {
34    fn id(&self) -> u32;
35    fn value(&self) -> ControlValue;
36}
37
38impl<T: ControlEntry> DynControlEntry for T {
39    fn id(&self) -> u32 {
40        Self::ID
41    }
42
43    fn value(&self) -> ControlValue {
44        self.clone().into()
45    }
46}
47
48#[repr(transparent)]
49pub struct ControlInfo(libcamera_control_info_t);
50
51#[repr(transparent)]
52pub struct ControlIdMap(libcamera_control_id_map_t);
53
54impl ControlIdMap {
55    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_id_map_t>) -> &'a mut Self {
56        &mut *(ptr.as_ptr() as *mut Self)
57    }
58
59    pub fn iter(&self) -> Option<ControlIdMapIter<'_>> {
60        ControlIdMapIter::new(self)
61    }
62
63    pub(crate) fn ptr(&self) -> *const libcamera_control_id_map_t {
64        &self.0 as *const libcamera_control_id_map_t
65    }
66}
67
68#[derive(Clone, Copy)]
69pub struct ControlIdRef {
70    ptr: NonNull<libcamera_control_id_t>,
71}
72
73impl ControlIdRef {
74    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_control_id_t>) -> Self {
75        Self { ptr }
76    }
77
78    pub fn id(&self) -> u32 {
79        unsafe { libcamera_control_id(self.ptr.as_ptr()) as u32 }
80    }
81
82    pub fn name(&self) -> &str {
83        unsafe {
84            CStr::from_ptr(libcamera_control_name(self.ptr.as_ptr()))
85                .to_str()
86                .unwrap()
87        }
88    }
89
90    pub fn vendor(&self) -> &str {
91        unsafe {
92            CStr::from_ptr(libcamera_control_id_vendor(self.ptr.as_ptr()))
93                .to_str()
94                .unwrap()
95        }
96    }
97
98    pub fn ty(&self) -> ControlType {
99        unsafe { libcamera_control_id_type(self.ptr.as_ptr()) }
100            .try_into()
101            .unwrap_or(ControlType::None)
102    }
103
104    pub fn is_array(&self) -> bool {
105        unsafe { libcamera_control_id_is_array(self.ptr.as_ptr()) }
106    }
107
108    pub fn size(&self) -> usize {
109        unsafe { libcamera_control_id_size(self.ptr.as_ptr()) }
110    }
111}
112
113impl ControlInfo {
114    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_info_t>) -> &'a mut Self {
115        // Safety: we can cast it because of `#[repr(transparent)]`
116        &mut *(ptr.as_ptr() as *mut Self)
117    }
118
119    pub(crate) fn ptr(&self) -> *const libcamera_control_info_t {
120        // Safety: we can cast it because of `#[repr(transparent)]`
121        &self.0 as *const libcamera_control_info_t
122    }
123
124    pub fn min(&self) -> ControlValue {
125        unsafe {
126            ControlValue::read(NonNull::new(libcamera_control_info_min(self.ptr().cast_mut()).cast_mut()).unwrap())
127                .unwrap()
128        }
129    }
130
131    pub fn max(&self) -> ControlValue {
132        unsafe {
133            ControlValue::read(NonNull::new(libcamera_control_info_max(self.ptr().cast_mut()).cast_mut()).unwrap())
134                .unwrap()
135        }
136    }
137
138    pub fn def(&self) -> ControlValue {
139        unsafe {
140            ControlValue::read(NonNull::new(libcamera_control_info_def(self.ptr().cast_mut()).cast_mut()).unwrap())
141                .unwrap()
142        }
143    }
144
145    pub fn values(&self) -> Vec<ControlValue> {
146        unsafe {
147            let mut size: usize = 0;
148            let values_ptr = libcamera_control_info_values(self.ptr(), &mut size as *mut usize);
149
150            if values_ptr.is_null() || size == 0 {
151                return Vec::new();
152            }
153
154            // Determine the size of libcamera_control_value_t
155            let control_value_size = libcamera_control_value_size();
156
157            // Cast the pointer to *const u8 for byte-wise pointer arithmetic
158            let base_ptr = values_ptr as *const u8;
159
160            let mut control_values = Vec::with_capacity(size);
161            for i in 0..size {
162                // Calculate the pointer to the i-th ControlValue
163                let offset = i * control_value_size;
164                let val_ptr = base_ptr.add(offset) as *const libcamera_control_value_t;
165
166                if val_ptr.is_null() {
167                    eprintln!("ControlValue at index {i} is null");
168                    continue;
169                }
170
171                // Read and convert the ControlValue
172                match ControlValue::read(NonNull::new(val_ptr.cast_mut()).unwrap()) {
173                    Ok(control_val) => control_values.push(control_val),
174                    Err(e) => {
175                        eprintln!("Failed to read ControlValue at index {i}: {e:?}");
176                    }
177                }
178            }
179
180            control_values
181        }
182    }
183}
184
185impl core::fmt::Debug for ControlInfo {
186    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187        f.debug_struct("ControlInfo")
188            .field("min", &self.min())
189            .field("max", &self.max())
190            .field("def", &self.def())
191            .field("values", &self.values())
192            .finish()
193    }
194}
195
196#[repr(transparent)]
197pub struct ControlInfoMap(libcamera_control_info_map_t);
198
199impl ControlInfoMap {
200    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_info_map_t>) -> &'a mut Self {
201        // Safety: we can cast it because of `#[repr(transparent)]`
202        &mut *(ptr.as_ptr() as *mut Self)
203    }
204
205    pub(crate) fn ptr(&self) -> *const libcamera_control_info_map_t {
206        // Safety: we can cast it because of `#[repr(transparent)]`
207        &self.0 as *const libcamera_control_info_map_t
208    }
209
210    pub fn at(&self, key: u32) -> Result<&ControlInfo, ControlError> {
211        unsafe {
212            let ptr = NonNull::new(libcamera_control_info_map_at(self.ptr().cast_mut(), key).cast_mut());
213            match ptr {
214                Some(ptr) => Ok(ControlInfo::from_ptr(ptr)),
215                None => Err(ControlError::NotFound(key)),
216            }
217        }
218    }
219
220    pub fn count(&self, key: u32) -> usize {
221        unsafe { libcamera_control_info_map_count(self.ptr().cast_mut(), key) }
222    }
223
224    pub fn find(&self, key: u32) -> Result<&ControlInfo, ControlError> {
225        unsafe {
226            let ptr = NonNull::new(libcamera_control_info_map_find(self.ptr().cast_mut(), key).cast_mut());
227
228            match ptr {
229                Some(ptr) => Ok(ControlInfo::from_ptr(ptr)),
230                None => Err(ControlError::NotFound(key)),
231            }
232        }
233    }
234
235    pub fn size(&self) -> usize {
236        unsafe { libcamera_control_info_map_size(self.ptr().cast_mut()) }
237    }
238}
239
240impl<'a> IntoIterator for &'a ControlInfoMap {
241    type Item = (u32, &'a ControlInfo);
242    type IntoIter = ControlInfoMapIter<'a>;
243
244    fn into_iter(self) -> Self::IntoIter {
245        ControlInfoMapIter::new(self).expect("Failed to create ControlInfoMap iterator")
246    }
247}
248
249impl core::fmt::Debug for ControlInfoMap {
250    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
251        let mut dm = f.debug_map();
252        for (key, value) in self.into_iter() {
253            match ControlId::try_from(key) {
254                Ok(id) => dm.entry(&id.name(), value),
255                Err(_) => dm.entry(&key, value),
256            };
257        }
258        dm.finish()
259    }
260}
261
262#[repr(transparent)]
263pub struct ControlList(libcamera_control_list_t);
264
265/// How to merge control lists.
266#[derive(Debug, Clone, Copy)]
267#[repr(u32)]
268pub enum MergePolicy {
269    KeepExisting = libcamera_control_merge_policy::LIBCAMERA_CONTROL_MERGE_KEEP_EXISTING,
270    OverwriteExisting = libcamera_control_merge_policy::LIBCAMERA_CONTROL_MERGE_OVERWRITE_EXISTING,
271}
272
273impl UniquePtrTarget for ControlList {
274    unsafe fn ptr_new() -> *mut Self {
275        libcamera_control_list_create() as *mut Self
276    }
277
278    unsafe fn ptr_drop(ptr: *mut Self) {
279        libcamera_control_list_destroy(ptr as *mut libcamera_control_list_t)
280    }
281}
282
283impl ControlList {
284    pub fn new() -> UniquePtr<Self> {
285        UniquePtr::new()
286    }
287
288    pub fn from_id_map(map: &ControlIdMap) -> Option<UniquePtr<Self>> {
289        unsafe {
290            let ptr = libcamera_control_list_create_with_idmap(map.ptr());
291            UniquePtr::from_raw(ptr as *mut Self)
292        }
293    }
294
295    pub fn from_info_map(info_map: &ControlInfoMap) -> Option<UniquePtr<Self>> {
296        unsafe {
297            let ptr = libcamera_control_list_create_with_info_map(info_map.ptr());
298            UniquePtr::from_raw(ptr as *mut Self)
299        }
300    }
301
302    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_list_t>) -> &'a mut Self {
303        // Safety: we can cast it because of `#[repr(transparent)]`
304        &mut *(ptr.as_ptr() as *mut Self)
305    }
306
307    pub(crate) fn ptr(&self) -> *const libcamera_control_list_t {
308        // Safety: we can cast it because of `#[repr(transparent)]`
309        &self.0 as *const libcamera_control_list_t
310    }
311
312    pub fn len(&self) -> usize {
313        unsafe { libcamera_control_list_size(self.ptr().cast_mut()) }
314    }
315
316    pub fn is_empty(&self) -> bool {
317        unsafe { libcamera_control_list_is_empty(self.ptr().cast_mut()) }
318    }
319
320    pub fn clear(&mut self) {
321        unsafe { libcamera_control_list_clear(self.ptr().cast_mut()) }
322    }
323
324    pub fn contains(&self, id: u32) -> bool {
325        unsafe { libcamera_control_list_contains(self.ptr(), id) }
326    }
327
328    pub fn merge(&mut self, other: &ControlList, policy: MergePolicy) {
329        unsafe { libcamera_control_list_merge(self.ptr().cast_mut(), other.ptr(), policy as u32) }
330    }
331
332    pub fn info_map(&self) -> Option<&ControlInfoMap> {
333        unsafe {
334            let ptr = libcamera_control_list_info_map(self.ptr());
335            NonNull::new(ptr.cast_mut()).map(|p| {
336                let m: &mut ControlInfoMap = ControlInfoMap::from_ptr(p);
337                &*m
338            })
339        }
340    }
341
342    pub fn id_map(&self) -> Option<&ControlIdMap> {
343        unsafe {
344            let ptr = libcamera_control_list_id_map(self.ptr());
345            NonNull::new(ptr.cast_mut()).map(|p| {
346                let m: &mut ControlIdMap = ControlIdMap::from_ptr(p);
347                &*m
348            })
349        }
350    }
351
352    pub fn get<C: Control>(&self) -> Result<C, ControlError> {
353        let val_ptr = NonNull::new(unsafe { libcamera_control_list_get(self.ptr().cast_mut(), C::ID as _).cast_mut() })
354            .ok_or(ControlError::NotFound(C::ID))?;
355
356        let val = unsafe { ControlValue::read(val_ptr) }?;
357        Ok(C::try_from(val)?)
358    }
359
360    /// Sets control value.
361    ///
362    /// This can fail if control is not supported by the camera, but due to libcamera API limitations an error will not
363    /// be returned. Use [ControlList::get] if you need to ensure that value was set.
364    pub fn set<C: Control>(&mut self, val: C) -> Result<(), ControlError> {
365        let ctrl_val: ControlValue = val.into();
366
367        unsafe {
368            let val_ptr = NonNull::new(libcamera_control_value_create()).unwrap();
369            ctrl_val.write(val_ptr);
370            libcamera_control_list_set(self.ptr().cast_mut(), C::ID as _, val_ptr.as_ptr());
371            libcamera_control_value_destroy(val_ptr.as_ptr());
372        }
373
374        Ok(())
375    }
376
377    /// Sets control value.
378    ///
379    /// This can fail if control is not supported by the camera, but due to libcamera API limitations an error will not
380    /// be returned. Use [ControlList::get] if you need to ensure that value was set.
381    pub fn set_raw(&mut self, id: u32, val: ControlValue) -> Result<(), ControlError> {
382        unsafe {
383            let val_ptr = NonNull::new(libcamera_control_value_create()).unwrap();
384            val.write(val_ptr);
385            libcamera_control_list_set(self.ptr().cast_mut(), id as _, val_ptr.as_ptr());
386            libcamera_control_value_destroy(val_ptr.as_ptr());
387        }
388
389        Ok(())
390    }
391
392    pub fn get_raw(&mut self, id: u32) -> Result<ControlValue, ControlError> {
393        let val_ptr = NonNull::new(unsafe { libcamera_control_list_get(self.ptr().cast_mut(), id as _).cast_mut() })
394            .ok_or(ControlError::NotFound(id))?;
395
396        let val = unsafe { ControlValue::read(val_ptr) }?;
397        Ok(val)
398    }
399}
400
401impl<'d> IntoIterator for &'d ControlList {
402    type Item = (u32, ControlValue);
403
404    type IntoIter = ControlListRefIterator<'d>;
405
406    fn into_iter(self) -> Self::IntoIter {
407        ControlListRefIterator {
408            it: NonNull::new(unsafe { libcamera_control_list_iter(self.ptr().cast_mut()) }).unwrap(),
409            _phantom: Default::default(),
410        }
411    }
412}
413
414impl core::fmt::Debug for ControlList {
415    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
416        let mut map = f.debug_map();
417        for (id, val) in self.into_iter() {
418            match ControlId::try_from(id) {
419                // Try to parse dynamic control, if not successful, just display the raw ControlValue
420                Ok(id) => match controls::make_dyn(id, val.clone()) {
421                    Ok(val) => map.entry(&id, &val),
422                    Err(_) => map.entry(&id, &val),
423                },
424                // If ControlId is unknown just use u32 as key
425                Err(_) => map.entry(&id, &val),
426            };
427        }
428        map.finish()
429    }
430}
431
432#[repr(transparent)]
433pub struct PropertyList(libcamera_control_list_t);
434
435impl PropertyList {
436    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_list_t>) -> &'a mut Self {
437        // Safety: we can cast it because of `#[repr(transparent)]`
438        &mut *(ptr.as_ptr() as *mut Self)
439    }
440
441    pub(crate) fn ptr(&self) -> *const libcamera_control_list_t {
442        // Safety: we can cast it because of `#[repr(transparent)]`
443        &self.0 as *const libcamera_control_list_t
444    }
445
446    pub fn get<C: Property>(&self) -> Result<C, ControlError> {
447        let val_ptr = NonNull::new(unsafe { libcamera_control_list_get(self.ptr().cast_mut(), C::ID as _).cast_mut() })
448            .ok_or(ControlError::NotFound(C::ID))?;
449
450        let val = unsafe { ControlValue::read(val_ptr) }?;
451
452        Ok(C::try_from(val)?)
453    }
454}
455
456impl<'d> IntoIterator for &'d PropertyList {
457    type Item = (u32, ControlValue);
458
459    type IntoIter = ControlListRefIterator<'d>;
460
461    fn into_iter(self) -> Self::IntoIter {
462        ControlListRefIterator {
463            it: NonNull::new(unsafe { libcamera_control_list_iter(self.ptr().cast_mut()) }).unwrap(),
464            _phantom: Default::default(),
465        }
466    }
467}
468
469impl core::fmt::Debug for PropertyList {
470    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
471        let mut map = f.debug_map();
472        for (id, val) in self.into_iter() {
473            match PropertyId::try_from(id) {
474                // Try to parse dynamic property, if not successful, just display the raw ControlValue
475                Ok(id) => match properties::make_dyn(id, val.clone()) {
476                    Ok(val) => map.entry(&id, &val),
477                    Err(_) => map.entry(&id, &val),
478                },
479                // If PropertyId is unknown just use u32 as key
480                Err(_) => map.entry(&id, &val),
481            };
482        }
483        map.finish()
484    }
485}
486
487pub struct ControlListRefIterator<'d> {
488    it: NonNull<libcamera_control_list_iter_t>,
489    _phantom: PhantomData<&'d ()>,
490}
491
492impl Iterator for ControlListRefIterator<'_> {
493    type Item = (u32, ControlValue);
494
495    fn next(&mut self) -> Option<Self::Item> {
496        if unsafe { libcamera_control_list_iter_end(self.it.as_ptr()) } {
497            None
498        } else {
499            let id = unsafe { libcamera_control_list_iter_id(self.it.as_ptr()) };
500            let val_ptr =
501                NonNull::new(unsafe { libcamera_control_list_iter_value(self.it.as_ptr()).cast_mut() }).unwrap();
502            let val = unsafe { ControlValue::read(val_ptr) }.unwrap();
503
504            unsafe { libcamera_control_list_iter_next(self.it.as_ptr()) };
505
506            Some((id, val))
507        }
508    }
509}
510
511impl Drop for ControlListRefIterator<'_> {
512    fn drop(&mut self) {
513        unsafe { libcamera_control_list_iter_destroy(self.it.as_ptr()) }
514    }
515}
516
517pub struct ControlInfoMapIter<'a> {
518    iter: *mut libcamera_control_info_map_iter_t,
519    marker: PhantomData<&'a libcamera_control_info_map_t>,
520}
521
522impl<'a> ControlInfoMapIter<'a> {
523    pub fn new(map: &'a ControlInfoMap) -> Option<Self> {
524        unsafe {
525            let iter = libcamera_control_info_map_iter_create(map.ptr());
526            if iter.is_null() {
527                None
528            } else {
529                Some(ControlInfoMapIter {
530                    iter,
531                    marker: PhantomData,
532                })
533            }
534        }
535    }
536}
537
538impl<'a> Iterator for ControlInfoMapIter<'a> {
539    type Item = (u32, &'a ControlInfo);
540
541    fn next(&mut self) -> Option<Self::Item> {
542        unsafe {
543            if libcamera_control_info_map_iter_has_next(self.iter) {
544                let key = libcamera_control_info_map_iter_key(self.iter);
545                let value_ptr = libcamera_control_info_map_iter_value(self.iter);
546                if value_ptr.is_null() {
547                    None
548                } else {
549                    let control_info = &*(value_ptr as *const ControlInfo);
550                    libcamera_control_info_map_iter_next(self.iter);
551                    Some((key, control_info))
552                }
553            } else {
554                None
555            }
556        }
557    }
558}
559
560impl<'a> Drop for ControlInfoMapIter<'a> {
561    fn drop(&mut self) {
562        unsafe {
563            libcamera_control_info_map_iter_destroy(self.iter);
564        }
565    }
566}
567
568pub struct ControlIdEnumeratorsIter<'a> {
569    iter: *mut libcamera_control_id_enumerators_iter_t,
570    marker: PhantomData<&'a ControlId>,
571}
572
573impl<'a> ControlIdEnumeratorsIter<'a> {
574    fn new(id: &'a ControlId) -> Option<Self> {
575        unsafe {
576            let iter = libcamera_control_id_enumerators_iter_create(id.as_ptr());
577            if iter.is_null() {
578                None
579            } else {
580                Some(ControlIdEnumeratorsIter {
581                    iter,
582                    marker: PhantomData,
583                })
584            }
585        }
586    }
587}
588
589impl Iterator for ControlIdEnumeratorsIter<'_> {
590    type Item = (i32, String);
591
592    fn next(&mut self) -> Option<Self::Item> {
593        unsafe {
594            if libcamera_control_id_enumerators_iter_has_next(self.iter) {
595                let key = libcamera_control_id_enumerators_iter_key(self.iter);
596                let val_ptr = libcamera_control_id_enumerators_iter_value(self.iter);
597                if val_ptr.is_null() {
598                    None
599                } else {
600                    let name = CStr::from_ptr(val_ptr).to_string_lossy().into_owned();
601                    libcamera_control_id_enumerators_iter_next(self.iter);
602                    Some((key, name))
603                }
604            } else {
605                None
606            }
607        }
608    }
609}
610
611impl Drop for ControlIdEnumeratorsIter<'_> {
612    fn drop(&mut self) {
613        unsafe {
614            libcamera_control_id_enumerators_iter_destroy(self.iter);
615        }
616    }
617}
618
619pub struct ControlIdMapIter<'a> {
620    iter: *mut libcamera_control_id_map_iter_t,
621    marker: PhantomData<&'a ControlIdMap>,
622}
623
624impl<'a> ControlIdMapIter<'a> {
625    fn new(map: &'a ControlIdMap) -> Option<Self> {
626        unsafe {
627            let iter = libcamera_control_id_map_iter_create(map.ptr());
628            if iter.is_null() {
629                None
630            } else {
631                Some(Self {
632                    iter,
633                    marker: PhantomData,
634                })
635            }
636        }
637    }
638}
639
640impl<'a> Iterator for ControlIdMapIter<'a> {
641    type Item = (u32, ControlIdRef);
642
643    fn next(&mut self) -> Option<Self::Item> {
644        unsafe {
645            if libcamera_control_id_map_iter_has_next(self.iter) {
646                let key = libcamera_control_id_map_iter_key(self.iter);
647                let id_ptr = libcamera_control_id_map_iter_value(self.iter);
648                libcamera_control_id_map_iter_next(self.iter);
649                NonNull::new(id_ptr.cast_mut()).map(|p| (key, ControlIdRef::from_ptr(p)))
650            } else {
651                None
652            }
653        }
654    }
655}
656
657impl Drop for ControlIdMapIter<'_> {
658    fn drop(&mut self) {
659        unsafe {
660            libcamera_control_id_map_iter_destroy(self.iter);
661        }
662    }
663}
664
665#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
666#[repr(u32)]
667pub enum ControlDirection {
668    /// Input flag (1<<0)
669    In = LIBCAMERA_CONTROL_DIRECTION_IN,
670    /// Output flag (1<<1)
671    Out = LIBCAMERA_CONTROL_DIRECTION_OUT,
672    /// Input and output flags combined (1<<0 | 1<<1)
673    InOut = LIBCAMERA_CONTROL_DIRECTION_IN | LIBCAMERA_CONTROL_DIRECTION_OUT,
674}
675
676impl ControlId {
677    pub fn name(&self) -> String {
678        unsafe { CStr::from_ptr(libcamera_control_name_from_id(self.id())) }
679            .to_str()
680            .unwrap()
681            .into()
682    }
683
684    fn as_ptr(&self) -> *mut libcamera_control_id_t {
685        let ptr = unsafe { libcamera_control_from_id(self.id()) as *mut libcamera_control_id_t };
686        assert!(!ptr.is_null(), "libcamera_control_from_id returned null");
687        ptr
688    }
689
690    pub fn vendor(&self) -> String {
691        unsafe {
692            let ctrl = self.as_ptr();
693            if ctrl.is_null() {
694                String::new()
695            } else {
696                let ptr = libcamera_control_id_vendor(ctrl);
697                CStr::from_ptr(ptr).to_string_lossy().to_string()
698            }
699        }
700    }
701
702    pub fn control_type(&self) -> ControlType {
703        let raw = unsafe { libcamera_control_id_type(self.as_ptr()) } as u32;
704        ControlType::try_from(raw).expect("Unknown ControlType")
705    }
706
707    pub fn direction(&self) -> ControlDirection {
708        let raw = unsafe { libcamera_control_id_direction(self.as_ptr()) } as u32;
709        ControlDirection::try_from(raw).expect("Unknown libcamera_control_direction value")
710    }
711
712    pub fn is_input(&self) -> bool {
713        unsafe { libcamera_control_id_is_input(self.as_ptr()) }
714    }
715
716    pub fn is_output(&self) -> bool {
717        unsafe { libcamera_control_id_is_output(self.as_ptr()) }
718    }
719
720    pub fn is_array(&self) -> bool {
721        unsafe { libcamera_control_id_is_array(self.as_ptr()) }
722    }
723
724    pub fn size(&self) -> usize {
725        unsafe { libcamera_control_id_size(self.as_ptr()) }
726    }
727
728    pub fn enumerators(&self) -> Option<ControlIdEnumeratorsIter<'_>> {
729        ControlIdEnumeratorsIter::new(self)
730    }
731
732    pub fn enumerators_map(&self) -> HashMap<i32, String> {
733        match self.enumerators() {
734            Some(iter) => iter.collect(),
735            None => HashMap::new(),
736        }
737    }
738
739    pub fn from_id(id: u32) -> Option<Self> {
740        ControlId::try_from(id).ok()
741    }
742}
743
744impl PropertyId {
745    pub fn name(&self) -> String {
746        unsafe { CStr::from_ptr(libcamera_property_name_from_id(self.id())) }
747            .to_str()
748            .unwrap()
749            .into()
750    }
751}