use super::*;
use crate::canon::{CompositeBody, IrField, IrStorage};
fn func(group: u32, supertype: Option<u32>) -> ModuleType {
ModuleType {
group,
finality: Finality::NonFinal,
supertype,
body: CompositeBody::Func {
params: Vec::new(),
results: Vec::new(),
},
}
}
#[test]
fn structurally_identical_groups_share_a_canonical_id() {
let mut reg = TypeRegistry::default();
let (ids1, g1) = reg.intern_module(&[func(0, None)]);
let (ids2, g2) = reg.intern_module(&[func(0, None)]);
assert_eq!(ids1[0], ids2[0]); assert_eq!(g1, g2); }
#[test]
fn declared_supertype_chain_is_a_subtype() {
let mut reg = TypeRegistry::default();
let field = IrField {
mutable: false,
storage: IrStorage::I8,
};
let module = [
ModuleType {
group: 0,
finality: Finality::NonFinal,
supertype: None,
body: CompositeBody::Struct(vec![field.clone()]),
},
ModuleType {
group: 1,
finality: Finality::Final,
supertype: Some(0),
body: CompositeBody::Struct(vec![field.clone(), field]),
},
];
let (ids, _) = reg.intern_module(&module);
assert!(reg.is_subtype(ids[1], ids[0]));
assert!(!reg.is_subtype(ids[0], ids[1]));
}
#[test]
fn refcount_reclaims_only_at_zero() {
let mut reg = TypeRegistry::default();
let (ids1, g1) = reg.intern_module(&[func(0, None)]);
let (_ids2, g2) = reg.intern_module(&[func(0, None)]); reg.release(&g1);
assert!(reg.kind(ids1[0]).is_some()); reg.release(&g2);
assert!(reg.kind(ids1[0]).is_none()); }
mod reclaim {
#![allow(clippy::unwrap_used)]
use crate::value::{
ArrayType, FieldType, Finality, Mutability, RecGroupBuilder, StorageType, StructRef,
StructRefPre, StructType, Val, ValType,
};
use crate::{Engine, Store};
fn i32_field(mutability: Mutability) -> FieldType {
FieldType::new(mutability, StorageType::ValType(ValType::I32))
}
#[test]
fn host_type_drop_reclaims() {
let engine = Engine::default();
let base = engine.live_group_count();
{
let _st = StructType::new(&engine, [i32_field(Mutability::Var)]).unwrap();
let _at = ArrayType::new(&engine, i32_field(Mutability::Var));
assert_eq!(engine.live_group_count(), base + 2);
}
assert_eq!(engine.live_group_count(), base); }
#[test]
fn clone_keeps_type_alive_until_last_drop() {
let engine = Engine::default();
let base = engine.live_group_count();
let st = StructType::new(&engine, [i32_field(Mutability::Var)]).unwrap();
let clone = st.clone();
drop(st);
assert_eq!(engine.live_group_count(), base + 1); drop(clone);
assert_eq!(engine.live_group_count(), base);
}
#[test]
fn build_and_drop_loop_returns_to_baseline() {
let engine = Engine::default();
let base = engine.live_group_count();
for _ in 0..100 {
let mut b = RecGroupBuilder::new(&engine);
let node = b.declare_struct();
b.define_struct(node)
.forward_ref_field(node) .mutability(Mutability::Var)
.finish()
.finish();
let _g = b.build().unwrap();
}
assert_eq!(engine.live_group_count(), base); }
#[test]
fn cross_group_supertype_pins_until_both_drop() {
let engine = Engine::default();
let base = engine.live_group_count();
let mut bb = RecGroupBuilder::new(&engine);
let base_id = bb.declare_struct();
bb.define_struct(base_id)
.finality(Finality::NonFinal)
.field(i32_field(Mutability::Const))
.finish();
let base_group = bb.build().unwrap();
let mut sb = RecGroupBuilder::new(&engine);
let sub_id = sb.declare_struct();
sb.define_struct(sub_id)
.supertype(base_group.get_struct(base_id).unwrap())
.field(i32_field(Mutability::Const))
.field(i32_field(Mutability::Const))
.finish();
let sub_group = sb.build().unwrap();
assert_eq!(engine.live_group_count(), base + 2);
drop(base_group); assert_eq!(engine.live_group_count(), base + 2);
drop(sub_group); assert_eq!(engine.live_group_count(), base);
}
#[test]
fn host_object_outlives_its_type_handle() {
let engine = Engine::default();
let base = engine.live_group_count();
let mut store = Store::new(&engine, ());
let st = StructType::new(&engine, [i32_field(Mutability::Var)]).unwrap();
let pre = StructRefPre::new(&mut store, st); let s = StructRef::new(&mut store, &pre, &[Val::I32(7)]).unwrap();
drop(pre); assert_eq!(engine.live_group_count(), base + 1);
assert_eq!(s.field(&mut store, 0).unwrap().unwrap_i32(), 7); drop(store); assert_eq!(engine.live_group_count(), base);
}
}