use crate::extern_::{val_matches, Tag};
use crate::store::{AsContext, AsContextMut, ExnEntity};
use crate::value::gc_ref::{ExnRef, Rooted};
use crate::value::{ExnType, HeapType, Val, ValType};
use crate::{Error, Result};
#[derive(Debug)]
pub struct ExnRefPre {
ty: ExnType,
}
impl ExnRefPre {
pub fn new(store: impl AsContextMut, ty: ExnType) -> Self {
let _ = store; ExnRefPre { ty }
}
}
impl ExnRef {
pub fn new(
mut store: impl AsContextMut,
allocator: &ExnRefPre,
tag: &Tag,
fields: &[Val],
) -> Result<Rooted<ExnRef>> {
let params: Vec<ValType> = allocator.ty.func().params().collect();
if fields.len() != params.len() {
return Err(Error::msg("wrong number of exception fields"));
}
for (v, ty) in fields.iter().zip(¶ms) {
if !val_matches(v, ty) {
return Err(Error::msg("exception field value has the wrong type"));
}
}
let mut ctx = store.as_context_mut();
let exn = ctx.store_mut().gc_alloc_exn(ExnEntity {
tag: *tag,
args: fields.to_vec(),
backtrace: None,
})?;
let inner = ctx.inner_mut();
inner.push_gc_root(exn.raw(), crate::canon::RefKind::Exn);
Ok(Rooted::from_raw_gen(
exn.raw(),
inner.exn_generation(exn.raw()).unwrap_or(0),
))
}
}
impl Rooted<ExnRef> {
pub fn field(&self, mut store: impl AsContextMut, index: usize) -> Result<Val> {
let ctx = store.as_context_mut();
ctx.inner()
.exn_checked(*self)?
.args
.get(index)
.copied()
.ok_or_else(|| Error::msg("exception field index out of bounds"))
}
pub fn tag(&self, mut store: impl AsContextMut) -> Result<Tag> {
Ok(store.as_context_mut().inner().exn_checked(*self)?.tag)
}
pub fn ty(&self, store: impl AsContext) -> Result<ExnType> {
let ctx = store.as_context();
let tag = ctx.inner().exn_checked(*self)?.tag;
ExnType::from_tag_type(&ctx.inner().tag(tag).ty)
}
pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> {
let _ = store.as_context();
Ok(HeapType::Exn.matches(ty))
}
}