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 crate::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 {
from(handle: Handle) -> Self30     fn from(handle: Handle) -> Self {
31         handle.0
32     }
33 }
34 
35 impl From<Handle> for u32 {
from(handle: Handle) -> Self36     fn from(handle: Handle) -> Self {
37         handle.0.into()
38     }
39 }
40 
41 impl From<RawResourceHandle> for Handle {
from(handle: RawResourceHandle) -> Self42     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 {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result52     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)]
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.
handle(&self) -> Handle69     pub fn handle(&self) -> Handle {
70         self.handle
71     }
72 
73     /// Returns the name of this property.
name(&self) -> &std::ffi::CStr74     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.
value_type(&self) -> ValueType79     pub fn value_type(&self) -> ValueType {
80         self.val_type.clone()
81     }
82 
83     /// Returns whether this property is mutable.
mutable(&self) -> bool84     pub fn mutable(&self) -> bool {
85         self.mutable
86     }
87 
88     /// Returns whether this property can be atomically updated.
atomic(&self) -> bool89     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`]
convert_value(&self, value: RawValue) -> Value131     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)]
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 {
from(value: Value<'a>) -> Self187     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 
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
as_boolean(&self) -> Option<bool>220     pub fn as_boolean(&self) -> Option<bool> {
221         match_variant!(self, Boolean)
222     }
223 
224     /// Unsigned range value
as_unsigned_range(&self) -> Option<u64>225     pub fn as_unsigned_range(&self) -> Option<u64> {
226         match_variant!(self, UnsignedRange)
227     }
228 
229     /// Signed range value
as_signed_range(&self) -> Option<i64>230     pub fn as_signed_range(&self) -> Option<i64> {
231         match_variant!(self, SignedRange)
232     }
233 
234     /// Enum Value
as_enum(&self) -> Option<&'a EnumValue>235     pub fn as_enum(&self) -> Option<&'a EnumValue> {
236         match_variant!(self, Enum).flatten()
237     }
238 
239     /// Bitmask value
as_bitmask(&self) -> Option<u64>240     pub fn as_bitmask(&self) -> Option<u64> {
241         match_variant!(self, Bitmask)
242     }
243 
244     /// Opaque (blob) value
as_blob(&self) -> Option<u64>245     pub fn as_blob(&self) -> Option<u64> {
246         match_variant!(self, Blob)
247     }
248 
249     /// Unknown object value
as_object(&self) -> Option<RawResourceHandle>250     pub fn as_object(&self) -> Option<RawResourceHandle> {
251         match_variant!(self, Object).flatten()
252     }
253 
254     /// Crtc object value
as_crtc(&self) -> Option<super::crtc::Handle>255     pub fn as_crtc(&self) -> Option<super::crtc::Handle> {
256         match_variant!(self, CRTC).flatten()
257     }
258 
259     /// Connector object value
as_connector(&self) -> Option<super::connector::Handle>260     pub fn as_connector(&self) -> Option<super::connector::Handle> {
261         match_variant!(self, Connector).flatten()
262     }
263 
264     /// Encoder object value
as_encoder(&self) -> Option<super::encoder::Handle>265     pub fn as_encoder(&self) -> Option<super::encoder::Handle> {
266         match_variant!(self, Encoder).flatten()
267     }
268 
269     /// Framebuffer object value
as_framebuffer(&self) -> Option<super::framebuffer::Handle>270     pub fn as_framebuffer(&self) -> Option<super::framebuffer::Handle> {
271         match_variant!(self, Framebuffer).flatten()
272     }
273 
274     /// Plane object value
as_plane(&self) -> Option<super::plane::Handle>275     pub fn as_plane(&self) -> Option<super::plane::Handle> {
276         match_variant!(self, Plane).flatten()
277     }
278 
279     /// Property object value
as_property(&self) -> Option<Handle>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
value(&self) -> RawValue292     pub fn value(&self) -> RawValue {
293         self.0.value
294     }
295 
296     /// Returns the name of this value
name(&self) -> &std::ffi::CStr297     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 {
from(inner: ffi::drm_mode_property_enum) -> Self303     fn from(inner: ffi::drm_mode_property_enum) -> Self {
304         EnumValue(inner)
305     }
306 }
307 
308 impl std::fmt::Debug for EnumValue {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result309     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)]
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
values(&self) -> (&[RawValue], &[EnumValue])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`].
get_value_from_raw_value(&self, value: RawValue) -> Option<&EnumValue>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 }
343