use std::fmt::{Debug, Display, Formatter};
use std::num::{NonZero, NonZeroU8};
pub const VOID: Type = Type::Void;
pub const I1: Type = Type::int(1);
pub const I8: Type = Type::int(8);
pub const I16: Type = Type::int(16);
pub const I32: Type = Type::int(32);
pub const I64: Type = Type::int(64);
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum Type {
Void,
Int(NonZeroU8),
}
impl Type {
const fn int(n: u8) -> Self {
if n == 0 {
panic!("Cannot have i0");
}
Self::Int(unsafe { NonZero::new_unchecked(n) })
}
pub fn is_void(&self) -> bool {
matches!(self, Self::Void)
}
}
impl Display for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Type::Void => write!(f, "void"),
Type::Int(w) => write!(f, "i{}", w),
}
}
}
impl Debug for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Type::Void => write!(f, "VOID"),
Type::Int(w) => write!(f, "I{}", w),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display() {
let actual = &[VOID, I1, I8, I16, I32, I64]
.iter()
.map(|ty| ty.to_string())
.collect::<Vec<_>>()
.join(", ");
let expected = "void, i1, i8, i16, i32, i64";
assert_eq!(actual, expected)
}
#[test]
fn test_debug() {
let actual = &[VOID, I1, I8, I16, I32, I64]
.iter()
.map(|ty| format!("{ty:?}"))
.collect::<Vec<_>>()
.join(", ");
let expected = "VOID, I1, I8, I16, I32, I64";
assert_eq!(actual, expected)
}
}