use std::{
fmt::{Debug, Display, Formatter, Write},
hash::{Hash, Hasher},
sync::Arc,
};
use indexmap::IndexMap;
use crate::{
dag::DependentGraph,
encoder::WastEncoder,
helpers::{AliasOuter, ComponentDefine, EmitDefault, TypeDefinition, TypeReference},
wasi_types::{
array::NyarArray,
functions::{WasiFunctionBody, WasiNativeFunction},
resources::WasiResource,
variants::WasiVariantType,
},
DependenciesTrace, Identifier, WasiFunction, WasiModule, WasiRecordType, WasiTypeReference,
};
use std::{cmp::Ordering, ops::AddAssign};
use WasiType::{Float32, Float64, Integer16, Integer32, Integer64, Integer8};
pub mod array;
mod display;
pub mod enumerations;
pub mod functions;
pub mod records;
pub mod reference;
pub mod resources;
pub mod variants;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WasiType {
Boolean,
Integer8 {
signed: bool,
},
Integer16 {
signed: bool,
},
Integer32 {
signed: bool,
},
Integer64 {
signed: bool,
},
Float32,
Float64,
Option {
inner: Box<WasiType>,
},
Result {
success: Option<Box<WasiType>>,
failure: Option<Box<WasiType>>,
},
Resource(WasiResource),
Record(WasiRecordType),
Variant(WasiVariantType),
TypeHandler(WasiTypeReference),
Array(Box<NyarArray>),
Function(Box<WasiNativeFunction>),
External(Box<WasiFunction>),
}
impl WasiType {
pub fn wasm_module(&self) -> Option<&WasiModule> {
match self {
Self::Resource(v) => Some(&v.wasi_module),
Self::External(v) => match &v.body {
WasiFunctionBody::External { wasi_module, .. } => Some(wasi_module),
WasiFunctionBody::Normal { .. } => None,
},
_ => None,
}
}
pub fn language_id(&self) -> Option<&Identifier> {
match self {
Self::Variant(v) => Some(&v.symbol),
Self::Resource(v) => Some(&v.symbol),
Self::External(v) => Some(&v.symbol),
_ => None,
}
}
}
impl DependenciesTrace for WasiType {
#[track_caller]
fn define_language_types(&self, _: &mut DependentGraph) {
panic!("Invalid Call");
}
fn collect_wasi_types<'a, 'i>(&'a self, dict: &'i DependentGraph, collected: &mut Vec<&'i WasiType>)
where
'a: 'i,
{
match self {
WasiType::Option { inner } => inner.collect_wasi_types(dict, collected),
WasiType::Result { success, failure } => {
success.iter().for_each(|s| s.collect_wasi_types(dict, collected));
failure.iter().for_each(|f| f.collect_wasi_types(dict, collected));
}
WasiType::Resource(_) => collected.push(self),
WasiType::Variant(_) => collected.push(self),
WasiType::TypeHandler(v) => collected.push(dict.get(v)),
WasiType::External(_) => collected.push(self),
_ => {}
};
}
}
impl EmitDefault for WasiType {
fn emit_default<W: Write>(&self, w: &mut WastEncoder<W>) -> std::fmt::Result {
match self {
WasiType::Boolean => {
write!(w, "i32.const 0")
}
Integer8 { .. } => {
write!(w, "i32.const 0")
}
Integer16 { .. } => {
write!(w, "i32.const 0")
}
Integer32 { .. } => {
write!(w, "i32.const 0")
}
Integer64 { .. } => {
write!(w, "i64.const 0")
}
Float32 => {
write!(w, "f32.const 0")
}
Float64 => {
write!(w, "f64.const 0")
}
WasiType::Option { .. } => {
todo!()
}
WasiType::Result { .. } => {
todo!()
}
WasiType::Resource(_) => {
todo!()
}
WasiType::Record(_) => {
todo!()
}
WasiType::Variant(_) => {
todo!()
}
WasiType::TypeHandler { .. } => {
todo!()
}
WasiType::Array(_) => {
todo!()
}
WasiType::External(_) => {
todo!()
}
WasiType::Function(_) => {
todo!()
}
}
}
}
impl WasiType {
pub fn emit_convert<W: Write>(&self, target: &WasiType, w: &mut WastEncoder<W>) -> std::fmt::Result {
match (self, target) {
(Integer8 { .. } | Integer16 { .. } | Integer32 { .. }, Integer64 { .. }) => write!(w, "i32.wrap_i64")?,
(Float32, Integer8 { signed: true } | Integer16 { signed: true } | Integer32 { signed: true }) => {
write!(w, "i32.trunc_f32_s")?
}
(Float32, Integer8 { signed: false } | Integer16 { signed: false } | Integer32 { signed: false }) => {
write!(w, "i32.trunc_f32_u")?
}
(Float64, Integer8 { signed: true } | Integer16 { signed: true } | Integer32 { signed: true }) => {
write!(w, "i32.trunc_f64_s")?
}
(Float64, Integer8 { signed: false } | Integer16 { signed: false } | Integer32 { signed: false }) => {
write!(w, "i32.trunc_f64_u")?
}
(Integer8 { .. } | Integer16 { .. } | Integer32 { .. }, Integer64 { signed: true }) => {
write!(w, "i64.extend_i32_s")?
}
(Integer8 { .. } | Integer16 { .. } | Integer32 { .. }, Integer64 { signed: false }) => {
write!(w, "i64.extend_i32_u")?
}
(Float32, Integer64 { signed: true }) => write!(w, "i64.trunc_f32_s")?,
(Float32, Integer64 { signed: false }) => write!(w, "i64.trunc_f32_u")?,
(Float64, Integer64 { signed: true }) => write!(w, "i64.trunc_f64_s")?,
(Float64, Integer64 { signed: false }) => write!(w, "i64.trunc_f64_u")?,
(Integer8 { signed: true } | Integer16 { signed: true } | Integer32 { signed: true }, Float32) => {
write!(w, "f32.convert_i32_s")?
}
(Integer8 { signed: false } | Integer16 { signed: false } | Integer32 { signed: false }, Float32) => {
write!(w, "f32.convert_i32_u")?
}
(Integer64 { signed: true }, Float32) => write!(w, "f32.convert_i64_s")?,
(Integer64 { signed: false }, Float32) => write!(w, "f32.convert_i64_u")?,
(Float32, Float32) => write!(w, "f32.demote_f64")?,
(Integer8 { signed: true } | Integer16 { signed: true } | Integer32 { signed: true }, Float64) => {
write!(w, "f64.convert_i32_s")?
}
(Integer8 { signed: false } | Integer16 { signed: false } | Integer32 { signed: false }, Float64) => {
write!(w, "f64.convert_i32_u")?
}
(Integer64 { signed: true }, Float64) => write!(w, "f64.convert_i64_s")?,
(Integer64 { signed: false }, Float64) => write!(w, "f64.convert_i64_u")?,
(Float32, Float64) => write!(w, "f64.promote_f32")?,
_ => unimplemented!("convert {} to {}", self, target),
}
Ok(())
}
pub fn emit_transmute<W: Write>(&self, target: &WasiType, w: &mut WastEncoder<W>) -> std::fmt::Result {
match (self, target) {
(Float32, Integer32 { .. }) => write!(w, "i32.reinterpret_f32")?,
(Float64, Integer64 { .. }) => write!(w, "i64.reinterpret_f64")?,
(Integer32 { .. }, Float32) => write!(w, "f32.reinterpret_i32")?,
(Integer64 { .. }, Float64) => write!(w, "f64.reinterpret_i64")?,
_ => unimplemented!("transmute {} to {}", self, target),
}
Ok(())
}
}