1use core::ffi::c_int;
2use std::ffi::CStr;
3
4use bitflags::bitflags;
5use cue_sdk_sys as ffi;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13#[repr(u32)]
14pub enum PropertyId {
15 PropertyArray = ffi::CorsairDevicePropertyId_CDPI_PropertyArray,
16 MicEnabled = ffi::CorsairDevicePropertyId_CDPI_MicEnabled,
17 SurroundSoundEnabled = ffi::CorsairDevicePropertyId_CDPI_SurroundSoundEnabled,
18 SidetoneEnabled = ffi::CorsairDevicePropertyId_CDPI_SidetoneEnabled,
19 EqualizerPreset = ffi::CorsairDevicePropertyId_CDPI_EqualizerPreset,
20 PhysicalLayout = ffi::CorsairDevicePropertyId_CDPI_PhysicalLayout,
21 LogicalLayout = ffi::CorsairDevicePropertyId_CDPI_LogicalLayout,
22 MacroKeyArray = ffi::CorsairDevicePropertyId_CDPI_MacroKeyArray,
23 BatteryLevel = ffi::CorsairDevicePropertyId_CDPI_BatteryLevel,
24 ChannelLedCount = ffi::CorsairDevicePropertyId_CDPI_ChannelLedCount,
25 ChannelDeviceCount = ffi::CorsairDevicePropertyId_CDPI_ChannelDeviceCount,
26 ChannelDeviceLedCountArray = ffi::CorsairDevicePropertyId_CDPI_ChannelDeviceLedCountArray,
27 ChannelDeviceTypeArray = ffi::CorsairDevicePropertyId_CDPI_ChannelDeviceTypeArray,
28}
29
30impl PropertyId {
31 pub(crate) fn to_ffi(self) -> ffi::CorsairDevicePropertyId {
33 self as ffi::CorsairDevicePropertyId
34 }
35}
36
37bitflags! {
42 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
44 pub struct PropertyFlags: u32 {
45 const CAN_READ = ffi::CorsairPropertyFlag_CPF_CanRead;
46 const CAN_WRITE = ffi::CorsairPropertyFlag_CPF_CanWrite;
47 const INDEXED = ffi::CorsairPropertyFlag_CPF_Indexed;
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum DataType {
58 Boolean,
59 Int32,
60 Float64,
61 String,
62 BooleanArray,
63 Int32Array,
64 Float64Array,
65 StringArray,
66}
67
68impl DataType {
69 pub(crate) fn from_ffi(raw: ffi::CorsairDataType) -> Option<Self> {
70 match raw {
71 ffi::CorsairDataType_CT_Boolean => Some(Self::Boolean),
72 ffi::CorsairDataType_CT_Int32 => Some(Self::Int32),
73 ffi::CorsairDataType_CT_Float64 => Some(Self::Float64),
74 ffi::CorsairDataType_CT_String => Some(Self::String),
75 ffi::CorsairDataType_CT_Boolean_Array => Some(Self::BooleanArray),
76 ffi::CorsairDataType_CT_Int32_Array => Some(Self::Int32Array),
77 ffi::CorsairDataType_CT_Float64_Array => Some(Self::Float64Array),
78 ffi::CorsairDataType_CT_String_Array => Some(Self::StringArray),
79 _ => None,
80 }
81 }
82}
83
84#[derive(Debug, Clone, Copy)]
90pub struct PropertyInfo {
91 pub data_type: DataType,
92 pub flags: PropertyFlags,
93}
94
95#[derive(Debug, Clone)]
104pub enum PropertyValue {
105 Boolean(bool),
106 Int32(i32),
107 Float64(f64),
108 String(std::string::String),
109 BooleanArray(Vec<bool>),
110 Int32Array(Vec<i32>),
111 Float64Array(Vec<f64>),
112 StringArray(Vec<std::string::String>),
113}
114
115impl PropertyValue {
116 pub(crate) unsafe fn from_ffi_and_free(prop: &mut ffi::CorsairProperty) -> Option<Self> {
124 let val = match prop.type_ {
128 ffi::CorsairDataType_CT_Boolean => {
129 Some(PropertyValue::Boolean(unsafe { prop.value.boolean }))
131 }
132 ffi::CorsairDataType_CT_Int32 => {
133 Some(PropertyValue::Int32(unsafe { prop.value.int32 }))
135 }
136 ffi::CorsairDataType_CT_Float64 => {
137 Some(PropertyValue::Float64(unsafe { prop.value.float64 }))
139 }
140 ffi::CorsairDataType_CT_String => {
141 let ptr = unsafe { prop.value.string };
143 if ptr.is_null() {
144 Some(PropertyValue::String(std::string::String::new()))
145 } else {
146 let s = unsafe { CStr::from_ptr(ptr) }
148 .to_string_lossy()
149 .into_owned();
150 Some(PropertyValue::String(s))
151 }
152 }
153 ffi::CorsairDataType_CT_Boolean_Array => {
154 let arr = unsafe { prop.value.boolean_array };
156 let slice = if arr.items.is_null() || arr.count == 0 {
157 &[]
158 } else {
159 unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
161 };
162 Some(PropertyValue::BooleanArray(slice.to_vec()))
163 }
164 ffi::CorsairDataType_CT_Int32_Array => {
165 let arr = unsafe { prop.value.int32_array };
167 let slice = if arr.items.is_null() || arr.count == 0 {
168 &[]
169 } else {
170 unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
172 };
173 Some(PropertyValue::Int32Array(slice.to_vec()))
174 }
175 ffi::CorsairDataType_CT_Float64_Array => {
176 let arr = unsafe { prop.value.float64_array };
178 let slice = if arr.items.is_null() || arr.count == 0 {
179 &[]
180 } else {
181 unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
183 };
184 Some(PropertyValue::Float64Array(slice.to_vec()))
185 }
186 ffi::CorsairDataType_CT_String_Array => {
187 let arr = unsafe { prop.value.string_array };
189 let ptrs = if arr.items.is_null() || arr.count == 0 {
190 &[]
191 } else {
192 unsafe { std::slice::from_raw_parts(arr.items, arr.count as usize) }
194 };
195 let strings = ptrs
196 .iter()
197 .map(|&p| {
198 if p.is_null() {
199 std::string::String::new()
200 } else {
201 unsafe { CStr::from_ptr(p) }.to_string_lossy().into_owned()
203 }
204 })
205 .collect();
206 Some(PropertyValue::StringArray(strings))
207 }
208 _ => None,
209 };
210
211 unsafe {
215 let _ = ffi::CorsairFreeProperty(prop as *mut ffi::CorsairProperty);
216 }
217
218 val
219 }
220}
221
222pub(crate) fn make_bool_property(value: bool) -> ffi::CorsairProperty {
224 let mut prop: ffi::CorsairProperty = unsafe { std::mem::zeroed() };
227 prop.type_ = ffi::CorsairDataType_CT_Boolean;
228 prop.value = ffi::CorsairDataValue { boolean: value };
229 prop
230}
231
232pub(crate) fn make_int32_property(value: i32) -> ffi::CorsairProperty {
234 let mut prop: ffi::CorsairProperty = unsafe { std::mem::zeroed() };
236 prop.type_ = ffi::CorsairDataType_CT_Int32;
237 prop.value = ffi::CorsairDataValue {
238 int32: value as c_int,
239 };
240 prop
241}
242
243pub(crate) fn make_float64_property(value: f64) -> ffi::CorsairProperty {
245 let mut prop: ffi::CorsairProperty = unsafe { std::mem::zeroed() };
247 prop.type_ = ffi::CorsairDataType_CT_Float64;
248 prop.value = ffi::CorsairDataValue { float64: value };
249 prop
250}