libcamera/
control_value.rs

1use std::ptr::NonNull;
2
3use libcamera_control_type::*;
4use libcamera_sys::*;
5use smallvec::{smallvec, SmallVec};
6use thiserror::Error;
7
8use crate::geometry::{Point, Rectangle, Size};
9
10#[derive(Error, Debug)]
11pub enum ControlValueError {
12    /// Control value type does not match the one being read/written
13    #[error("Expected type {expected}, found {found}")]
14    InvalidType { expected: u32, found: u32 },
15    /// Control value type is not recognized
16    #[error("Unknown control type {0}")]
17    UnknownType(u32),
18    /// Control value dimensionality mismatch
19    #[error("Expected {expected} elements, found {found}")]
20    InvalidLength { expected: usize, found: usize },
21    /// Control value type is correct, but it could not be converted into enum variant
22    #[error("Unknown enum variant {0:?}")]
23    UnknownVariant(ControlValue),
24}
25/// A value of a control or a property.
26#[derive(Debug, Clone)]
27pub enum ControlValue {
28    None,
29    Bool(SmallVec<[bool; 1]>),
30    Byte(SmallVec<[u8; 1]>),
31    Uint16(SmallVec<[u16; 1]>),
32    Uint32(SmallVec<[u32; 1]>),
33    Int32(SmallVec<[i32; 1]>),
34    Int64(SmallVec<[i64; 1]>),
35    Float(SmallVec<[f32; 1]>),
36    String(SmallVec<[String; 1]>),
37    Rectangle(SmallVec<[Rectangle; 1]>),
38    Size(SmallVec<[Size; 1]>),
39    // bad gues
40    Point(SmallVec<[Point; 1]>),
41}
42
43macro_rules! impl_control_value {
44    ($p:path, $type:ty) => {
45        impl From<$type> for ControlValue {
46            fn from(val: $type) -> Self {
47                $p(smallvec![val])
48            }
49        }
50
51        impl TryFrom<ControlValue> for $type {
52            type Error = ControlValueError;
53
54            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
55                match value {
56                    $p(mut val) => {
57                        if val.len() == 1 {
58                            Ok(val.pop().unwrap())
59                        } else {
60                            Err(ControlValueError::InvalidLength {
61                                expected: 1,
62                                found: val.len(),
63                            })
64                        }
65                    }
66                    _ => Err(ControlValueError::InvalidType {
67                        // not really efficient, but eh, only on error
68                        expected: $p(Default::default()).ty(),
69                        found: value.ty(),
70                    }),
71                }
72            }
73        }
74    };
75}
76
77impl_control_value!(ControlValue::Bool, bool);
78impl_control_value!(ControlValue::Byte, u8);
79impl_control_value!(ControlValue::Uint16, u16);
80impl_control_value!(ControlValue::Uint32, u32);
81impl_control_value!(ControlValue::Int32, i32);
82impl_control_value!(ControlValue::Int64, i64);
83impl_control_value!(ControlValue::Float, f32);
84impl_control_value!(ControlValue::Rectangle, Rectangle);
85impl_control_value!(ControlValue::Size, Size);
86impl_control_value!(ControlValue::Point, Point);
87
88macro_rules! impl_control_value_vec {
89    ($p:path, $type:ty) => {
90        impl From<Vec<$type>> for ControlValue {
91            fn from(val: Vec<$type>) -> Self {
92                $p(SmallVec::from_vec(val))
93            }
94        }
95
96        impl TryFrom<ControlValue> for Vec<$type> {
97            type Error = ControlValueError;
98
99            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
100                match value {
101                    $p(val) => Ok(val.into_vec()),
102                    _ => Err(ControlValueError::InvalidType {
103                        // not really efficient, but eh, only on error
104                        expected: $p(Default::default()).ty(),
105                        found: value.ty(),
106                    }),
107                }
108            }
109        }
110    };
111}
112
113impl_control_value_vec!(ControlValue::Bool, bool);
114impl_control_value_vec!(ControlValue::Byte, u8);
115impl_control_value_vec!(ControlValue::Uint16, u16);
116impl_control_value_vec!(ControlValue::Uint32, u32);
117impl_control_value_vec!(ControlValue::Int32, i32);
118impl_control_value_vec!(ControlValue::Int64, i64);
119impl_control_value_vec!(ControlValue::Float, f32);
120impl_control_value_vec!(ControlValue::Rectangle, Rectangle);
121impl_control_value_vec!(ControlValue::Size, Size);
122impl_control_value_vec!(ControlValue::Point, Point);
123
124macro_rules! impl_control_value_array {
125    ($p:path, $type:ty) => {
126        impl<const N: usize> From<[$type; N]> for ControlValue {
127            fn from(val: [$type; N]) -> Self {
128                $p(SmallVec::from_slice(&val))
129            }
130        }
131
132        impl<const N: usize> TryFrom<ControlValue> for [$type; N] {
133            type Error = ControlValueError;
134
135            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
136                match value {
137                    $p(val) => {
138                        Ok(val
139                            .into_vec()
140                            .try_into()
141                            .map_err(|e: Vec<$type>| ControlValueError::InvalidLength {
142                                expected: N,
143                                found: e.len(),
144                            })?)
145                    }
146                    _ => Err(ControlValueError::InvalidType {
147                        // not really efficient, but eh, only on error
148                        expected: $p(Default::default()).ty(),
149                        found: value.ty(),
150                    }),
151                }
152            }
153        }
154
155        impl<const N: usize, const M: usize> From<[[$type; M]; N]> for ControlValue {
156            fn from(val: [[$type; M]; N]) -> Self {
157                $p(SmallVec::from_slice(&unsafe {
158                    core::slice::from_raw_parts(val.as_ptr().cast(), N * M)
159                }))
160            }
161        }
162
163        impl<const N: usize, const M: usize> TryFrom<ControlValue> for [[$type; M]; N] {
164            type Error = ControlValueError;
165
166            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
167                match value {
168                    $p(val) => {
169                        if val.len() == N * M {
170                            let mut iter = val.into_iter();
171                            Ok([[(); M]; N].map(|a| a.map(|_| iter.next().unwrap())))
172                        } else {
173                            Err(ControlValueError::InvalidLength {
174                                expected: N * M,
175                                found: val.len(),
176                            })
177                        }
178                    }
179                    _ => Err(ControlValueError::InvalidType {
180                        // not really efficient, but eh, only on error
181                        expected: $p(Default::default()).ty(),
182                        found: value.ty(),
183                    }),
184                }
185            }
186        }
187    };
188}
189
190impl_control_value_array!(ControlValue::Bool, bool);
191impl_control_value_array!(ControlValue::Byte, u8);
192impl_control_value_array!(ControlValue::Uint16, u16);
193impl_control_value_array!(ControlValue::Uint32, u32);
194impl_control_value_array!(ControlValue::Int32, i32);
195impl_control_value_array!(ControlValue::Int64, i64);
196impl_control_value_array!(ControlValue::Float, f32);
197impl_control_value_array!(ControlValue::Rectangle, Rectangle);
198impl_control_value_array!(ControlValue::Size, Size);
199impl_control_value_array!(ControlValue::Point, Point);
200
201impl From<String> for ControlValue {
202    fn from(val: String) -> Self {
203        Self::String(smallvec![val])
204    }
205}
206
207impl TryFrom<ControlValue> for String {
208    type Error = ControlValueError;
209
210    fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
211        match value {
212            ControlValue::String(mut v) => {
213                if v.len() == 1 {
214                    Ok(v.pop().unwrap())
215                } else {
216                    Err(ControlValueError::InvalidLength {
217                        expected: 1,
218                        found: v.len(),
219                    })
220                }
221            }
222            _ => Err(ControlValueError::InvalidType {
223                expected: libcamera_control_type::LIBCAMERA_CONTROL_TYPE_STRING,
224                found: value.ty(),
225            }),
226        }
227    }
228}
229
230impl From<Vec<String>> for ControlValue {
231    fn from(val: Vec<String>) -> Self {
232        ControlValue::String(SmallVec::from_vec(val))
233    }
234}
235
236impl TryFrom<ControlValue> for Vec<String> {
237    type Error = ControlValueError;
238
239    fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
240        match value {
241            ControlValue::String(v) => Ok(v.into_vec()),
242            _ => Err(ControlValueError::InvalidType {
243                expected: libcamera_control_type::LIBCAMERA_CONTROL_TYPE_STRING,
244                found: value.ty(),
245            }),
246        }
247    }
248}
249
250impl ControlValue {
251    pub(crate) unsafe fn read(val: NonNull<libcamera_control_value_t>) -> Result<Self, ControlValueError> {
252        let ty = unsafe { libcamera_control_value_type(val.as_ptr()) };
253        let num_elements = unsafe { libcamera_control_value_num_elements(val.as_ptr()) };
254        let data = unsafe { libcamera_control_value_get(val.as_ptr()) };
255
256        match ty {
257            LIBCAMERA_CONTROL_TYPE_NONE => Ok(Self::None),
258            LIBCAMERA_CONTROL_TYPE_BOOL => {
259                let slice = core::slice::from_raw_parts(data as *const bool, num_elements);
260                Ok(Self::Bool(SmallVec::from_slice(slice)))
261            }
262            LIBCAMERA_CONTROL_TYPE_BYTE => {
263                let slice = core::slice::from_raw_parts(data as *const u8, num_elements);
264                Ok(Self::Byte(SmallVec::from_slice(slice)))
265            }
266            LIBCAMERA_CONTROL_TYPE_UINT16 => {
267                let slice = core::slice::from_raw_parts(data as *const u16, num_elements);
268                Ok(Self::Uint16(SmallVec::from_slice(slice)))
269            }
270            LIBCAMERA_CONTROL_TYPE_UINT32 => {
271                let slice = core::slice::from_raw_parts(data as *const u32, num_elements);
272                Ok(Self::Uint32(SmallVec::from_slice(slice)))
273            }
274            LIBCAMERA_CONTROL_TYPE_INT32 => {
275                let slice = core::slice::from_raw_parts(data as *const i32, num_elements);
276                Ok(Self::Int32(SmallVec::from_slice(slice)))
277            }
278            LIBCAMERA_CONTROL_TYPE_INT64 => {
279                let slice = core::slice::from_raw_parts(data as *const i64, num_elements);
280                Ok(Self::Int64(SmallVec::from_slice(slice)))
281            }
282            LIBCAMERA_CONTROL_TYPE_FLOAT => {
283                let slice = core::slice::from_raw_parts(data as *const f32, num_elements);
284                Ok(Self::Float(SmallVec::from_slice(slice)))
285            }
286            LIBCAMERA_CONTROL_TYPE_STRING => {
287                let slice = core::slice::from_raw_parts(data as *const u8, num_elements);
288                // Split on interior NULs to support string arrays; fallback to single string if no delimiters.
289                let mut parts = Vec::new();
290                let mut start = 0usize;
291                for (idx, b) in slice.iter().enumerate() {
292                    if *b == 0 {
293                        parts.push(&slice[start..idx]);
294                        start = idx + 1;
295                    }
296                }
297                if start < slice.len() {
298                    parts.push(&slice[start..]);
299                }
300                if parts.is_empty() {
301                    parts.push(&[]);
302                }
303                let strings = parts
304                    .into_iter()
305                    .filter_map(|p| core::str::from_utf8(p).ok())
306                    .map(|s| s.to_string())
307                    .collect();
308                Ok(Self::String(strings))
309            }
310            LIBCAMERA_CONTROL_TYPE_RECTANGLE => {
311                let slice = core::slice::from_raw_parts(data as *const libcamera_rectangle_t, num_elements);
312                Ok(Self::Rectangle(SmallVec::from_iter(
313                    slice.iter().map(|r| Rectangle::from(*r)),
314                )))
315            }
316            LIBCAMERA_CONTROL_TYPE_SIZE => {
317                let slice = core::slice::from_raw_parts(data as *const libcamera_size_t, num_elements);
318                Ok(Self::Size(SmallVec::from_iter(slice.iter().map(|r| Size::from(*r)))))
319            }
320            LIBCAMERA_CONTROL_TYPE_POINT => {
321                let slice = core::slice::from_raw_parts(data as *const libcamera_point_t, num_elements);
322                Ok(Self::Point(SmallVec::from_iter(slice.iter().map(|r| Point::from(*r)))))
323            }
324            _ => Err(ControlValueError::UnknownType(ty)),
325        }
326    }
327
328    pub(crate) unsafe fn write(&self, val: NonNull<libcamera_control_value_t>) {
329        let mut tmp_string_buf: Vec<u8> = Vec::new();
330        let (data, len) = match self {
331            ControlValue::None => (core::ptr::null(), 0),
332            ControlValue::Bool(v) => (v.as_ptr().cast(), v.len()),
333            ControlValue::Byte(v) => (v.as_ptr().cast(), v.len()),
334            ControlValue::Uint16(v) => (v.as_ptr().cast(), v.len()),
335            ControlValue::Uint32(v) => (v.as_ptr().cast(), v.len()),
336            ControlValue::Int32(v) => (v.as_ptr().cast(), v.len()),
337            ControlValue::Int64(v) => (v.as_ptr().cast(), v.len()),
338            ControlValue::Float(v) => (v.as_ptr().cast(), v.len()),
339            ControlValue::String(v) => {
340                if v.len() <= 1 {
341                    let s = v.first().map(|s| s.as_bytes()).unwrap_or(&[]);
342                    tmp_string_buf.extend_from_slice(s);
343                } else {
344                    tmp_string_buf.extend_from_slice(v.join("\0").as_bytes());
345                }
346                (tmp_string_buf.as_ptr(), tmp_string_buf.len())
347            }
348            ControlValue::Rectangle(v) => (v.as_ptr().cast(), v.len()),
349            ControlValue::Size(v) => (v.as_ptr().cast(), v.len()),
350            ControlValue::Point(v) => (v.as_ptr().cast(), v.len()),
351        };
352
353        // Strings must always be treated as arrays of bytes; passing a scalar causes libcamera to
354        // allocate only one byte. For all other types, keep the previous "len != 1" rule.
355        let is_array = matches!(self, ControlValue::String(_)) || len != 1;
356
357        libcamera_control_value_set(val.as_ptr(), self.ty(), data.cast(), is_array, len as _);
358    }
359
360    pub fn ty(&self) -> u32 {
361        use libcamera_control_type::*;
362        match self {
363            ControlValue::None => LIBCAMERA_CONTROL_TYPE_NONE,
364            ControlValue::Bool(_) => LIBCAMERA_CONTROL_TYPE_BOOL,
365            ControlValue::Byte(_) => LIBCAMERA_CONTROL_TYPE_BYTE,
366            ControlValue::Uint16(_) => LIBCAMERA_CONTROL_TYPE_UINT16,
367            ControlValue::Uint32(_) => LIBCAMERA_CONTROL_TYPE_UINT32,
368            ControlValue::Int32(_) => LIBCAMERA_CONTROL_TYPE_INT32,
369            ControlValue::Int64(_) => LIBCAMERA_CONTROL_TYPE_INT64,
370            ControlValue::Float(_) => LIBCAMERA_CONTROL_TYPE_FLOAT,
371            ControlValue::String(_) => LIBCAMERA_CONTROL_TYPE_STRING,
372            ControlValue::Rectangle(_) => LIBCAMERA_CONTROL_TYPE_RECTANGLE,
373            ControlValue::Size(_) => LIBCAMERA_CONTROL_TYPE_SIZE,
374            ControlValue::Point(_) => LIBCAMERA_CONTROL_TYPE_POINT,
375        }
376    }
377}
378
379#[derive(Error, Debug)]
380pub enum ControlTypeError {
381    /// Control type is not recognized
382    #[error("Unknown control type {0}")]
383    UnknownType(u32),
384}
385
386#[derive(Debug, Clone)]
387#[repr(u32)]
388pub enum ControlType {
389    None = LIBCAMERA_CONTROL_TYPE_NONE,
390    Bool = LIBCAMERA_CONTROL_TYPE_BOOL,
391    Byte = LIBCAMERA_CONTROL_TYPE_BYTE,
392    Uint16 = LIBCAMERA_CONTROL_TYPE_UINT16,
393    Uint32 = LIBCAMERA_CONTROL_TYPE_UINT32,
394    Int32 = LIBCAMERA_CONTROL_TYPE_INT32,
395    Int64 = LIBCAMERA_CONTROL_TYPE_INT64,
396    Float = LIBCAMERA_CONTROL_TYPE_FLOAT,
397    String = LIBCAMERA_CONTROL_TYPE_STRING,
398    Rectangle = LIBCAMERA_CONTROL_TYPE_RECTANGLE,
399    Size = LIBCAMERA_CONTROL_TYPE_SIZE,
400    Point = LIBCAMERA_CONTROL_TYPE_POINT,
401}
402
403impl TryFrom<u32> for ControlType {
404    type Error = ControlTypeError;
405
406    fn try_from(value: u32) -> Result<Self, Self::Error> {
407        use libcamera_control_type::*;
408        match value {
409            LIBCAMERA_CONTROL_TYPE_NONE => Ok(ControlType::None),
410            LIBCAMERA_CONTROL_TYPE_BOOL => Ok(ControlType::Bool),
411            LIBCAMERA_CONTROL_TYPE_BYTE => Ok(ControlType::Byte),
412            LIBCAMERA_CONTROL_TYPE_UINT16 => Ok(ControlType::Uint16),
413            LIBCAMERA_CONTROL_TYPE_UINT32 => Ok(ControlType::Uint32),
414            LIBCAMERA_CONTROL_TYPE_INT32 => Ok(ControlType::Int32),
415            LIBCAMERA_CONTROL_TYPE_INT64 => Ok(ControlType::Int64),
416            LIBCAMERA_CONTROL_TYPE_FLOAT => Ok(ControlType::Float),
417            LIBCAMERA_CONTROL_TYPE_STRING => Ok(ControlType::String),
418            LIBCAMERA_CONTROL_TYPE_RECTANGLE => Ok(ControlType::Rectangle),
419            LIBCAMERA_CONTROL_TYPE_SIZE => Ok(ControlType::Size),
420            LIBCAMERA_CONTROL_TYPE_POINT => Ok(ControlType::Point),
421            unknown => Err(ControlTypeError::UnknownType(unknown)),
422        }
423    }
424}
425
426impl From<ControlType> for u32 {
427    fn from(control_type: ControlType) -> Self {
428        control_type as u32
429    }
430}
431
432impl From<&ControlValue> for ControlType {
433    fn from(control_value: &ControlValue) -> Self {
434        match control_value {
435            ControlValue::None => ControlType::None,
436            ControlValue::Bool(_) => ControlType::Bool,
437            ControlValue::Byte(_) => ControlType::Byte,
438            ControlValue::Uint16(_) => ControlType::Uint16,
439            ControlValue::Uint32(_) => ControlType::Uint32,
440            ControlValue::Int32(_) => ControlType::Int32,
441            ControlValue::Int64(_) => ControlType::Int64,
442            ControlValue::Float(_) => ControlType::Float,
443            ControlValue::String(_) => ControlType::String,
444            ControlValue::Rectangle(_) => ControlType::Rectangle,
445            ControlValue::Size(_) => ControlType::Size,
446            ControlValue::Point(_) => ControlType::Point,
447        }
448    }
449}
450
451impl TryFrom<ControlValue> for ControlType {
452    type Error = ControlTypeError;
453
454    fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
455        Ok(ControlType::from(&value))
456    }
457}