use std::ffi::CString;
use wasm3x_sys as ffi;
use crate::error::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ValType {
I32,
I64,
F32,
F64,
}
impl ValType {
pub(crate) fn from_ffi(raw: ffi::M3ValueType::Type) -> Option<Self> {
match raw {
ffi::M3ValueType::c_m3Type_i32 => Some(Self::I32),
ffi::M3ValueType::c_m3Type_i64 => Some(Self::I64),
ffi::M3ValueType::c_m3Type_f32 => Some(Self::F32),
ffi::M3ValueType::c_m3Type_f64 => Some(Self::F64),
_ => None,
}
}
pub(crate) fn to_ffi(self) -> ffi::M3ValueType::Type {
match self {
Self::I32 => ffi::M3ValueType::c_m3Type_i32,
Self::I64 => ffi::M3ValueType::c_m3Type_i64,
Self::F32 => ffi::M3ValueType::c_m3Type_f32,
Self::F64 => ffi::M3ValueType::c_m3Type_f64,
}
}
pub(crate) fn signature_char(self) -> u8 {
match self {
Self::I32 => b'i',
Self::I64 => b'I',
Self::F32 => b'f',
Self::F64 => b'F',
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Val {
I32(i32),
I64(i64),
F32(f32),
F64(f64),
}
impl Val {
pub fn ty(&self) -> ValType {
match self {
Self::I32(_) => ValType::I32,
Self::I64(_) => ValType::I64,
Self::F32(_) => ValType::F32,
Self::F64(_) => ValType::F64,
}
}
pub fn default_for_ty(ty: ValType) -> Self {
match ty {
ValType::I32 => Self::I32(0),
ValType::I64 => Self::I64(0),
ValType::F32 => Self::F32(0.0),
ValType::F64 => Self::F64(0.0),
}
}
pub fn i32(&self) -> Option<i32> {
match self {
Self::I32(v) => Some(*v),
_ => None,
}
}
pub fn i64(&self) -> Option<i64> {
match self {
Self::I64(v) => Some(*v),
_ => None,
}
}
pub fn f32(&self) -> Option<f32> {
match self {
Self::F32(v) => Some(*v),
_ => None,
}
}
pub fn f64(&self) -> Option<f64> {
match self {
Self::F64(v) => Some(*v),
_ => None,
}
}
pub(crate) fn to_slot(self) -> u64 {
match self {
Self::I32(v) => v as u32 as u64,
Self::I64(v) => v as u64,
Self::F32(v) => v.to_bits() as u64,
Self::F64(v) => v.to_bits(),
}
}
pub(crate) fn from_slot(ty: ValType, slot: u64) -> Self {
match ty {
ValType::I32 => Self::I32(slot as u32 as i32),
ValType::I64 => Self::I64(slot as i64),
ValType::F32 => Self::F32(f32::from_bits(slot as u32)),
ValType::F64 => Self::F64(f64::from_bits(slot)),
}
}
}
impl From<i32> for Val {
fn from(v: i32) -> Self {
Self::I32(v)
}
}
impl From<i64> for Val {
fn from(v: i64) -> Self {
Self::I64(v)
}
}
impl From<f32> for Val {
fn from(v: f32) -> Self {
Self::F32(v)
}
}
impl From<f64> for Val {
fn from(v: f64) -> Self {
Self::F64(v)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Mutability {
Mutable,
Const,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GlobalType {
content: ValType,
mutability: Mutability,
}
impl GlobalType {
pub fn new(content: ValType, mutability: Mutability) -> Self {
Self {
content,
mutability,
}
}
pub fn content(&self) -> ValType {
self.content
}
pub fn mutability(&self) -> Mutability {
self.mutability
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FuncType {
params: Box<[ValType]>,
results: Box<[ValType]>,
}
impl FuncType {
pub fn new<P, R>(params: P, results: R) -> Self
where
P: IntoIterator<Item = ValType>,
R: IntoIterator<Item = ValType>,
{
Self {
params: params.into_iter().collect(),
results: results.into_iter().collect(),
}
}
pub fn params(&self) -> &[ValType] {
&self.params
}
pub fn results(&self) -> &[ValType] {
&self.results
}
pub(crate) fn signature_cstring(&self) -> Result<CString> {
if self.results.len() > 1 {
return Err(Error::mismatch(
"wasm3 host functions cannot return more than one value",
));
}
let mut bytes = Vec::with_capacity(self.params.len() + 3);
bytes.push(self.results.first().map_or(b'v', |ty| ty.signature_char()));
bytes.push(b'(');
for param in self.params.iter() {
bytes.push(param.signature_char());
}
bytes.push(b')');
CString::new(bytes).map_err(|_| Error::mismatch("invalid function signature"))
}
}