libcamera/
control_value.rs

1use std::ptr::NonNull;
2
3use libcamera_sys::*;
4use smallvec::{smallvec, SmallVec};
5use thiserror::Error;
6
7use crate::geometry::{Point, Rectangle, Size};
8
9#[derive(Error, Debug)]
10pub enum ControlValueError {
11    /// Control value type does not match the one being read/written
12    #[error("Expected type {expected}, found {found}")]
13    InvalidType { expected: u32, found: u32 },
14    /// Control value type is not recognized
15    #[error("Unknown control type {0}")]
16    UnknownType(u32),
17    /// Control value dimensionality mismatch
18    #[error("Expected {expected} elements, found {found}")]
19    InvalidLength { expected: usize, found: usize },
20    /// Control value type is correct, but it could not be converted into enum variant
21    #[error("Unknown enum variant {0:?}")]
22    UnknownVariant(ControlValue),
23}
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    Int32(SmallVec<[i32; 1]>),
32    Int64(SmallVec<[i64; 1]>),
33    Float(SmallVec<[f32; 1]>),
34    String(String),
35    Rectangle(SmallVec<[Rectangle; 1]>),
36    Size(SmallVec<[Size; 1]>),
37    // bad gues
38    Point(SmallVec<[Point; 1]>),
39}
40
41macro_rules! impl_control_value {
42    ($p:path, $type:ty) => {
43        impl From<$type> for ControlValue {
44            fn from(val: $type) -> Self {
45                $p(smallvec![val])
46            }
47        }
48
49        impl TryFrom<ControlValue> for $type {
50            type Error = ControlValueError;
51
52            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
53                match value {
54                    $p(mut val) => {
55                        if val.len() == 1 {
56                            Ok(val.pop().unwrap())
57                        } else {
58                            Err(ControlValueError::InvalidLength {
59                                expected: 1,
60                                found: val.len(),
61                            })
62                        }
63                    }
64                    _ => Err(ControlValueError::InvalidType {
65                        // not really efficient, but eh, only on error
66                        expected: $p(Default::default()).ty(),
67                        found: value.ty(),
68                    }),
69                }
70            }
71        }
72    };
73}
74
75impl_control_value!(ControlValue::Bool, bool);
76impl_control_value!(ControlValue::Byte, u8);
77impl_control_value!(ControlValue::Int32, i32);
78impl_control_value!(ControlValue::Int64, i64);
79impl_control_value!(ControlValue::Float, f32);
80impl_control_value!(ControlValue::Rectangle, Rectangle);
81impl_control_value!(ControlValue::Size, Size);
82
83macro_rules! impl_control_value_vec {
84    ($p:path, $type:ty) => {
85        impl From<Vec<$type>> for ControlValue {
86            fn from(val: Vec<$type>) -> Self {
87                $p(SmallVec::from_vec(val))
88            }
89        }
90
91        impl TryFrom<ControlValue> for Vec<$type> {
92            type Error = ControlValueError;
93
94            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
95                match value {
96                    $p(val) => Ok(val.into_vec()),
97                    _ => Err(ControlValueError::InvalidType {
98                        // not really efficient, but eh, only on error
99                        expected: $p(Default::default()).ty(),
100                        found: value.ty(),
101                    }),
102                }
103            }
104        }
105    };
106}
107
108impl_control_value_vec!(ControlValue::Bool, bool);
109impl_control_value_vec!(ControlValue::Byte, u8);
110impl_control_value_vec!(ControlValue::Int32, i32);
111impl_control_value_vec!(ControlValue::Int64, i64);
112impl_control_value_vec!(ControlValue::Float, f32);
113impl_control_value_vec!(ControlValue::Rectangle, Rectangle);
114impl_control_value_vec!(ControlValue::Size, Size);
115impl_control_value_vec!(ControlValue::Point, Point);
116
117macro_rules! impl_control_value_array {
118    ($p:path, $type:ty) => {
119        impl<const N: usize> From<[$type; N]> for ControlValue {
120            fn from(val: [$type; N]) -> Self {
121                $p(SmallVec::from_slice(&val))
122            }
123        }
124
125        impl<const N: usize> TryFrom<ControlValue> for [$type; N] {
126            type Error = ControlValueError;
127
128            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
129                match value {
130                    $p(val) => {
131                        Ok(val
132                            .into_vec()
133                            .try_into()
134                            .map_err(|e: Vec<$type>| ControlValueError::InvalidLength {
135                                expected: N,
136                                found: e.len(),
137                            })?)
138                    }
139                    _ => Err(ControlValueError::InvalidType {
140                        // not really efficient, but eh, only on error
141                        expected: $p(Default::default()).ty(),
142                        found: value.ty(),
143                    }),
144                }
145            }
146        }
147
148        impl<const N: usize, const M: usize> From<[[$type; M]; N]> for ControlValue {
149            fn from(val: [[$type; M]; N]) -> Self {
150                $p(SmallVec::from_slice(&unsafe {
151                    core::slice::from_raw_parts(val.as_ptr().cast(), N * M)
152                }))
153            }
154        }
155
156        impl<const N: usize, const M: usize> TryFrom<ControlValue> for [[$type; M]; N] {
157            type Error = ControlValueError;
158
159            fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
160                match value {
161                    $p(val) => {
162                        if val.len() == N * M {
163                            let mut iter = val.into_iter();
164                            Ok([[(); M]; N].map(|a| a.map(|_| iter.next().unwrap())))
165                        } else {
166                            Err(ControlValueError::InvalidLength {
167                                expected: N * M,
168                                found: val.len(),
169                            })
170                        }
171                    }
172                    _ => Err(ControlValueError::InvalidType {
173                        // not really efficient, but eh, only on error
174                        expected: $p(Default::default()).ty(),
175                        found: value.ty(),
176                    }),
177                }
178            }
179        }
180    };
181}
182
183impl_control_value_array!(ControlValue::Bool, bool);
184impl_control_value_array!(ControlValue::Byte, u8);
185impl_control_value_array!(ControlValue::Int32, i32);
186impl_control_value_array!(ControlValue::Int64, i64);
187impl_control_value_array!(ControlValue::Float, f32);
188impl_control_value_array!(ControlValue::Rectangle, Rectangle);
189impl_control_value_array!(ControlValue::Size, Size);
190
191impl From<String> for ControlValue {
192    fn from(val: String) -> Self {
193        Self::String(val)
194    }
195}
196
197impl TryFrom<ControlValue> for String {
198    type Error = ControlValueError;
199
200    fn try_from(value: ControlValue) -> Result<Self, Self::Error> {
201        match value {
202            ControlValue::String(v) => Ok(v),
203            _ => Err(ControlValueError::InvalidType {
204                expected: libcamera_control_type::LIBCAMERA_CONTROL_TYPE_STRING,
205                found: value.ty(),
206            }),
207        }
208    }
209}
210
211impl ControlValue {
212    pub(crate) unsafe fn read(val: NonNull<libcamera_control_value_t>) -> Result<Self, ControlValueError> {
213        let ty = unsafe { libcamera_control_value_type(val.as_ptr()) };
214        let num_elements = unsafe { libcamera_control_value_num_elements(val.as_ptr()) };
215        let data = unsafe { libcamera_control_value_get(val.as_ptr()) };
216
217        use libcamera_control_type::*;
218        match ty {
219            LIBCAMERA_CONTROL_TYPE_NONE => Ok(Self::None),
220            LIBCAMERA_CONTROL_TYPE_BOOL => {
221                let slice = core::slice::from_raw_parts(data as *const bool, num_elements);
222                Ok(Self::Bool(SmallVec::from_slice(slice)))
223            }
224            LIBCAMERA_CONTROL_TYPE_BYTE => {
225                let slice = core::slice::from_raw_parts(data as *const u8, num_elements);
226                Ok(Self::Byte(SmallVec::from_slice(slice)))
227            }
228            LIBCAMERA_CONTROL_TYPE_INT32 => {
229                let slice = core::slice::from_raw_parts(data as *const i32, num_elements);
230                Ok(Self::Int32(SmallVec::from_slice(slice)))
231            }
232            LIBCAMERA_CONTROL_TYPE_INT64 => {
233                let slice = core::slice::from_raw_parts(data as *const i64, num_elements);
234                Ok(Self::Int64(SmallVec::from_slice(slice)))
235            }
236            LIBCAMERA_CONTROL_TYPE_FLOAT => {
237                let slice = core::slice::from_raw_parts(data as *const f32, num_elements);
238                Ok(Self::Float(SmallVec::from_slice(slice)))
239            }
240            LIBCAMERA_CONTROL_TYPE_STRING => {
241                let slice = core::slice::from_raw_parts(data as *const u8, num_elements);
242                Ok(Self::String(core::str::from_utf8(slice).unwrap().to_string()))
243            }
244            LIBCAMERA_CONTROL_TYPE_RECTANGLE => {
245                let slice = core::slice::from_raw_parts(data as *const libcamera_rectangle_t, num_elements);
246                Ok(Self::Rectangle(SmallVec::from_iter(
247                    slice.iter().map(|r| Rectangle::from(*r)),
248                )))
249            }
250            LIBCAMERA_CONTROL_TYPE_SIZE => {
251                let slice = core::slice::from_raw_parts(data as *const libcamera_size_t, num_elements);
252                Ok(Self::Size(SmallVec::from_iter(slice.iter().map(|r| Size::from(*r)))))
253            }
254            _ => Err(ControlValueError::UnknownType(ty)),
255        }
256    }
257
258    pub(crate) unsafe fn write(&self, val: NonNull<libcamera_control_value_t>) {
259        let (data, len) = match self {
260            ControlValue::None => (core::ptr::null(), 0),
261            ControlValue::Bool(v) => (v.as_ptr().cast(), v.len()),
262            ControlValue::Byte(v) => (v.as_ptr().cast(), v.len()),
263            ControlValue::Int32(v) => (v.as_ptr().cast(), v.len()),
264            ControlValue::Int64(v) => (v.as_ptr().cast(), v.len()),
265            ControlValue::Float(v) => (v.as_ptr().cast(), v.len()),
266            ControlValue::String(v) => (v.as_ptr().cast(), v.len()),
267            ControlValue::Rectangle(v) => (v.as_ptr().cast(), v.len()),
268            ControlValue::Size(v) => (v.as_ptr().cast(), v.len()),
269            ControlValue::Point(v) => (v.as_ptr().cast(), v.len()),
270        };
271
272        let ty = self.ty();
273        let is_array = if ty == libcamera_control_type::LIBCAMERA_CONTROL_TYPE_STRING {
274            true
275        } else {
276            len != 1
277        };
278
279        libcamera_control_value_set(val.as_ptr(), self.ty(), data, is_array, len as _);
280    }
281
282    pub fn ty(&self) -> u32 {
283        use libcamera_control_type::*;
284        match self {
285            ControlValue::None => LIBCAMERA_CONTROL_TYPE_NONE,
286            ControlValue::Bool(_) => LIBCAMERA_CONTROL_TYPE_BOOL,
287            ControlValue::Byte(_) => LIBCAMERA_CONTROL_TYPE_BYTE,
288            ControlValue::Int32(_) => LIBCAMERA_CONTROL_TYPE_INT32,
289            ControlValue::Int64(_) => LIBCAMERA_CONTROL_TYPE_INT64,
290            ControlValue::Float(_) => LIBCAMERA_CONTROL_TYPE_FLOAT,
291            ControlValue::String(_) => LIBCAMERA_CONTROL_TYPE_STRING,
292            ControlValue::Rectangle(_) => LIBCAMERA_CONTROL_TYPE_RECTANGLE,
293            ControlValue::Size(_) => LIBCAMERA_CONTROL_TYPE_SIZE,
294            ControlValue::Point(_) => LIBCAMERA_CONTROL_TYPE_POINT,
295        }
296    }
297}