use crate::canon::CanonicalTypeId;
use crate::engine::Engine;
use crate::value::gc_type::{ArrayType, StructType};
use crate::value::tag_type::TagType;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ValType {
I32,
I64,
F32,
F64,
V128,
Ref(RefType),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum Mutability {
Const,
Var,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RefType {
nullable: bool,
heap: HeapType,
}
impl RefType {
pub fn new(is_nullable: bool, heap_type: HeapType) -> RefType {
RefType {
nullable: is_nullable,
heap: heap_type,
}
}
pub(crate) const fn new_nullable(heap: HeapType) -> RefType {
RefType {
nullable: true,
heap,
}
}
pub fn is_nullable(&self) -> bool {
self.nullable
}
pub fn heap_type(&self) -> &HeapType {
&self.heap
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum HeapType {
Func,
NoFunc,
Extern,
NoExtern,
Any,
Eq,
I31,
Struct,
ConcreteStruct(StructType),
Array,
ConcreteArray(ArrayType),
Exn,
NoExn,
None,
ConcreteFunc(FuncType),
}
impl HeapType {
pub(crate) fn matches(&self, other: &HeapType) -> bool {
use HeapType as H;
if self == other {
return true;
}
matches!(
(self, other),
(H::NoFunc, H::Func | H::ConcreteFunc(_))
| (H::ConcreteFunc(_), H::Func)
| (H::NoExtern, H::Extern)
| (H::NoExn, H::Exn)
| (H::I31 | H::Struct | H::Array | H::Eq, H::Any)
| (H::I31 | H::Struct | H::Array, H::Eq)
| (H::ConcreteStruct(_), H::Struct | H::Eq | H::Any)
| (H::ConcreteArray(_), H::Array | H::Eq | H::Any)
| (
H::None,
H::Any
| H::Eq
| H::I31
| H::Struct
| H::Array
| H::ConcreteStruct(_)
| H::ConcreteArray(_)
)
)
}
}
impl RefType {
pub(crate) fn matches(&self, other: &RefType) -> bool {
(!self.nullable || other.nullable) && self.heap.matches(&other.heap)
}
}
impl ValType {
pub(crate) fn matches(&self, other: &ValType) -> bool {
match (self, other) {
(ValType::Ref(a), ValType::Ref(b)) => a.matches(b),
_ => self == other,
}
}
}
pub(crate) fn val_type_belongs_to_engine(ty: &ValType, engine: &Engine) -> bool {
let ValType::Ref(reference) = ty else {
return true;
};
match reference.heap_type() {
HeapType::ConcreteStruct(ty) => ty.engine().same(engine),
HeapType::ConcreteArray(ty) => ty.engine().same(engine),
HeapType::ConcreteFunc(ty) => ty.engine().same(engine),
_ => true,
}
}
pub struct FuncType {
engine: Engine,
id: CanonicalTypeId,
}
impl FuncType {
pub fn new(
engine: &Engine,
params: impl IntoIterator<Item = ValType>,
results: impl IntoIterator<Item = ValType>,
) -> FuncType {
let params: Vec<ValType> = params.into_iter().collect();
let results: Vec<ValType> = results.into_iter().collect();
assert!(
params
.iter()
.chain(&results)
.all(|ty| val_type_belongs_to_engine(ty, engine)),
"function type contains a concrete type from a different engine"
);
let id = engine.intern_func_type(¶ms, &results);
FuncType {
engine: engine.clone(),
id,
}
}
pub(crate) fn from_id(engine: &Engine, id: CanonicalTypeId) -> FuncType {
engine.incref_type(id);
FuncType {
engine: engine.clone(),
id,
}
}
pub(crate) fn canonical_id(&self) -> CanonicalTypeId {
self.id
}
pub(crate) fn engine(&self) -> &Engine {
&self.engine
}
pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> {
self.signature().0.into_iter()
}
pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> {
self.signature().1.into_iter()
}
fn signature(&self) -> (Vec<ValType>, Vec<ValType>) {
self.engine
.func_sig(self.id)
.expect("live FuncType registration must retain its signature")
}
}
impl Clone for FuncType {
fn clone(&self) -> Self {
self.engine.incref_type(self.id);
FuncType {
engine: self.engine.clone(),
id: self.id,
}
}
}
impl Drop for FuncType {
fn drop(&mut self) {
self.engine.decref_type(self.id);
}
}
impl PartialEq for FuncType {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for FuncType {}
impl core::hash::Hash for FuncType {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl core::fmt::Debug for FuncType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("FuncType")
.field("id", &self.id)
.finish_non_exhaustive()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct MemoryType {
minimum: u64,
maximum: Option<u64>,
memory64: bool,
}
impl MemoryType {
pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType {
MemoryType {
minimum: u64::from(minimum),
maximum: maximum.map(u64::from),
memory64: false,
}
}
pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType {
MemoryType {
minimum,
maximum,
memory64: true,
}
}
pub fn minimum(&self) -> u64 {
self.minimum
}
pub fn maximum(&self) -> Option<u64> {
self.maximum
}
pub fn is_64(&self) -> bool {
self.memory64
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct GlobalType {
content: ValType,
mutability: Mutability,
}
impl GlobalType {
pub fn new(content: ValType, mutability: Mutability) -> GlobalType {
GlobalType {
content,
mutability,
}
}
pub fn content(&self) -> &ValType {
&self.content
}
pub fn mutability(&self) -> Mutability {
self.mutability
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TableType {
element: RefType,
minimum: u64,
maximum: Option<u64>,
table64: bool,
}
impl TableType {
pub fn new(element: RefType, min: u32, max: Option<u32>) -> TableType {
TableType {
element,
minimum: u64::from(min),
maximum: max.map(u64::from),
table64: false,
}
}
pub fn new64(element: RefType, min: u64, max: Option<u64>) -> TableType {
TableType {
element,
minimum: min,
maximum: max,
table64: true,
}
}
pub fn element(&self) -> &RefType {
&self.element
}
pub fn minimum(&self) -> u64 {
self.minimum
}
pub fn maximum(&self) -> Option<u64> {
self.maximum
}
pub fn is_64(&self) -> bool {
self.table64
}
}
#[derive(Clone, Debug)]
pub enum ExternType {
Func(FuncType),
Memory(MemoryType),
Global(GlobalType),
Table(TableType),
Tag(TagType),
}
#[derive(Clone, Debug)]
pub struct ImportType<'module> {
module: &'module str,
name: &'module str,
ty: ExternType,
}
impl<'module> ImportType<'module> {
pub(crate) fn new(module: &'module str, name: &'module str, ty: ExternType) -> Self {
ImportType { module, name, ty }
}
pub fn module(&self) -> &'module str {
self.module
}
pub fn name(&self) -> &'module str {
self.name
}
pub fn ty(&self) -> ExternType {
self.ty.clone()
}
}
#[derive(Clone, Debug)]
pub struct ExportType<'module> {
name: &'module str,
ty: ExternType,
}
impl<'module> ExportType<'module> {
pub(crate) fn new(name: &'module str, ty: ExternType) -> Self {
ExportType { name, ty }
}
pub fn name(&self) -> &'module str {
self.name
}
pub fn ty(&self) -> ExternType {
self.ty.clone()
}
}