use crate::control::{RawResourceHandle, ResourceHandle};
use drm_ffi as ffi;
pub type RawValue = u64;
#[repr(transparent)]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct Handle(RawResourceHandle);
unsafe impl bytemuck::ZeroableInOption for Handle {}
unsafe impl bytemuck::PodInOption for Handle {}
impl From<Handle> for RawResourceHandle {
fn from(handle: Handle) -> Self {
handle.0
}
}
impl From<Handle> for u32 {
fn from(handle: Handle) -> Self {
handle.0.into()
}
}
impl From<RawResourceHandle> for Handle {
fn from(handle: RawResourceHandle) -> Self {
Handle(handle)
}
}
impl ResourceHandle for Handle {
const FFI_TYPE: u32 = ffi::DRM_MODE_OBJECT_PROPERTY;
}
impl std::fmt::Debug for Handle {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_tuple("property::Handle").field(&self.0).finish()
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Info {
pub(crate) handle: Handle,
pub(crate) val_type: ValueType,
pub(crate) mutable: bool,
pub(crate) atomic: bool,
pub(crate) info: ffi::drm_mode_get_property,
}
impl Info {
pub fn handle(&self) -> Handle {
self.handle
}
pub fn name(&self) -> &std::ffi::CStr {
unsafe { std::ffi::CStr::from_ptr(&self.info.name[0] as _) }
}
pub fn value_type(&self) -> ValueType {
self.val_type.clone()
}
pub fn mutable(&self) -> bool {
self.mutable
}
pub fn atomic(&self) -> bool {
self.atomic
}
}
#[allow(clippy::upper_case_acronyms)]
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ValueType {
Unknown,
Boolean,
UnsignedRange(u64, u64),
SignedRange(i64, i64),
Enum(EnumValues),
Bitmask,
Blob,
Object,
CRTC,
Connector,
Encoder,
Framebuffer,
Plane,
Property,
}
impl ValueType {
pub fn convert_value(&self, value: RawValue) -> Value {
match self {
ValueType::Unknown => Value::Unknown(value),
ValueType::Boolean => Value::Boolean(value != 0),
ValueType::UnsignedRange(_, _) => Value::UnsignedRange(value),
ValueType::SignedRange(_, _) => Value::SignedRange(value as i64),
ValueType::Enum(values) => Value::Enum(values.get_value_from_raw_value(value)),
ValueType::Bitmask => Value::Bitmask(value),
ValueType::Blob => Value::Blob(value),
ValueType::Object => Value::Object(bytemuck::cast(value as u32)),
ValueType::CRTC => Value::CRTC(bytemuck::cast(value as u32)),
ValueType::Connector => Value::Connector(bytemuck::cast(value as u32)),
ValueType::Encoder => Value::Encoder(bytemuck::cast(value as u32)),
ValueType::Framebuffer => Value::Framebuffer(bytemuck::cast(value as u32)),
ValueType::Plane => Value::Plane(bytemuck::cast(value as u32)),
ValueType::Property => Value::Property(bytemuck::cast(value as u32)),
}
}
}
#[allow(missing_docs)]
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum Value<'a> {
Unknown(RawValue),
Boolean(bool),
UnsignedRange(u64),
SignedRange(i64),
Enum(Option<&'a EnumValue>),
Bitmask(u64),
Blob(u64),
Object(Option<RawResourceHandle>),
CRTC(Option<super::crtc::Handle>),
Connector(Option<super::connector::Handle>),
Encoder(Option<super::encoder::Handle>),
Framebuffer(Option<super::framebuffer::Handle>),
Plane(Option<super::plane::Handle>),
Property(Option<Handle>),
}
impl<'a> From<Value<'a>> for RawValue {
fn from(value: Value<'a>) -> Self {
match value {
Value::Unknown(x) => x,
Value::Boolean(true) => 1,
Value::Boolean(false) => 0,
Value::UnsignedRange(x) => x,
Value::SignedRange(x) => x as u64,
Value::Enum(val) => val.map_or(0, EnumValue::value),
Value::Bitmask(x) => x,
Value::Blob(x) => x,
Value::Object(x) => bytemuck::cast::<_, u32>(x) as u64,
Value::CRTC(x) => bytemuck::cast::<_, u32>(x) as u64,
Value::Connector(x) => bytemuck::cast::<_, u32>(x) as u64,
Value::Encoder(x) => bytemuck::cast::<_, u32>(x) as u64,
Value::Framebuffer(x) => bytemuck::cast::<_, u32>(x) as u64,
Value::Plane(x) => bytemuck::cast::<_, u32>(x) as u64,
Value::Property(x) => bytemuck::cast::<_, u32>(x) as u64,
}
}
}
macro_rules! match_variant {
($this:ident, $variant:ident) => {
if let Self::$variant(v) = *$this {
Some(v)
} else {
None
}
};
}
impl<'a> Value<'a> {
pub fn as_boolean(&self) -> Option<bool> {
match_variant!(self, Boolean)
}
pub fn as_unsigned_range(&self) -> Option<u64> {
match_variant!(self, UnsignedRange)
}
pub fn as_signed_range(&self) -> Option<i64> {
match_variant!(self, SignedRange)
}
pub fn as_enum(&self) -> Option<&'a EnumValue> {
match_variant!(self, Enum).flatten()
}
pub fn as_bitmask(&self) -> Option<u64> {
match_variant!(self, Bitmask)
}
pub fn as_blob(&self) -> Option<u64> {
match_variant!(self, Blob)
}
pub fn as_object(&self) -> Option<RawResourceHandle> {
match_variant!(self, Object).flatten()
}
pub fn as_crtc(&self) -> Option<super::crtc::Handle> {
match_variant!(self, CRTC).flatten()
}
pub fn as_connector(&self) -> Option<super::connector::Handle> {
match_variant!(self, Connector).flatten()
}
pub fn as_encoder(&self) -> Option<super::encoder::Handle> {
match_variant!(self, Encoder).flatten()
}
pub fn as_framebuffer(&self) -> Option<super::framebuffer::Handle> {
match_variant!(self, Framebuffer).flatten()
}
pub fn as_plane(&self) -> Option<super::plane::Handle> {
match_variant!(self, Plane).flatten()
}
pub fn as_property(&self) -> Option<Handle> {
match_variant!(self, Property).flatten()
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Hash, PartialEq, Eq, bytemuck::TransparentWrapper)]
pub struct EnumValue(ffi::drm_mode_property_enum);
impl EnumValue {
pub fn value(&self) -> RawValue {
self.0.value
}
pub fn name(&self) -> &std::ffi::CStr {
unsafe { std::ffi::CStr::from_ptr(&self.0.name[0] as _) }
}
}
impl From<ffi::drm_mode_property_enum> for EnumValue {
fn from(inner: ffi::drm_mode_property_enum) -> Self {
EnumValue(inner)
}
}
impl std::fmt::Debug for EnumValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("EnumValue")
.field("value", &self.value())
.field("name", &self.name())
.finish()
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct EnumValues {
pub(crate) values: Vec<u64>,
pub(crate) enums: Vec<EnumValue>,
}
impl EnumValues {
pub fn values(&self) -> (&[RawValue], &[EnumValue]) {
(&self.values, &self.enums)
}
pub fn get_value_from_raw_value(&self, value: RawValue) -> Option<&EnumValue> {
let (values, enums) = self.values();
let index = if values.get(value as usize) == Some(&value) {
value as usize
} else {
values.iter().position(|&v| v == value)?
};
Some(&enums[index])
}
}