1 | //! # Property |
2 | //! |
3 | //! A property of a modesetting resource. |
4 | //! |
5 | //! All modesetting resources have a set of properties that have values that |
6 | //! can be modified. These properties are modesetting resources themselves, and |
7 | //! may even have their own set of properties. |
8 | //! |
9 | //! Properties may have mutable values attached to them. These can be changed by |
10 | //! either changing the state of a resource (thereby affecting the property), |
11 | //! directly changing the property value itself, or by batching property changes |
12 | //! together and executing them all atomically. |
13 | |
14 | use control::{RawResourceHandle, ResourceHandle}; |
15 | use drm_ffi as ffi; |
16 | |
17 | /// A raw property value that does not have a specific property type |
18 | pub type RawValue = u64; |
19 | |
20 | /// A handle to a property |
21 | #[repr (transparent)] |
22 | #[derive (Copy, Clone, Hash, PartialEq, Eq)] |
23 | pub struct Handle(RawResourceHandle); |
24 | |
25 | // Safety: Handle is repr(transparent) over NonZeroU32 |
26 | unsafe impl bytemuck::ZeroableInOption for Handle {} |
27 | unsafe impl bytemuck::PodInOption for Handle {} |
28 | |
29 | impl From<Handle> for RawResourceHandle { |
30 | fn from(handle: Handle) -> Self { |
31 | handle.0 |
32 | } |
33 | } |
34 | |
35 | impl From<Handle> for u32 { |
36 | fn from(handle: Handle) -> Self { |
37 | handle.0.into() |
38 | } |
39 | } |
40 | |
41 | impl From<RawResourceHandle> for Handle { |
42 | fn from(handle: RawResourceHandle) -> Self { |
43 | Handle(handle) |
44 | } |
45 | } |
46 | |
47 | impl ResourceHandle for Handle { |
48 | const FFI_TYPE: u32 = ffi::DRM_MODE_OBJECT_PROPERTY; |
49 | } |
50 | |
51 | impl std::fmt::Debug for Handle { |
52 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
53 | f.debug_tuple(name:"property::Handle" ).field(&self.0).finish() |
54 | } |
55 | } |
56 | |
57 | /// Information about a property |
58 | #[derive (Debug, Clone, Hash, PartialEq, Eq)] |
59 | pub struct Info { |
60 | pub(crate) handle: Handle, |
61 | pub(crate) val_type: ValueType, |
62 | pub(crate) mutable: bool, |
63 | pub(crate) atomic: bool, |
64 | pub(crate) info: ffi::drm_mode_get_property, |
65 | } |
66 | |
67 | impl Info { |
68 | /// Returns the handle to this property. |
69 | pub fn handle(&self) -> Handle { |
70 | self.handle |
71 | } |
72 | |
73 | /// Returns the name of this property. |
74 | pub fn name(&self) -> &std::ffi::CStr { |
75 | unsafe { std::ffi::CStr::from_ptr(&self.info.name[0] as _) } |
76 | } |
77 | |
78 | /// Returns the ValueType of this property. |
79 | pub fn value_type(&self) -> ValueType { |
80 | self.val_type.clone() |
81 | } |
82 | |
83 | /// Returns whether this property is mutable. |
84 | pub fn mutable(&self) -> bool { |
85 | self.mutable |
86 | } |
87 | |
88 | /// Returns whether this property can be atomically updated. |
89 | pub fn atomic(&self) -> bool { |
90 | self.atomic |
91 | } |
92 | } |
93 | |
94 | /// Describes the types of value that a property uses. |
95 | #[allow (clippy::upper_case_acronyms)] |
96 | #[allow (clippy::large_enum_variant)] |
97 | #[derive (Debug, Clone, Hash, PartialEq, Eq)] |
98 | pub enum ValueType { |
99 | /// A catch-all for any unknown types |
100 | Unknown, |
101 | /// A True or False type |
102 | Boolean, |
103 | /// An unsigned integer that has a min and max value |
104 | UnsignedRange(u64, u64), |
105 | /// A signed integer that has a min and max value |
106 | SignedRange(i64, i64), |
107 | /// A set of values that are mutually exclusive |
108 | Enum(EnumValues), |
109 | /// A set of values that can be combined |
110 | Bitmask, |
111 | /// A chunk of binary data that must be acquired |
112 | Blob, |
113 | /// A non-specific DRM object |
114 | Object, |
115 | /// A CRTC object |
116 | CRTC, |
117 | /// A Connector object |
118 | Connector, |
119 | /// An Encoder object |
120 | Encoder, |
121 | /// A Framebuffer object |
122 | Framebuffer, |
123 | /// A Plane object |
124 | Plane, |
125 | /// A Property object |
126 | Property, |
127 | } |
128 | |
129 | impl ValueType { |
130 | /// Given a [`RawValue`], convert it into a specific [`Value`] |
131 | pub fn convert_value(&self, value: RawValue) -> Value { |
132 | match self { |
133 | ValueType::Unknown => Value::Unknown(value), |
134 | ValueType::Boolean => Value::Boolean(value != 0), |
135 | ValueType::UnsignedRange(_, _) => Value::UnsignedRange(value), |
136 | ValueType::SignedRange(_, _) => Value::SignedRange(value as i64), |
137 | ValueType::Enum(values: &EnumValues) => Value::Enum(values.get_value_from_raw_value(value)), |
138 | ValueType::Bitmask => Value::Bitmask(value), |
139 | ValueType::Blob => Value::Blob(value), |
140 | ValueType::Object => Value::Object(bytemuck::cast(value as u32)), |
141 | ValueType::CRTC => Value::CRTC(bytemuck::cast(value as u32)), |
142 | ValueType::Connector => Value::Connector(bytemuck::cast(value as u32)), |
143 | ValueType::Encoder => Value::Encoder(bytemuck::cast(value as u32)), |
144 | ValueType::Framebuffer => Value::Framebuffer(bytemuck::cast(value as u32)), |
145 | ValueType::Plane => Value::Plane(bytemuck::cast(value as u32)), |
146 | ValueType::Property => Value::Property(bytemuck::cast(value as u32)), |
147 | } |
148 | } |
149 | } |
150 | |
151 | /// The value of a property, in a typed format |
152 | #[allow (missing_docs)] |
153 | #[allow (clippy::upper_case_acronyms)] |
154 | #[derive (Debug, Copy, Clone, Hash, PartialEq, Eq)] |
155 | pub enum Value<'a> { |
156 | /// Unknown value |
157 | Unknown(RawValue), |
158 | /// Boolean value |
159 | Boolean(bool), |
160 | /// Unsigned range value |
161 | UnsignedRange(u64), |
162 | /// Signed range value |
163 | SignedRange(i64), |
164 | /// Enum Value |
165 | Enum(Option<&'a EnumValue>), |
166 | /// Bitmask value |
167 | Bitmask(u64), |
168 | /// Opaque (blob) value |
169 | Blob(u64), |
170 | /// Unknown object value |
171 | Object(Option<RawResourceHandle>), |
172 | /// Crtc object value |
173 | CRTC(Option<super::crtc::Handle>), |
174 | /// Connector object value |
175 | Connector(Option<super::connector::Handle>), |
176 | /// Encoder object value |
177 | Encoder(Option<super::encoder::Handle>), |
178 | /// Framebuffer object value |
179 | Framebuffer(Option<super::framebuffer::Handle>), |
180 | /// Plane object value |
181 | Plane(Option<super::plane::Handle>), |
182 | /// Property object value |
183 | Property(Option<Handle>), |
184 | } |
185 | |
186 | impl<'a> From<Value<'a>> for RawValue { |
187 | fn from(value: Value<'a>) -> Self { |
188 | match value { |
189 | Value::Unknown(x: u64) => x, |
190 | Value::Boolean(true) => 1, |
191 | Value::Boolean(false) => 0, |
192 | Value::UnsignedRange(x: u64) => x, |
193 | Value::SignedRange(x: i64) => x as u64, |
194 | Value::Enum(val: Option<&EnumValue>) => val.map_or(default:0, f:EnumValue::value), |
195 | Value::Bitmask(x: u64) => x, |
196 | Value::Blob(x: u64) => x, |
197 | Value::Object(x: Option>) => bytemuck::cast::<_, u32>(x) as u64, |
198 | Value::CRTC(x: Option) => bytemuck::cast::<_, u32>(x) as u64, |
199 | Value::Connector(x: Option) => bytemuck::cast::<_, u32>(x) as u64, |
200 | Value::Encoder(x: Option) => bytemuck::cast::<_, u32>(x) as u64, |
201 | Value::Framebuffer(x: Option) => bytemuck::cast::<_, u32>(x) as u64, |
202 | Value::Plane(x: Option) => bytemuck::cast::<_, u32>(x) as u64, |
203 | Value::Property(x: Option) => bytemuck::cast::<_, u32>(x) as u64, |
204 | } |
205 | } |
206 | } |
207 | |
208 | macro_rules! match_variant { |
209 | ($this:ident, $variant:ident) => { |
210 | if let Self::$variant(v) = *$this { |
211 | Some(v) |
212 | } else { |
213 | None |
214 | } |
215 | }; |
216 | } |
217 | |
218 | impl<'a> Value<'a> { |
219 | /// Boolean value |
220 | pub fn as_boolean(&self) -> Option<bool> { |
221 | match_variant!(self, Boolean) |
222 | } |
223 | |
224 | /// Unsigned range value |
225 | pub fn as_unsigned_range(&self) -> Option<u64> { |
226 | match_variant!(self, UnsignedRange) |
227 | } |
228 | |
229 | /// Signed range value |
230 | pub fn as_signed_range(&self) -> Option<i64> { |
231 | match_variant!(self, SignedRange) |
232 | } |
233 | |
234 | /// Enum Value |
235 | pub fn as_enum(&self) -> Option<&'a EnumValue> { |
236 | match_variant!(self, Enum).flatten() |
237 | } |
238 | |
239 | /// Bitmask value |
240 | pub fn as_bitmask(&self) -> Option<u64> { |
241 | match_variant!(self, Bitmask) |
242 | } |
243 | |
244 | /// Opaque (blob) value |
245 | pub fn as_blob(&self) -> Option<u64> { |
246 | match_variant!(self, Blob) |
247 | } |
248 | |
249 | /// Unknown object value |
250 | pub fn as_object(&self) -> Option<RawResourceHandle> { |
251 | match_variant!(self, Object).flatten() |
252 | } |
253 | |
254 | /// Crtc object value |
255 | pub fn as_crtc(&self) -> Option<super::crtc::Handle> { |
256 | match_variant!(self, CRTC).flatten() |
257 | } |
258 | |
259 | /// Connector object value |
260 | pub fn as_connector(&self) -> Option<super::connector::Handle> { |
261 | match_variant!(self, Connector).flatten() |
262 | } |
263 | |
264 | /// Encoder object value |
265 | pub fn as_encoder(&self) -> Option<super::encoder::Handle> { |
266 | match_variant!(self, Encoder).flatten() |
267 | } |
268 | |
269 | /// Framebuffer object value |
270 | pub fn as_framebuffer(&self) -> Option<super::framebuffer::Handle> { |
271 | match_variant!(self, Framebuffer).flatten() |
272 | } |
273 | |
274 | /// Plane object value |
275 | pub fn as_plane(&self) -> Option<super::plane::Handle> { |
276 | match_variant!(self, Plane).flatten() |
277 | } |
278 | |
279 | /// Property object value |
280 | pub fn as_property(&self) -> Option<Handle> { |
281 | match_variant!(self, Property).flatten() |
282 | } |
283 | } |
284 | |
285 | /// A single value of [`ValueType::Enum`] type |
286 | #[repr (transparent)] |
287 | #[derive (Copy, Clone, Hash, PartialEq, Eq, bytemuck::TransparentWrapper)] |
288 | pub struct EnumValue(ffi::drm_mode_property_enum); |
289 | |
290 | impl EnumValue { |
291 | /// Returns the [`RawValue`] of this value |
292 | pub fn value(&self) -> RawValue { |
293 | self.0.value |
294 | } |
295 | |
296 | /// Returns the name of this value |
297 | pub fn name(&self) -> &std::ffi::CStr { |
298 | unsafe { std::ffi::CStr::from_ptr(&self.0.name[0] as _) } |
299 | } |
300 | } |
301 | |
302 | impl From<ffi::drm_mode_property_enum> for EnumValue { |
303 | fn from(inner: ffi::drm_mode_property_enum) -> Self { |
304 | EnumValue(inner) |
305 | } |
306 | } |
307 | |
308 | impl std::fmt::Debug for EnumValue { |
309 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
310 | f&mut DebugStruct<'_, '_>.debug_struct("EnumValue" ) |
311 | .field("value" , &self.value()) |
312 | .field(name:"name" , &self.name()) |
313 | .finish() |
314 | } |
315 | } |
316 | |
317 | /// A set of [`EnumValue`]s for a single property |
318 | #[derive (Debug, Clone, Hash, PartialEq, Eq)] |
319 | pub struct EnumValues { |
320 | pub(crate) values: Vec<u64>, |
321 | pub(crate) enums: Vec<EnumValue>, |
322 | } |
323 | |
324 | impl EnumValues { |
325 | /// Returns a tuple containing slices to the [`RawValue`]s and the [`EnumValue`]s |
326 | pub fn values(&self) -> (&[RawValue], &[EnumValue]) { |
327 | (&self.values, &self.enums) |
328 | } |
329 | |
330 | /// Returns an [`EnumValue`] for a [`RawValue`], or [`None`] if `value` is |
331 | /// not part of this [`EnumValues`]. |
332 | pub fn get_value_from_raw_value(&self, value: RawValue) -> Option<&EnumValue> { |
333 | let (values: &[u64], enums: &[EnumValue]) = self.values(); |
334 | let index: usize = if values.get(index:value as usize) == Some(&value) { |
335 | // Early-out: indices match values |
336 | value as usize |
337 | } else { |
338 | values.iter().position(|&v: u64| v == value)? |
339 | }; |
340 | Some(&enums[index]) |
341 | } |
342 | } |
343 | |