use super::Mio;
use crate::result::{Error, Result};
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Address {
Memory(usize),
Io(usize),
}
impl Address {
pub const MIN: usize = 0;
pub const MAX: usize = 0x1ffff;
pub const fn new() -> Self {
Self::Memory(Self::MIN)
}
pub const fn memory(self) -> usize {
match self {
Self::Memory(addr) => addr,
_ => 0,
}
}
pub const fn io(self) -> usize {
match self {
Self::Io(addr) => addr,
_ => 0,
}
}
pub const fn from_parts(mio: Mio, addr: usize) -> Self {
match Self::try_from_parts(mio, addr) {
Ok(addr) => addr,
Err(_err) => panic!("command::arg::address: invalid field value, min: 0, max: 0x1ffff"),
}
}
pub const fn try_from_parts(mio: Mio, addr: usize) -> Result<Self> {
if addr > Self::MAX {
Err(Error::invalid_field_value(
"command::arg::address",
addr,
Self::MIN,
Self::MAX,
))
} else {
match mio {
Mio::Memory => Ok(Self::Memory(addr)),
Mio::Io => Ok(Self::Io(addr)),
}
}
}
pub const fn into_parts(self) -> (Mio, usize) {
match self {
Self::Memory(addr) => (Mio::Memory, addr),
Self::Io(addr) => (Mio::Io, addr),
}
}
}
impl Default for Address {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fields() {
(1..=usize::BITS)
.map(|r| ((1u128 << r) - 1) as usize)
.for_each(|addr| match Address::try_from_parts(Mio::Memory, addr) {
Ok(exp_addr) => {
let exp_mem = Address::Memory(addr);
let exp_io = Address::Io(addr);
assert_eq!(Address::try_from_parts(Mio::Memory, addr), Ok(exp_mem));
assert_eq!(Address::from_parts(Mio::Memory, addr), exp_mem);
assert_eq!(exp_mem.into_parts(), (Mio::Memory, addr));
assert_eq!(Address::try_from_parts(Mio::Io, addr), Ok(exp_io));
assert_eq!(Address::from_parts(Mio::Io, addr), exp_io);
assert_eq!(exp_io.into_parts(), (Mio::Io, addr));
}
Err(exp_err) => {
assert_eq!(Address::try_from_parts(Mio::Memory, addr), Err(exp_err));
assert_eq!(Address::try_from_parts(Mio::Io, addr), Err(exp_err));
}
});
}
}