drm/control/
property.rs

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
14use crate::control::{RawResourceHandle, ResourceHandle};
15use drm_ffi as ffi;
16
17/// A raw property value that does not have a specific property type
18pub type RawValue = u64;
19
20/// A handle to a property
21#[repr(transparent)]
22#[derive(Copy, Clone, Hash, PartialEq, Eq)]
23pub struct Handle(RawResourceHandle);
24
25// Safety: Handle is repr(transparent) over NonZeroU32
26unsafe impl bytemuck::ZeroableInOption for Handle {}
27unsafe impl bytemuck::PodInOption for Handle {}
28
29impl From<Handle> for RawResourceHandle {
30    fn from(handle: Handle) -> Self {
31        handle.0
32    }
33}
34
35impl From<Handle> for u32 {
36    fn from(handle: Handle) -> Self {
37        handle.0.into()
38    }
39}
40
41impl From<RawResourceHandle> for Handle {
42    fn from(handle: RawResourceHandle) -> Self {
43        Handle(handle)
44    }
45}
46
47impl ResourceHandle for Handle {
48    const FFI_TYPE: u32 = ffi::DRM_MODE_OBJECT_PROPERTY;
49}
50
51impl std::fmt::Debug for Handle {
52    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
53        f.debug_tuple("property::Handle").field(&self.0).finish()
54    }
55}
56
57/// Information about a property
58#[derive(Debug, Clone, Hash, PartialEq, Eq)]
59pub 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
67impl 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)]
98pub 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
129impl 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) => 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)]
155pub 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
186impl<'a> From<Value<'a>> for RawValue {
187    fn from(value: Value<'a>) -> Self {
188        match value {
189            Value::Unknown(x) => x,
190            Value::Boolean(true) => 1,
191            Value::Boolean(false) => 0,
192            Value::UnsignedRange(x) => x,
193            Value::SignedRange(x) => x as u64,
194            Value::Enum(val) => val.map_or(0, EnumValue::value),
195            Value::Bitmask(x) => x,
196            Value::Blob(x) => x,
197            Value::Object(x) => bytemuck::cast::<_, u32>(x) as u64,
198            Value::CRTC(x) => bytemuck::cast::<_, u32>(x) as u64,
199            Value::Connector(x) => bytemuck::cast::<_, u32>(x) as u64,
200            Value::Encoder(x) => bytemuck::cast::<_, u32>(x) as u64,
201            Value::Framebuffer(x) => bytemuck::cast::<_, u32>(x) as u64,
202            Value::Plane(x) => bytemuck::cast::<_, u32>(x) as u64,
203            Value::Property(x) => bytemuck::cast::<_, u32>(x) as u64,
204        }
205    }
206}
207
208macro_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
218impl<'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)]
288pub struct EnumValue(ffi::drm_mode_property_enum);
289
290impl 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
302impl From<ffi::drm_mode_property_enum> for EnumValue {
303    fn from(inner: ffi::drm_mode_property_enum) -> Self {
304        EnumValue(inner)
305    }
306}
307
308impl std::fmt::Debug for EnumValue {
309    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
310        f.debug_struct("EnumValue")
311            .field("value", &self.value())
312            .field("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)]
319pub struct EnumValues {
320    pub(crate) values: Vec<u64>,
321    pub(crate) enums: Vec<EnumValue>,
322}
323
324impl 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, enums) = self.values();
334        let index = if values.get(value as usize) == Some(&value) {
335            // Early-out: indices match values
336            value as usize
337        } else {
338            values.iter().position(|&v| v == value)?
339        };
340        Some(&enums[index])
341    }
342}