use core::ffi::c_int;
use std::ffi::CStr;
use bitflags::bitflags;
use cue_sdk_sys as ffi;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum PropertyId {
PropertyArray = ffi::CorsairDevicePropertyId_CDPI_PropertyArray,
MicEnabled = ffi::CorsairDevicePropertyId_CDPI_MicEnabled,
SurroundSoundEnabled = ffi::CorsairDevicePropertyId_CDPI_SurroundSoundEnabled,
SidetoneEnabled = ffi::CorsairDevicePropertyId_CDPI_SidetoneEnabled,
EqualizerPreset = ffi::CorsairDevicePropertyId_CDPI_EqualizerPreset,
PhysicalLayout = ffi::CorsairDevicePropertyId_CDPI_PhysicalLayout,
LogicalLayout = ffi::CorsairDevicePropertyId_CDPI_LogicalLayout,
MacroKeyArray = ffi::CorsairDevicePropertyId_CDPI_MacroKeyArray,
BatteryLevel = ffi::CorsairDevicePropertyId_CDPI_BatteryLevel,
ChannelLedCount = ffi::CorsairDevicePropertyId_CDPI_ChannelLedCount,
ChannelDeviceCount = ffi::CorsairDevicePropertyId_CDPI_ChannelDeviceCount,
ChannelDeviceLedCountArray = ffi::CorsairDevicePropertyId_CDPI_ChannelDeviceLedCountArray,
ChannelDeviceTypeArray = ffi::CorsairDevicePropertyId_CDPI_ChannelDeviceTypeArray,
}
impl PropertyId {
pub(crate) fn to_ffi(self) -> ffi::CorsairDevicePropertyId {
self as ffi::CorsairDevicePropertyId
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PropertyFlags: u32 {
const CAN_READ = ffi::CorsairPropertyFlag_CPF_CanRead;
const CAN_WRITE = ffi::CorsairPropertyFlag_CPF_CanWrite;
const INDEXED = ffi::CorsairPropertyFlag_CPF_Indexed;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataType {
Boolean,
Int32,
Float64,
String,
BooleanArray,
Int32Array,
Float64Array,
StringArray,
}
impl DataType {
pub(crate) fn from_ffi(raw: ffi::CorsairDataType) -> Option<Self> {
match raw {
ffi::CorsairDataType_CT_Boolean => Some(Self::Boolean),
ffi::CorsairDataType_CT_Int32 => Some(Self::Int32),
ffi::CorsairDataType_CT_Float64 => Some(Self::Float64),
ffi::CorsairDataType_CT_String => Some(Self::String),
ffi::CorsairDataType_CT_Boolean_Array => Some(Self::BooleanArray),
ffi::CorsairDataType_CT_Int32_Array => Some(Self::Int32Array),
ffi::CorsairDataType_CT_Float64_Array => Some(Self::Float64Array),
ffi::CorsairDataType_CT_String_Array => Some(Self::StringArray),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PropertyInfo {
pub data_type: DataType,
pub flags: PropertyFlags,
}
#[derive(Debug, Clone)]
pub enum PropertyValue {
Boolean(bool),
Int32(i32),
Float64(f64),
String(std::string::String),
BooleanArray(Vec<bool>),
Int32Array(Vec<i32>),
Float64Array(Vec<f64>),
StringArray(Vec<std::string::String>),
}
impl PropertyValue {
pub(crate) unsafe fn from_ffi_and_free(prop: &mut ffi::CorsairProperty) -> Option<Self> {
let val = match prop.type_ {
ffi::CorsairDataType_CT_Boolean => {
Some(PropertyValue::Boolean(unsafe { prop.value.boolean }))
}
ffi::CorsairDataType_CT_Int32 => {
Some(PropertyValue::Int32(unsafe { prop.value.int32 }))
}
ffi::CorsairDataType_CT_Float64 => {
Some(PropertyValue::Float64(unsafe { prop.value.float64 }))
}
ffi::CorsairDataType_CT_String => {
let ptr = unsafe { prop.value.string };
if ptr.is_null() {
Some(PropertyValue::String(std::string::String::new()))
} else {
let s = unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
Some(PropertyValue::String(s))
}
}
ffi::CorsairDataType_CT_Boolean_Array => {
let arr = unsafe { prop.value.boolean_array };
let slice = if arr.items.is_null() || arr.count == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
};
Some(PropertyValue::BooleanArray(slice.to_vec()))
}
ffi::CorsairDataType_CT_Int32_Array => {
let arr = unsafe { prop.value.int32_array };
let slice = if arr.items.is_null() || arr.count == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
};
Some(PropertyValue::Int32Array(slice.to_vec()))
}
ffi::CorsairDataType_CT_Float64_Array => {
let arr = unsafe { prop.value.float64_array };
let slice = if arr.items.is_null() || arr.count == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
};
Some(PropertyValue::Float64Array(slice.to_vec()))
}
ffi::CorsairDataType_CT_String_Array => {
let arr = unsafe { prop.value.string_array };
let ptrs = if arr.items.is_null() || arr.count == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
};
let strings = ptrs
.iter()
.map(|&p| {
if p.is_null() {
std::string::String::new()
} else {
unsafe { CStr::from_ptr(p) }.to_string_lossy().into_owned()
}
})
.collect();
Some(PropertyValue::StringArray(strings))
}
_ => None,
};
unsafe {
let _ = ffi::CorsairFreeProperty(prop as *mut ffi::CorsairProperty);
}
val
}
}
pub(crate) fn make_bool_property(value: bool) -> ffi::CorsairProperty {
let mut prop: ffi::CorsairProperty = unsafe { std::mem::zeroed() };
prop.type_ = ffi::CorsairDataType_CT_Boolean;
prop.value = ffi::CorsairDataValue { boolean: value };
prop
}
pub(crate) fn make_int32_property(value: i32) -> ffi::CorsairProperty {
let mut prop: ffi::CorsairProperty = unsafe { std::mem::zeroed() };
prop.type_ = ffi::CorsairDataType_CT_Int32;
prop.value = ffi::CorsairDataValue {
int32: value as c_int,
};
prop
}
pub(crate) fn make_float64_property(value: f64) -> ffi::CorsairProperty {
let mut prop: ffi::CorsairProperty = unsafe { std::mem::zeroed() };
prop.type_ = ffi::CorsairDataType_CT_Float64;
prop.value = ffi::CorsairDataValue { float64: value };
prop
}