Skip to main content

rkg_utils/header/
controller.rs

1use std::convert::Infallible;
2use std::fmt::Display;
3
4use crate::byte_handler::{ByteHandlerError, FromByteHandler};
5
6/// Errors that can occur while constructing a [`Controller`].
7#[derive(thiserror::Error, Debug)]
8pub enum ControllerError {
9    /// The controller ID byte did not map to any known [`Controller`] variant.
10    #[error("Nonexistent Controller ID")]
11    NonexistentControllerID,
12    /// A `ByteHandler` operation failed.
13    #[error("ByteHandler Error: {0}")]
14    ByteHandlerError(#[from] ByteHandlerError),
15    /// Infallible conversion error; cannot occur at runtime.
16    #[error("")]
17    Infallible(#[from] Infallible),
18}
19
20/// The input controller used to record a Mario Kart Wii ghost.
21#[derive(Clone, Copy, Debug, PartialEq)]
22pub enum Controller {
23    WiiWheel,
24    Nunchuk,
25    Classic,
26    Gamecube,
27}
28
29/// Formats the controller as its display name (e.g. `"Wii Wheel"`, `"Gamecube"`).
30impl Display for Controller {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        match self {
33            Self::WiiWheel => write!(f, "Wii Wheel"),
34            Self::Nunchuk => write!(f, "Nunchuk"),
35            Self::Classic => write!(f, "Classic"),
36            Self::Gamecube => write!(f, "Gamecube"),
37        }
38    }
39}
40
41/// Deserializes a [`Controller`] from header byte `0x0B`.
42///
43/// The controller ID is stored in the lower nibble of the byte.
44impl FromByteHandler for Controller {
45    type Err = ControllerError;
46
47    fn from_byte_handler<T>(handler: T) -> Result<Self, Self::Err>
48    where
49        T: TryInto<crate::byte_handler::ByteHandler>,
50        Self::Err: From<T::Error>,
51    {
52        (handler.try_into()?.copy_byte(0) & 0x0F).try_into()
53    }
54}
55
56/// Converts a raw byte value from the RKG header into a [`Controller`].
57///
58/// # Errors
59///
60/// Returns [`ControllerError::NonexistentControllerID`] if the byte does not
61/// correspond to any known controller (valid range is 0–3).
62impl TryFrom<u8> for Controller {
63    type Error = ControllerError;
64    fn try_from(value: u8) -> Result<Self, Self::Error> {
65        match value {
66            0 => Ok(Self::WiiWheel),
67            1 => Ok(Self::Nunchuk),
68            2 => Ok(Self::Classic),
69            3 => Ok(Self::Gamecube),
70            _ => Err(ControllerError::NonexistentControllerID),
71        }
72    }
73}
74
75/// Converts a [`Controller`] into its raw byte representation for the RKG header.
76impl From<Controller> for u8 {
77    fn from(value: Controller) -> Self {
78        match value {
79            Controller::WiiWheel => 0,
80            Controller::Nunchuk => 1,
81            Controller::Classic => 2,
82            Controller::Gamecube => 3,
83        }
84    }
85}