1use num::BigInt;
2use std::fmt::{Debug, Display, Formatter};
3use std::num::{NonZero, NonZeroU8};
4
5pub const BOOL: Type = Type::int(1);
7pub const I8: Type = Type::int(8);
9pub const I16: Type = Type::int(16);
11pub const I32: Type = Type::int(32);
13pub const I64: Type = Type::int(64);
15
16pub const TYPES: [Type; 5] = [BOOL, I8, I16, I32, I64];
18
19#[derive(Copy, Clone, Eq, PartialEq, Hash)]
21pub enum Type {
22 Int(NonZeroU8),
24}
25
26impl Type {
27 pub fn bit_width(&self) -> u32 {
29 match self {
30 Type::Int(w) => w.get().into(),
31 }
32 }
33}
34
35impl Type {
36 pub const fn int(n: u8) -> Self {
38 if n == 0 {
39 panic!("Cannot have i0");
40 }
41
42 Self::Int(unsafe { NonZero::new_unchecked(n) })
44 }
45
46 #[inline]
48 pub fn is_bool(&self) -> bool {
49 matches!(self, Self::Int(w) if w.get() == 1)
50 }
51
52 #[inline]
54 pub fn max_val(&self) -> BigInt {
55 match self {
56 Type::Int(w) => (BigInt::from(1) << w.get()) - 1,
57 }
58 }
59}
60
61impl Display for Type {
62 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
63 match self {
64 Type::Int(w) => write!(f, "i{}", w),
65 }
66 }
67}
68
69impl Debug for Type {
70 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71 match self {
72 Type::Int(w) => write!(f, "I{}", w),
73 }
74 }
75}
76
77impl TryFrom<&str> for Type {
78 type Error = ();
79
80 fn try_from(value: &str) -> Result<Self, Self::Error> {
81 match value {
82 "i1" | "bool" => Ok(BOOL),
83 "i8" => Ok(I8),
84 "i16" => Ok(I16),
85 "i32" => Ok(I32),
86 "i64" => Ok(I64),
87 _ => Err(()),
88 }
89 }
90}
91
92#[cfg(feature = "arbitrary")]
93impl<'a> arbitrary::Arbitrary<'a> for Type {
94 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
95 let variant = u.int_in_range(0..=4)?;
96 let ty = match variant {
97 0 => BOOL,
98 1 => I8,
99 2 => I16,
100 3 => I32,
101 4 => I64,
102 _ => unreachable!(),
103 };
104
105 Ok(ty)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_display() {
115 let actual = &[BOOL, I8, I16, I32, I64]
116 .iter()
117 .map(|ty| ty.to_string())
118 .collect::<Vec<_>>()
119 .join(", ");
120 let expected = "i1, i8, i16, i32, i64";
121 assert_eq!(actual, expected)
122 }
123
124 #[test]
125 fn test_debug() {
126 let actual = &[BOOL, I8, I16, I32, I64]
127 .iter()
128 .map(|ty| format!("{ty:?}"))
129 .collect::<Vec<_>>()
130 .join(", ");
131 let expected = "I1, I8, I16, I32, I64";
132 assert_eq!(actual, expected)
133 }
134}