use core::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize)]
pub enum Scalar {
Bool,
I8,
I16,
I32,
I64,
U8,
U16,
U32,
U64,
F16,
F32,
F64,
}
impl Scalar {
pub const fn bits(self) -> u32 {
match self {
Scalar::Bool => 1,
Scalar::I8 | Scalar::U8 => 8,
Scalar::I16 | Scalar::U16 | Scalar::F16 => 16,
Scalar::I32 | Scalar::U32 | Scalar::F32 => 32,
Scalar::I64 | Scalar::U64 | Scalar::F64 => 64,
}
}
pub const fn is_float(self) -> bool {
matches!(self, Scalar::F16 | Scalar::F32 | Scalar::F64)
}
pub const fn is_signed(self) -> bool {
matches!(self, Scalar::I8 | Scalar::I16 | Scalar::I32 | Scalar::I64)
}
pub const fn is_unsigned(self) -> bool {
matches!(self, Scalar::U8 | Scalar::U16 | Scalar::U32 | Scalar::U64)
}
pub const fn is_integer(self) -> bool {
self.is_signed() || self.is_unsigned()
}
pub const fn name(self) -> &'static str {
match self {
Scalar::Bool => "bool",
Scalar::I8 => "i8",
Scalar::I16 => "i16",
Scalar::I32 => "i32",
Scalar::I64 => "i64",
Scalar::U8 => "u8",
Scalar::U16 => "u16",
Scalar::U32 => "u32",
Scalar::U64 => "u64",
Scalar::F16 => "f16",
Scalar::F32 => "f32",
Scalar::F64 => "f64",
}
}
pub fn parse(name: &str) -> Option<Scalar> {
Some(match name {
"bool" => Scalar::Bool,
"i8" => Scalar::I8,
"i16" => Scalar::I16,
"i32" => Scalar::I32,
"i64" => Scalar::I64,
"u8" => Scalar::U8,
"u16" => Scalar::U16,
"u32" => Scalar::U32,
"u64" => Scalar::U64,
"f16" => Scalar::F16,
"f32" => Scalar::F32,
"f64" => Scalar::F64,
_ => return None,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize)]
pub struct Type {
pub scalar: Scalar,
pub lanes: u8,
}
impl Type {
pub const fn scalar(scalar: Scalar) -> Type {
Type { scalar, lanes: 1 }
}
pub const fn vector(scalar: Scalar, lanes: u8) -> Type {
Type { scalar, lanes }
}
pub const F32: Type = Type::scalar(Scalar::F32);
pub const F32X4: Type = Type::vector(Scalar::F32, 4);
pub const U32: Type = Type::scalar(Scalar::U32);
pub const U32X4: Type = Type::vector(Scalar::U32, 4);
pub const I32: Type = Type::scalar(Scalar::I32);
pub const BOOL: Type = Type::scalar(Scalar::Bool);
pub const fn with(self, scalar: Scalar) -> Type {
Type {
scalar,
lanes: self.lanes,
}
}
pub const fn is_valid(self) -> bool {
self.lanes >= 1 && self.lanes <= 4
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.lanes == 1 {
f.write_str(self.scalar.name())
} else {
write!(f, "vec{}<{}>", self.lanes, self.scalar.name())
}
}
}