use acir::{
AcirField,
brillig::{BitSize, IntegerBitSize},
};
use crate::MemoryValue;
pub(crate) fn cast<F: AcirField>(
source_value: MemoryValue<F>,
target_bit_size: BitSize,
) -> MemoryValue<F> {
use MemoryValue::*;
match (source_value, target_bit_size) {
(Field(field), BitSize::Integer(target_bit_size)) => {
let as_u128 = field.to_u128();
match target_bit_size {
IntegerBitSize::U1 => U1(as_u128 & 0x01 == 1),
IntegerBitSize::U8 => U8(as_u128 as u8),
IntegerBitSize::U16 => U16(as_u128 as u16),
IntegerBitSize::U32 => U32(as_u128 as u32),
IntegerBitSize::U64 => U64(as_u128 as u64),
IntegerBitSize::U128 => U128(as_u128),
}
}
(U1(value), BitSize::Integer(IntegerBitSize::U8)) => U8(value.into()),
(U1(value), BitSize::Integer(IntegerBitSize::U16)) => U16(value.into()),
(U1(value), BitSize::Integer(IntegerBitSize::U32)) => U32(value.into()),
(U1(value), BitSize::Integer(IntegerBitSize::U64)) => U64(value.into()),
(U1(value), BitSize::Integer(IntegerBitSize::U128)) => U128(value.into()),
(U1(value), BitSize::Field) => Field(value.into()),
(U8(value), BitSize::Integer(IntegerBitSize::U1)) => U1(value & 0x01 == 1),
(U8(value), BitSize::Integer(IntegerBitSize::U16)) => U16(value.into()),
(U8(value), BitSize::Integer(IntegerBitSize::U32)) => U32(value.into()),
(U8(value), BitSize::Integer(IntegerBitSize::U64)) => U64(value.into()),
(U8(value), BitSize::Integer(IntegerBitSize::U128)) => U128(value.into()),
(U8(value), BitSize::Field) => Field((value as u128).into()),
(U16(value), BitSize::Integer(IntegerBitSize::U1)) => U1(value & 0x01 == 1),
(U16(value), BitSize::Integer(IntegerBitSize::U8)) => U8(value as u8),
(U16(value), BitSize::Integer(IntegerBitSize::U32)) => U32(value.into()),
(U16(value), BitSize::Integer(IntegerBitSize::U64)) => U64(value.into()),
(U16(value), BitSize::Integer(IntegerBitSize::U128)) => U128(value.into()),
(U16(value), BitSize::Field) => Field((value as u128).into()),
(U32(value), BitSize::Integer(IntegerBitSize::U1)) => U1(value & 0x01 == 1),
(U32(value), BitSize::Integer(IntegerBitSize::U8)) => U8(value as u8),
(U32(value), BitSize::Integer(IntegerBitSize::U16)) => U16(value as u16),
(U32(value), BitSize::Integer(IntegerBitSize::U64)) => U64(value.into()),
(U32(value), BitSize::Integer(IntegerBitSize::U128)) => U128(value.into()),
(U32(value), BitSize::Field) => Field((value as u128).into()),
(U64(value), BitSize::Integer(IntegerBitSize::U1)) => U1(value & 0x01 == 1),
(U64(value), BitSize::Integer(IntegerBitSize::U8)) => U8(value as u8),
(U64(value), BitSize::Integer(IntegerBitSize::U16)) => U16(value as u16),
(U64(value), BitSize::Integer(IntegerBitSize::U32)) => U32(value as u32),
(U64(value), BitSize::Integer(IntegerBitSize::U128)) => U128(value.into()),
(U64(value), BitSize::Field) => Field((value as u128).into()),
(U128(value), BitSize::Integer(IntegerBitSize::U1)) => U1(value & 0x01 == 1),
(U128(value), BitSize::Integer(IntegerBitSize::U8)) => U8(value as u8),
(U128(value), BitSize::Integer(IntegerBitSize::U16)) => U16(value as u16),
(U128(value), BitSize::Integer(IntegerBitSize::U32)) => U32(value as u32),
(U128(value), BitSize::Integer(IntegerBitSize::U64)) => U64(value as u64),
(U128(value), BitSize::Field) => Field(value.into()),
(Field(_), BitSize::Field) => source_value,
(U1(_), BitSize::Integer(IntegerBitSize::U1)) => source_value,
(U8(_), BitSize::Integer(IntegerBitSize::U8)) => source_value,
(U16(_), BitSize::Integer(IntegerBitSize::U16)) => source_value,
(U32(_), BitSize::Integer(IntegerBitSize::U32)) => source_value,
(U64(_), BitSize::Integer(IntegerBitSize::U64)) => source_value,
(U128(_), BitSize::Integer(IntegerBitSize::U128)) => source_value,
}
}