ferretro/ferretro_base/src/retro/wrapped_types.rs

204 lines
6.0 KiB
Rust

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<D> TryFrom<(D, c_uint)> for InputDeviceId
where D: TryInto<DeviceType>,
<D as std::convert::TryInto<DeviceType>>::Error: std::error::Error + Send + Sync + 'static,
{
type Error = Box<dyn std::error::Error>;
fn try_from(pair: (D, c_uint)) -> Result<Self, Self::Error> {
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<String>,
}
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<c_uint>,
}
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<Self, Self::Error> {
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<Self, Self::Error> {
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<SubsystemRomInfo2>,
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<String>,
pub need_fullpath: bool,
pub block_extract: bool,
pub required: bool,
pub memory: Vec<SubsystemMemoryInfo2>,
}
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,
}
}
}