rdif-reset 0.1.0

Driver Interface reset controller definition.
Documentation
#![no_std]

extern crate alloc;

use rdif_base::def_driver;
pub use rdif_base::{DriverGeneric, custom_type};

custom_type!(
    #[doc = "Reset signal id"],
    ResetId, u64, "{:#x}");

impl ResetId {
    pub const fn new(value: u64) -> Self {
        Self(value)
    }
}

impl From<u32> for ResetId {
    fn from(value: u32) -> Self {
        Self(u64::from(value))
    }
}

impl From<usize> for ResetId {
    fn from(value: usize) -> Self {
        Self(value as u64)
    }
}

#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResetError {
    #[error("invalid reset id")]
    InvalidId,
    #[error("unsupported reset operation")]
    Unsupported,
    #[error("reset controller is busy")]
    Busy,
    #[error("reset controller error")]
    Controller,
}

pub trait Interface: DriverGeneric {
    fn assert(&mut self, id: ResetId) -> Result<(), ResetError>;

    fn deassert(&mut self, id: ResetId) -> Result<(), ResetError>;

    fn reset(&mut self, id: ResetId) -> Result<(), ResetError> {
        self.assert(id)?;
        self.deassert(id)
    }
}

def_driver!(Reset, Interface);

#[cfg(test)]
mod tests {
    use super::*;

    struct RecordingReset {
        calls: alloc::vec::Vec<(&'static str, ResetId)>,
    }

    impl DriverGeneric for RecordingReset {
        fn name(&self) -> &str {
            "recording-reset"
        }
    }

    impl Interface for RecordingReset {
        fn assert(&mut self, id: ResetId) -> Result<(), ResetError> {
            self.calls.push(("assert", id));
            Ok(())
        }

        fn deassert(&mut self, id: ResetId) -> Result<(), ResetError> {
            self.calls.push(("deassert", id));
            Ok(())
        }
    }

    #[test]
    fn reset_id_conversions_preserve_raw_value() {
        assert_eq!(ResetId::new(7).raw(), 7);
        assert_eq!(ResetId::from(8_u32).raw(), 8);
        assert_eq!(ResetId::from(9_usize).raw(), 9);
        assert_eq!(ResetId::from(10_u64).raw(), 10);
    }

    #[test]
    fn reset_pulses_assert_then_deassert() {
        let mut reset = RecordingReset {
            calls: alloc::vec::Vec::new(),
        };

        reset.reset(ResetId::new(3)).unwrap();

        assert_eq!(
            reset.calls,
            alloc::vec![("assert", ResetId::new(3)), ("deassert", ResetId::new(3))]
        );
    }

    #[test]
    fn reset_wrapper_exposes_typed_driver() {
        let mut reset = Reset::new(RecordingReset {
            calls: alloc::vec::Vec::new(),
        });

        assert!(reset.typed_ref::<RecordingReset>().is_some());
        assert!(reset.typed_mut::<RecordingReset>().is_some());
    }
}