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 #[error("Expected type {expected}, found {found}")]
13 InvalidType { expected: u32, found: u32 },
14 #[error("Unknown control type {0}")]
16 UnknownType(u32),
17 #[error("Expected {expected} elements, found {found}")]
19 InvalidLength { expected: usize, found: usize },
20 #[error("Unknown enum variant {0:?}")]
22 UnknownVariant(ControlValue),
23}
24
25#[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 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 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 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 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 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}