use std::convert::{TryFrom, TryInto}; use std::ffi::{CStr}; use std::os::raw::{c_uint}; use std::slice::from_raw_parts; use super::constants::*; use super::ffi::*; #[derive(Clone, Copy, Debug)] pub enum InputDeviceId { None(c_uint), Joypad(JoypadButton), Mouse(MouseButton), Keyboard(c_uint), LightGun(LightGunButton), Analog(AnalogAxis), Pointer(PointerStat), } impl TryFrom<(D, c_uint)> for InputDeviceId where D: TryInto, >::Error: std::error::Error + Send + Sync + 'static, { type Error = Box; fn try_from(pair: (D, c_uint)) -> Result { let (device, id) = pair; Ok(match device.try_into()? { DeviceType::None => InputDeviceId::None(id), DeviceType::Joypad => InputDeviceId::Joypad(JoypadButton::try_from(id)?), DeviceType::Mouse => InputDeviceId::Mouse(MouseButton::try_from(id)?), DeviceType::Keyboard => InputDeviceId::Keyboard(id), DeviceType::LightGun => InputDeviceId::LightGun(LightGunButton::try_from(id)?), DeviceType::Analog => InputDeviceId::Analog(AnalogAxis::try_from(id)?), DeviceType::Pointer => InputDeviceId::Pointer(PointerStat::try_from(id)?), }) } } #[derive(Clone, Debug)] pub struct Variable2 { pub key: String, pub description: String, pub options: Vec, } impl From<&Variable> for Variable2 { fn from(var: &Variable) -> Self { let key = unsafe { CStr::from_ptr(var.key) } .to_string_lossy() .to_string(); let value = unsafe { CStr::from_ptr(var.value) } .to_string_lossy() .to_string(); let split: Vec<&str> = value.splitn(2, "; ").collect(); let description = split.get(0).unwrap_or(&"").to_string(); let options = split .get(1) .unwrap_or(&"") .split('|') .map(String::from) .collect(); Variable2 { key, description, options, } } } #[derive(Clone, Debug)] pub struct ControllerDescription2 { pub name: String, pub base_type: DeviceType, pub subclass: Option, } impl ControllerDescription2 { pub fn device_id(&self) -> c_uint { match self.subclass { None => c_uint::from(self.base_type), Some(sc) => self.base_type.device_subclass(sc), } } } impl TryFrom<&ControllerDescription> for ControllerDescription2 { type Error = (); fn try_from(t: &ControllerDescription) -> Result { let base_type = DeviceType::try_from(t.id & DEVICE_MASK).map_err(|_| ())?; let subclass = match t.id >> DEVICE_TYPE_SHIFT { 0 => None, n => Some(n - 1), }; let name = unsafe { CStr::from_ptr(t.desc) } .to_str() .map_err(|_| ())? .to_string(); Ok(ControllerDescription2 { base_type, subclass, name, }) } } #[derive(Clone, Debug)] pub struct InputDescriptor2 { pub port: c_uint, pub device_id: InputDeviceId, pub index: InputIndex, pub description: String, } impl TryFrom<&InputDescriptor> for InputDescriptor2 { type Error = (); fn try_from(t: &InputDescriptor) -> Result { if t.id >> DEVICE_TYPE_SHIFT != 0 { eprintln!("Device subclass encountered in retro_input_descriptor, ignoring"); } let description = unsafe { CStr::from_ptr(t.description) } .to_str() .map_err(|_| ())? .to_string(); Ok(InputDescriptor2 { port: t.port, device_id: InputDeviceId::try_from((t.device & DEVICE_MASK, t.id)).map_err(|_| ())?, index: InputIndex::try_from(t.index).map_err(|_| ())?, description, }) } } #[derive(Clone, Debug)] pub struct SubsystemInfo2 { pub description: String, pub identifier: String, pub roms: Vec, pub id: c_uint, } impl From<&SubsystemInfo> for SubsystemInfo2 { fn from(si: &SubsystemInfo) -> Self { let rom_slice = unsafe { from_raw_parts(si.roms, si.num_roms as usize) }; SubsystemInfo2 { description: unsafe { CStr::from_ptr(si.desc) } .to_string_lossy() .to_string(), identifier: unsafe { CStr::from_ptr(si.ident) } .to_string_lossy() .to_string(), roms: rom_slice.iter().map(Into::into).collect(), id: si.id, } } } #[derive(Clone, Debug)] pub struct SubsystemRomInfo2 { pub description: String, pub valid_extensions: Vec, pub need_fullpath: bool, pub block_extract: bool, pub required: bool, pub memory: Vec, } impl From<&SubsystemRomInfo> for SubsystemRomInfo2 { fn from(sri: &SubsystemRomInfo) -> Self { let mem_slice = unsafe { from_raw_parts(sri.memory, sri.num_memory as usize) }; SubsystemRomInfo2 { description: unsafe { CStr::from_ptr(sri.desc) } .to_string_lossy() .to_string(), valid_extensions: unsafe { CStr::from_ptr(sri.valid_extensions) } .to_string_lossy() .split('|') .map(str::to_string) .collect(), need_fullpath: sri.need_fullpath, block_extract: sri.block_extract, required: sri.required, memory: mem_slice.iter().map(Into::into).collect(), } } } #[derive(Clone, Debug)] pub struct SubsystemMemoryInfo2 { pub extension: String, pub kind: c_uint, } impl From<&SubsystemMemoryInfo> for SubsystemMemoryInfo2 { fn from(smi: &SubsystemMemoryInfo) -> Self { SubsystemMemoryInfo2 { extension: unsafe { CStr::from_ptr(smi.extension) } .to_string_lossy() .to_string(), kind: smi.kind, } } }