use crate::{ArrayType, CompositeType, FutureType, Identifier, IntegerType, MappingType, TupleType, common};
use itertools::Itertools;
use leo_span::Symbol;
use serde::{Deserialize, Serialize};
use snarkvm::prelude::{
Network,
PlaintextType,
PlaintextType::{Array, Literal, Struct},
};
use std::fmt;
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Type {
Address,
Array(ArrayType),
Boolean,
Composite(CompositeType),
Field,
Future(FutureType),
Group,
Identifier(Identifier),
Integer(IntegerType),
Mapping(MappingType),
Scalar,
Signature,
String,
Tuple(TupleType),
Unit,
#[default]
Err,
}
impl Type {
pub fn eq_flat_relaxed(&self, other: &Self) -> bool {
match (self, other) {
(Type::Address, Type::Address)
| (Type::Boolean, Type::Boolean)
| (Type::Field, Type::Field)
| (Type::Group, Type::Group)
| (Type::Scalar, Type::Scalar)
| (Type::Signature, Type::Signature)
| (Type::String, Type::String)
| (Type::Unit, Type::Unit) => true,
(Type::Array(left), Type::Array(right)) => {
left.element_type().eq_flat_relaxed(right.element_type()) && left.length() == right.length()
}
(Type::Identifier(left), Type::Identifier(right)) => left.matches(right),
(Type::Integer(left), Type::Integer(right)) => left.eq(right),
(Type::Mapping(left), Type::Mapping(right)) => {
left.key.eq_flat_relaxed(&right.key) && left.value.eq_flat_relaxed(&right.value)
}
(Type::Tuple(left), Type::Tuple(right)) if left.length() == right.length() => left
.elements()
.iter()
.zip_eq(right.elements().iter())
.all(|(left_type, right_type)| left_type.eq_flat_relaxed(right_type)),
(Type::Composite(left), Type::Composite(right)) => left.id.name == right.id.name,
(Type::Future(left), Type::Future(right)) if !left.is_explicit || !right.is_explicit => true,
(Type::Future(left), Type::Future(right)) if left.inputs.len() == right.inputs.len() => left
.inputs()
.iter()
.zip_eq(right.inputs().iter())
.all(|(left_type, right_type)| left_type.eq_flat_relaxed(right_type)),
_ => false,
}
}
pub fn from_snarkvm<N: Network>(t: &PlaintextType<N>, program: Option<Symbol>) -> Self {
match t {
Literal(lit) => match lit {
snarkvm::prelude::LiteralType::Address => Type::Address,
snarkvm::prelude::LiteralType::Boolean => Type::Boolean,
snarkvm::prelude::LiteralType::Field => Type::Field,
snarkvm::prelude::LiteralType::Group => Type::Group,
snarkvm::prelude::LiteralType::U8 => Type::Integer(IntegerType::U8),
snarkvm::prelude::LiteralType::U16 => Type::Integer(IntegerType::U16),
snarkvm::prelude::LiteralType::U32 => Type::Integer(IntegerType::U32),
snarkvm::prelude::LiteralType::U64 => Type::Integer(IntegerType::U64),
snarkvm::prelude::LiteralType::U128 => Type::Integer(IntegerType::U128),
snarkvm::prelude::LiteralType::I8 => Type::Integer(IntegerType::I8),
snarkvm::prelude::LiteralType::I16 => Type::Integer(IntegerType::I16),
snarkvm::prelude::LiteralType::I32 => Type::Integer(IntegerType::I32),
snarkvm::prelude::LiteralType::I64 => Type::Integer(IntegerType::I64),
snarkvm::prelude::LiteralType::I128 => Type::Integer(IntegerType::I128),
snarkvm::prelude::LiteralType::Scalar => Type::Scalar,
snarkvm::prelude::LiteralType::Signature => Type::Signature,
snarkvm::prelude::LiteralType::String => Type::String,
},
Struct(s) => Type::Composite(CompositeType { id: common::Identifier::from(s), program }),
Array(array) => Type::Array(ArrayType::from_snarkvm(array, program)),
}
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Type::Address => write!(f, "address"),
Type::Array(ref array_type) => write!(f, "{array_type}"),
Type::Boolean => write!(f, "bool"),
Type::Field => write!(f, "field"),
Type::Future(ref future_type) => write!(f, "{future_type}"),
Type::Group => write!(f, "group"),
Type::Identifier(ref variable) => write!(f, "{variable}"),
Type::Integer(ref integer_type) => write!(f, "{integer_type}"),
Type::Mapping(ref mapping_type) => write!(f, "{mapping_type}"),
Type::Scalar => write!(f, "scalar"),
Type::Signature => write!(f, "signature"),
Type::String => write!(f, "string"),
Type::Composite(ref struct_type) => write!(f, "{struct_type}"),
Type::Tuple(ref tuple) => write!(f, "{tuple}"),
Type::Unit => write!(f, "()"),
Type::Err => write!(f, "error"),
}
}
}