use std::any::Any;
use std::fmt::{Debug, Display};
use inetnum::asn::Asn;
use super::Operand;
#[derive(Clone, Debug)]
pub enum IrValue {
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
Char(char),
Asn(Asn),
Pointer(usize),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum IrType {
Bool,
U8,
U16,
U32,
U64,
I8,
I16,
I32,
I64,
F32,
F64,
Char,
Asn,
Pointer,
}
impl IrType {
pub fn bytes(&self) -> usize {
use IrType::*;
match self {
Bool | U8 | I8 => 1,
U16 | I16 => 2,
U32 | I32 | F32 | Asn | Char => 4,
U64 | I64 | F64 => 8,
Pointer => (usize::BITS / 8) as usize,
}
}
pub fn alignment(&self) -> usize {
self.bytes()
}
}
impl Display for IrType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use IrType::*;
let s = match self {
Bool => "bool",
U8 => "u8",
U16 => "u16",
U32 => "u32",
U64 => "u64",
I8 => "i8",
I16 => "i16",
I32 => "i32",
I64 => "i64",
F32 => "f32",
F64 => "f64",
Char => "char",
Asn => "Asn",
Pointer => "Pointer",
};
write!(f, "{s}")
}
}
impl PartialEq for IrValue {
fn eq(&self, other: &Self) -> bool {
use IrValue::*;
match (self, other) {
(Bool(l), Bool(r)) => l == r,
(U8(l), U8(r)) => l == r,
(U16(l), U16(r)) => l == r,
(U32(l), U32(r)) => l == r,
(I8(l), I8(r)) => l == r,
(I16(l), I16(r)) => l == r,
(I32(l), I32(r)) => l == r,
(Asn(l), Asn(r)) => l == r,
(Pointer(l), Pointer(r)) => l == r,
_ => panic!("tried comparing different types"),
}
}
}
impl Eq for IrValue {}
impl IrValue {
pub fn get_type(&self) -> IrType {
use IrValue::*;
match self {
Bool(_) => IrType::Bool,
U8(_) => IrType::U8,
U16(_) => IrType::U16,
U32(_) => IrType::U32,
U64(_) => IrType::U32,
I8(_) => IrType::I8,
I16(_) => IrType::I16,
I32(_) => IrType::I32,
I64(_) => IrType::I64,
F32(_) => IrType::F32,
F64(_) => IrType::F64,
Asn(_) => IrType::Asn,
Char(_) => IrType::Char,
Pointer(_) => IrType::Pointer,
}
}
pub fn to_any(&self) -> &dyn Any {
match &self {
Self::Bool(x) => x,
Self::U8(x) => x,
Self::U16(x) => x,
Self::U32(x) => x,
Self::U64(x) => x,
Self::I8(x) => x,
Self::I16(x) => x,
Self::I32(x) => x,
Self::I64(x) => x,
Self::F32(x) => x,
Self::F64(x) => x,
Self::Asn(x) => x,
Self::Char(x) => x,
Self::Pointer(x) => x,
}
}
pub fn from_any(any: Box<dyn Any>) -> Self {
if let Some(x) = any.downcast_ref() {
Self::Bool(*x)
} else if let Some(x) = any.downcast_ref() {
Self::U8(*x)
} else if let Some(x) = any.downcast_ref() {
Self::U16(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::U32(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::U64(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::I8(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::I16(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::I32(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::I64(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::Char(*x)
} else if let Some(x) = any.downcast_ref() {
IrValue::Asn(*x)
} else {
panic!("Could not downcast");
}
}
pub fn as_vec(&self) -> Vec<u8> {
match self {
Self::Bool(b) => (*b as u8).to_ne_bytes().into(),
Self::U8(x) => x.to_ne_bytes().into(),
Self::U16(x) => x.to_ne_bytes().into(),
Self::U32(x) => x.to_ne_bytes().into(),
Self::U64(x) => x.to_ne_bytes().into(),
Self::I8(x) => x.to_ne_bytes().into(),
Self::I16(x) => x.to_ne_bytes().into(),
Self::I32(x) => x.to_ne_bytes().into(),
Self::I64(x) => x.to_ne_bytes().into(),
Self::F32(x) => x.to_ne_bytes().into(),
Self::F64(x) => x.to_ne_bytes().into(),
Self::Asn(x) => x.into_u32().to_ne_bytes().into(),
Self::Char(x) => (*x as u32).to_ne_bytes().into(),
Self::Pointer(x) => x.to_ne_bytes().into(),
}
}
pub fn from_slice(ty: &IrType, val: &[u8]) -> Self {
match ty {
IrType::Bool => {
let val: &[u8; 1] = val.try_into().unwrap();
Self::Bool(match val[0] {
0 => false,
1 => true,
_ => panic!("Invalid bool value"),
})
}
IrType::U8 => {
let val: &[u8; 1] = val.try_into().unwrap();
Self::U8(u8::from_ne_bytes(*val))
}
IrType::U16 => {
let val: &[u8; 2] = val.try_into().unwrap();
Self::U16(u16::from_ne_bytes(*val))
}
IrType::U32 => {
let val: &[u8; 4] = val.try_into().unwrap();
Self::U32(u32::from_ne_bytes(*val))
}
IrType::U64 => {
let val: &[u8; 8] = val.try_into().unwrap();
Self::U64(u64::from_ne_bytes(*val))
}
IrType::I8 => {
let val: &[u8; 1] = val.try_into().unwrap();
Self::I8(i8::from_ne_bytes(*val))
}
IrType::I16 => {
let val: &[u8; 2] = val.try_into().unwrap();
Self::I16(i16::from_ne_bytes(*val))
}
IrType::I32 => {
let val: &[u8; 4] = val.try_into().unwrap();
Self::I32(i32::from_ne_bytes(*val))
}
IrType::I64 => {
let val: &[u8; 8] = val.try_into().unwrap();
Self::I64(i64::from_ne_bytes(*val))
}
IrType::F32 => {
let val: &[u8; 4] = val.try_into().unwrap();
Self::F32(f32::from_ne_bytes(*val))
}
IrType::F64 => {
let val: &[u8; 8] = val.try_into().unwrap();
Self::F64(f64::from_ne_bytes(*val))
}
IrType::Char => {
let val: &[u8; 4] = val.try_into().unwrap();
Self::Char(char::from_u32(u32::from_ne_bytes(*val)).unwrap())
}
IrType::Asn => {
let val: &[u8; 4] = val.try_into().unwrap();
Self::Asn(Asn::from_u32(u32::from_ne_bytes(*val)))
}
IrType::Pointer => {
const SIZE: usize = (usize::BITS / 8) as usize;
let val: &[u8; SIZE] = val.try_into().unwrap();
Self::Pointer(usize::from_ne_bytes(*val))
}
}
}
pub fn as_bool(&self) -> bool {
match self {
IrValue::Bool(x) => *x,
_ => panic!("Invalid value!"),
}
}
pub fn as_u64(&self) -> u64 {
match self {
IrValue::U8(x) => *x as u64,
IrValue::U16(x) => *x as u64,
IrValue::U32(x) => *x as u64,
IrValue::U64(x) => *x,
_ => panic!("Invalid value!"),
}
}
pub fn as_i64(&self) -> i64 {
match self {
IrValue::I8(x) => *x as i64,
IrValue::I16(x) => *x as i64,
IrValue::I32(x) => *x as i64,
IrValue::I64(x) => *x,
_ => panic!("Invalid value!"),
}
}
pub fn as_f64(&self) -> f64 {
match self {
IrValue::F32(x) => *x as f64,
IrValue::F64(x) => *x,
_ => panic!("Invalid value!"),
}
}
pub fn switch_on(&self) -> u32 {
match self {
IrValue::Bool(b) => *b as u32,
IrValue::U8(x) => *x as u32,
IrValue::U16(x) => *x as u32,
IrValue::U32(x) => *x,
_ => todo!(),
}
}
}
impl From<IrValue> for Operand {
fn from(value: IrValue) -> Self {
Operand::Value(value)
}
}
impl Display for IrValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use IrValue::*;
match self {
Bool(x) => write!(f, "bool({x})"),
U8(x) => write!(f, "u8({x})"),
U16(x) => write!(f, "u16({x})"),
U32(x) => write!(f, "u32({x})"),
U64(x) => write!(f, "u64({x})"),
I8(x) => write!(f, "i8({x})"),
I16(x) => write!(f, "i16({x})"),
I32(x) => write!(f, "i32({x})"),
I64(x) => write!(f, "i64({x})"),
F32(x) => write!(f, "f32({x})"),
F64(x) => write!(f, "f64({x})"),
Char(x) => write!(f, "char({x})"),
Asn(x) => write!(f, "Asn({x})"),
Pointer(x) => write!(f, "Pointer({x})"),
}
}
}