use std::collections::HashMap;
use std::convert::TryInto;
use impl_trait_for_tuples::impl_for_tuples;
use crate::bigint256::BigInt256;
use crate::chain::ergo_box::ErgoBox;
use crate::sigma_protocol::sigma_boolean::SigmaBoolean;
use crate::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
use crate::sigma_protocol::sigma_boolean::SigmaProp;
use crate::sigma_protocol::sigma_boolean::{ProveDhTuple, ProveDlog};
use ergo_chain_types::EcPoint;
use super::sfunc::SFunc;
use super::stuple::STuple;
use super::stype_param::STypeVar;
use crate::mir::avl_tree_data::AvlTreeData;
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum SType {
STypeVar(STypeVar),
SAny,
SUnit,
SBoolean,
SByte,
SShort,
SInt,
SLong,
SBigInt,
SGroupElement,
SSigmaProp,
SBox,
SAvlTree,
SOption(Box<SType>),
SColl(Box<SType>),
STuple(STuple),
SFunc(SFunc),
SContext,
SHeader,
SPreHeader,
SGlobal,
}
impl SType {
pub fn is_numeric(&self) -> bool {
matches!(
self,
SType::SByte | SType::SShort | SType::SInt | SType::SLong | SType::SBigInt
)
}
pub fn is_prim(&self) -> bool {
matches!(
self,
SType::SByte
| SType::SShort
| SType::SInt
| SType::SLong
| SType::SBigInt
| SType::SAny
| SType::SGroupElement
| SType::SSigmaProp
| SType::SBox
| SType::SAvlTree
| SType::SContext
| SType::SBoolean
| SType::SHeader
| SType::SPreHeader
| SType::SGlobal
)
}
pub(crate) fn with_subst(self, subst: &HashMap<STypeVar, SType>) -> Self {
match self {
SType::STypeVar(ref tpe_var) => subst.get(tpe_var).cloned().unwrap_or(self),
SType::SOption(tpe) => SType::SOption(tpe.with_subst(subst).into()),
SType::SColl(tpe) => SType::SColl(tpe.with_subst(subst).into()),
SType::STuple(stup) => SType::STuple(stup.with_subst(subst)),
SType::SFunc(sfunc) => SType::SFunc(sfunc.with_subst(subst)),
_ => self,
}
}
}
impl From<STuple> for SType {
fn from(v: STuple) -> Self {
SType::STuple(v)
}
}
impl From<STypeVar> for SType {
fn from(v: STypeVar) -> Self {
SType::STypeVar(v)
}
}
impl From<SFunc> for SType {
fn from(v: SFunc) -> Self {
SType::SFunc(v)
}
}
pub trait LiftIntoSType {
fn stype() -> SType;
}
impl<T: LiftIntoSType> LiftIntoSType for Vec<T> {
fn stype() -> SType {
SType::SColl(Box::new(T::stype()))
}
}
impl LiftIntoSType for bool {
fn stype() -> SType {
SType::SBoolean
}
}
impl LiftIntoSType for u8 {
fn stype() -> SType {
SType::SByte
}
}
impl LiftIntoSType for i8 {
fn stype() -> SType {
SType::SByte
}
}
impl LiftIntoSType for i16 {
fn stype() -> SType {
SType::SShort
}
}
impl LiftIntoSType for i32 {
fn stype() -> SType {
SType::SInt
}
}
impl LiftIntoSType for i64 {
fn stype() -> SType {
SType::SLong
}
}
impl LiftIntoSType for ErgoBox {
fn stype() -> SType {
SType::SBox
}
}
impl LiftIntoSType for SigmaBoolean {
fn stype() -> SType {
SType::SSigmaProp
}
}
impl LiftIntoSType for SigmaProofOfKnowledgeTree {
fn stype() -> SType {
SType::SSigmaProp
}
}
impl LiftIntoSType for SigmaProp {
fn stype() -> SType {
SType::SSigmaProp
}
}
impl LiftIntoSType for ProveDlog {
fn stype() -> SType {
SType::SSigmaProp
}
}
impl LiftIntoSType for EcPoint {
fn stype() -> SType {
SType::SGroupElement
}
}
impl LiftIntoSType for BigInt256 {
fn stype() -> SType {
SType::SBigInt
}
}
impl LiftIntoSType for ProveDhTuple {
fn stype() -> SType {
SType::SSigmaProp
}
}
impl LiftIntoSType for AvlTreeData {
fn stype() -> SType {
SType::SAvlTree
}
}
impl<T: LiftIntoSType> LiftIntoSType for Option<T> {
fn stype() -> SType {
SType::SOption(Box::new(T::stype()))
}
}
#[impl_for_tuples(2, 4)]
#[allow(clippy::unwrap_used)]
impl LiftIntoSType for Tuple {
fn stype() -> SType {
let v: Vec<SType> = [for_tuples!( #( Tuple::stype() ),* )].to_vec();
SType::STuple(v.try_into().unwrap())
}
}
#[cfg(feature = "arbitrary")]
#[allow(clippy::unwrap_used)]
pub(crate) mod tests {
use super::*;
use proptest::prelude::*;
pub(crate) fn primitive_type() -> BoxedStrategy<SType> {
prop_oneof![
Just(SType::SAny),
Just(SType::SBoolean),
Just(SType::SByte),
Just(SType::SShort),
Just(SType::SInt),
Just(SType::SLong),
Just(SType::SBigInt),
Just(SType::SGroupElement),
Just(SType::SSigmaProp),
Just(SType::SBox),
Just(SType::SAvlTree),
Just(SType::SContext),
Just(SType::SHeader),
Just(SType::SPreHeader),
Just(SType::SGlobal),
]
.boxed()
}
impl Arbitrary for SType {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
prop_oneof![primitive_type(), Just(SType::STypeVar(STypeVar::t())),]
.prop_recursive(
4, 64, 16, |elem| {
prop_oneof![
prop::collection::vec(elem.clone(), 2..=5)
.prop_map(|elems| SType::STuple(elems.try_into().unwrap())),
elem.clone().prop_map(|tpe| SType::SColl(Box::new(tpe))),
elem.prop_map(|tpe| SType::SOption(Box::new(tpe))),
]
},
)
.boxed()
}
}
}