ryzenadj 0.1.0

Safe Rust interface to RyzenAdj
use ryzenadj_sys as sys;
use thiserror::Error;

#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
pub enum Error {
    #[error("RyzenAdj initialization failed")]
    InitializationFailed,
    #[error("RyzenAdj is already in use")]
    AlreadyInUse,
    #[error(
        "invalid core address (CCD {ccd}, CCX {ccx}, core {core}): each index must be in 0..=15"
    )]
    InvalidCoreAddress { ccd: u8, ccx: u8, core: u8 },
    #[error("per-core Curve Optimizer offset {0} is outside -32768..=32767")]
    PerCoreCurveOptimizerOffsetOutOfRange(i32),
    #[error("per-core OC clock {0} MHz exceeds the 20-bit field maximum of 1048575 MHz")]
    PerCoreOcClockOutOfRange(u32),
    #[error("CPU family is unsupported")]
    UnsupportedFamily,
    #[error("SMU request timed out")]
    SmuTimeout,
    #[error("SMU command is unsupported")]
    SmuUnsupported,
    #[error("SMU command was rejected")]
    SmuRejected,
    #[error("physical memory access failed")]
    MemoryAccess,
    #[error("RyzenAdj returned unknown status {0}")]
    UnknownStatus(i32),
}

pub type Result<T> = std::result::Result<T, Error>;

pub(crate) trait StatusCode {
    fn check(self) -> Result<()>;
}

impl StatusCode for i32 {
    fn check(self) -> Result<()> {
        match self {
            0 => Ok(()),
            sys::ADJ_ERR_FAM_UNSUPPORTED => Err(Error::UnsupportedFamily),
            sys::ADJ_ERR_SMU_TIMEOUT => Err(Error::SmuTimeout),
            sys::ADJ_ERR_SMU_UNSUPPORTED => Err(Error::SmuUnsupported),
            sys::ADJ_ERR_SMU_REJECTED => Err(Error::SmuRejected),
            sys::ADJ_ERR_MEMORY_ACCESS => Err(Error::MemoryAccess),
            code => Err(Error::UnknownStatus(code)),
        }
    }
}