wasmgc 0.0.0

WasmGC types for Rust with a post-link toolchain
Documentation
//! Maps schema storage types and interns generated function signatures.
//!
//! Input type indices and GC schema indices are reserved before this interner
//! starts. Signatures are emitted in insertion order; hash-map iteration never
//! determines the output order.

use super::{Field, Input};
use crate::schema::FieldTag;
use std::collections::HashMap;
use wasm_encoder::{FuncType, HeapType, RefType, StorageType, ValType};

pub(super) fn schema_index(input: &Input, schema: u32) -> u32 {
    input.types + schema
}

pub(super) fn storage_type(input: &Input, field: &Field) -> StorageType {
    match field.tag {
        FieldTag::I8 => StorageType::I8,
        FieldTag::I16 => StorageType::I16,
        FieldTag::I32
        | FieldTag::I64
        | FieldTag::F32
        | FieldTag::F64
        | FieldTag::Bool
        | FieldTag::ExternRef
        | FieldTag::Ref
        | FieldTag::NullableRef
        | FieldTag::Array
        | FieldTag::NullableArray => StorageType::Val(value_type(input, field)),
    }
}

pub(super) fn value_type(input: &Input, field: &Field) -> ValType {
    match field.tag {
        FieldTag::I8 | FieldTag::I16 | FieldTag::I32 | FieldTag::Bool => ValType::I32,
        FieldTag::I64 => ValType::I64,
        FieldTag::F32 => ValType::F32,
        FieldTag::F64 => ValType::F64,
        FieldTag::ExternRef => ValType::EXTERNREF,
        FieldTag::Ref | FieldTag::NullableRef | FieldTag::Array | FieldTag::NullableArray => {
            ValType::Ref(RefType {
                nullable: matches!(field.tag, FieldTag::NullableRef | FieldTag::NullableArray),
                heap_type: HeapType::Concrete(schema_index(
                    input,
                    field.target.expect("reference field target"),
                )),
            })
        }
    }
}

pub(super) struct FunctionTypes {
    first: u32,
    signatures: Vec<FuncType>,
    indices: HashMap<FuncType, u32>,
}

impl FunctionTypes {
    pub fn new(first: u32) -> Self {
        Self {
            first,
            signatures: Vec::new(),
            indices: HashMap::new(),
        }
    }

    pub fn intern(
        &mut self,
        params: impl IntoIterator<Item = ValType>,
        results: impl IntoIterator<Item = ValType>,
    ) -> u32 {
        let signature = FuncType::new(params, results);
        if let Some(&index) = self.indices.get(&signature) {
            return index;
        }

        let index = self.first + self.signatures.len() as u32;
        self.indices.insert(signature.clone(), index);
        self.signatures.push(signature);
        index
    }

    pub fn finish(self) -> Vec<FuncType> {
        self.signatures
    }
}