use crate::{arena::Arena, binder::Eval, data::PlutusData, machine::MachineError, typ::Type};
#[derive(Debug, PartialEq)]
pub enum Constant<'a> {
Integer(&'a Integer),
ByteString(&'a [u8]),
String(&'a str),
Boolean(bool),
Data(&'a PlutusData<'a>),
ProtoList(&'a Type<'a>, &'a [&'a Constant<'a>]),
ProtoArray(&'a Type<'a>, &'a [&'a Constant<'a>]),
ProtoPair(
&'a Type<'a>,
&'a Type<'a>,
&'a Constant<'a>,
&'a Constant<'a>,
),
Unit,
Bls12_381G1Element(&'a blst::blst_p1),
Bls12_381G2Element(&'a blst::blst_p2),
Bls12_381MlResult(&'a blst::blst_fp12),
}
pub type Integer = num::BigInt;
pub fn integer(arena: &Arena) -> &Integer {
arena.alloc_integer(Integer::default())
}
pub fn integer_from(arena: &Arena, i: i128) -> &Integer {
arena.alloc_integer(Integer::from(i))
}
impl<'a> Constant<'a> {
pub fn integer(arena: &'a Arena, i: &'a Integer) -> &'a Constant<'a> {
arena.alloc(Constant::Integer(i))
}
pub fn integer_from(arena: &'a Arena, i: i128) -> &'a Constant<'a> {
arena.alloc(Constant::Integer(integer_from(arena, i)))
}
pub fn byte_string(arena: &'a Arena, bytes: &'a [u8]) -> &'a Constant<'a> {
arena.alloc(Constant::ByteString(bytes))
}
pub fn string(arena: &'a Arena, s: &'a str) -> &'a Constant<'a> {
arena.alloc(Constant::String(s))
}
pub fn bool(arena: &'a Arena, v: bool) -> &'a Constant<'a> {
arena.alloc(Constant::Boolean(v))
}
pub fn data(arena: &'a Arena, d: &'a PlutusData<'a>) -> &'a Constant<'a> {
arena.alloc(Constant::Data(d))
}
pub fn unit(arena: &'a Arena) -> &'a Constant<'a> {
arena.alloc(Constant::Unit)
}
pub fn proto_list(
arena: &'a Arena,
inner: &'a Type<'a>,
values: &'a [&'a Constant<'a>],
) -> &'a Constant<'a> {
arena.alloc(Constant::ProtoList(inner, values))
}
pub fn proto_array(
arena: &'a Arena,
inner: &'a Type<'a>,
values: &'a [&'a Constant<'a>],
) -> &'a Constant<'a> {
arena.alloc(Constant::ProtoArray(inner, values))
}
pub fn proto_pair(
arena: &'a Arena,
first_type: &'a Type<'a>,
second_type: &'a Type<'a>,
first_value: &'a Constant<'a>,
second_value: &'a Constant<'a>,
) -> &'a Constant<'a> {
arena.alloc(Constant::ProtoPair(
first_type,
second_type,
first_value,
second_value,
))
}
pub fn g1(arena: &'a Arena, g1: &'a blst::blst_p1) -> &'a Constant<'a> {
arena.alloc(Constant::Bls12_381G1Element(g1))
}
pub fn g2(arena: &'a Arena, g2: &'a blst::blst_p2) -> &'a Constant<'a> {
arena.alloc(Constant::Bls12_381G2Element(g2))
}
pub fn ml_result(arena: &'a Arena, ml_res: &'a blst::blst_fp12) -> &'a Constant<'a> {
arena.alloc(Constant::Bls12_381MlResult(ml_res))
}
pub fn unwrap_data<V>(&'a self) -> Result<&'a PlutusData<'a>, MachineError<'a, V>>
where
V: Eval<'a>,
{
match self {
Constant::Data(data) => Ok(data),
_ => Err(MachineError::not_data(self)),
}
}
pub fn type_of(&self, arena: &'a Arena) -> &'a Type<'a> {
match self {
Constant::Integer(_) => Type::integer(arena),
Constant::ByteString(_) => Type::byte_string(arena),
Constant::String(_) => Type::string(arena),
Constant::Boolean(_) => Type::bool(arena),
Constant::Data(_) => Type::data(arena),
Constant::ProtoList(t, _) => Type::list(arena, t),
Constant::ProtoArray(t, _) => Type::array(arena, t),
Constant::ProtoPair(t1, t2, _, _) => Type::pair(arena, t1, t2),
Constant::Unit => Type::unit(arena),
Constant::Bls12_381G1Element(_) => Type::g1(arena),
Constant::Bls12_381G2Element(_) => Type::g2(arena),
Constant::Bls12_381MlResult(_) => Type::ml_result(arena),
}
}
}