use std::any::*;
use std::fmt::Display;
use std::hash::*;
use std::sync::atomic::*;
use std::sync::*;
use anyhow::*;
use fxhash::*;
use id_arena::*;
#[cfg(feature = "serde")]
use serde::*;
use crate::values::ComponentType;
use crate::TypeIdentifier;
use crate::{require_matches, UnaryComponentType};
use crate::{AsContextMut, ComponentInner, StoreContextMut};
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ValueType {
Bool,
S8,
U8,
S16,
U16,
S32,
U32,
S64,
U64,
F32,
F64,
Char,
String,
List(ListType),
Record(RecordType),
Tuple(TupleType),
Variant(VariantType),
Enum(EnumType),
Option(OptionType),
Result(ResultType),
Flags(FlagsType),
Own(ResourceType),
Borrow(ResourceType),
}
impl Display for ValueType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ValueType::Bool => write!(f, "bool"),
ValueType::S8 => write!(f, "s8"),
ValueType::U8 => write!(f, "u8"),
ValueType::S16 => write!(f, "s16"),
ValueType::U16 => write!(f, "u16"),
ValueType::S32 => write!(f, "s32"),
ValueType::U32 => write!(f, "u32"),
ValueType::S64 => write!(f, "s64"),
ValueType::U64 => write!(f, "u64"),
ValueType::F32 => write!(f, "f32"),
ValueType::F64 => write!(f, "f64"),
ValueType::Char => write!(f, "char"),
ValueType::String => write!(f, "string"),
ValueType::List(x) => write!(f, "list<{}>", x.element_ty()),
ValueType::Record(x) => {
write!(f, "record<")?;
let mut first = true;
for (name, ty) in x.fields() {
if !first {
write!(f, ", ")?;
}
write!(f, "{}: {}", name, ty)?;
first = false;
}
write!(f, ">")
}
ValueType::Tuple(x) => {
write!(f, "tuple<")?;
let mut first = true;
for ty in x.fields() {
if !first {
write!(f, ", ")?;
}
write!(f, "{}", ty)?;
first = false;
}
write!(f, ">")
}
ValueType::Variant(x) => {
write!(f, "variant<")?;
let mut first = true;
for case in x.cases() {
if !first {
write!(f, ", ")?;
}
write!(f, "{}", case.name())?;
if let Some(ty) = case.ty() {
write!(f, ": {}", ty)?;
}
first = false;
}
write!(f, ">")
}
ValueType::Enum(x) => {
write!(f, "enum<")?;
let mut first = true;
for case in x.cases() {
if !first {
write!(f, ", ")?;
}
write!(f, "{}", case)?;
first = false;
}
write!(f, ">")
}
ValueType::Option(x) => write!(f, "option<{}>", x.some_ty()),
ValueType::Result(x) => {
write!(f, "result<")?;
if let Some(ty) = x.ok_ty() {
write!(f, "{}", ty)?;
} else {
write!(f, "unit")?;
}
write!(f, ", ")?;
if let Some(ty) = x.err_ty() {
write!(f, "{}", ty)?;
} else {
write!(f, "unit")?;
}
write!(f, ">")
}
ValueType::Flags(x) => {
write!(f, "flags<")?;
let mut first = true;
for name in x.names() {
if !first {
write!(f, ", ")?;
}
write!(f, "{}", name)?;
first = false;
}
write!(f, ">")
}
ValueType::Own(x) => write!(
f,
"own<{}>",
x.name().map(ToString::to_string).unwrap_or("".to_string())
),
ValueType::Borrow(x) => write!(
f,
"borrow<{}>",
x.name().map(ToString::to_string).unwrap_or("".to_string())
),
}
}
}
impl ValueType {
pub(crate) fn from_component(
ty: &wit_parser::Type,
component: &ComponentInner,
resource_map: Option<&FxHashMap<ResourceType, ResourceType>>,
) -> Result<Self> {
Ok(match ty {
wit_parser::Type::Bool => Self::Bool,
wit_parser::Type::U8 => Self::U8,
wit_parser::Type::U16 => Self::U16,
wit_parser::Type::U32 => Self::U32,
wit_parser::Type::U64 => Self::U64,
wit_parser::Type::S8 => Self::S8,
wit_parser::Type::S16 => Self::S16,
wit_parser::Type::S32 => Self::S32,
wit_parser::Type::S64 => Self::S64,
wit_parser::Type::Float32 => Self::F32,
wit_parser::Type::Float64 => Self::F64,
wit_parser::Type::Char => Self::Char,
wit_parser::Type::String => Self::String,
wit_parser::Type::Id(x) => Self::from_component_typedef(*x, component, resource_map)?,
})
}
pub(crate) fn from_component_typedef(
def: Id<wit_parser::TypeDef>,
component: &ComponentInner,
resource_map: Option<&FxHashMap<ResourceType, ResourceType>>,
) -> Result<Self> {
let name = component.type_identifiers[def.index()].clone();
Ok(match &component.resolve.types[def].kind {
wit_parser::TypeDefKind::Record(x) => Self::Record(RecordType::from_component(
name,
x,
component,
resource_map,
)?),
wit_parser::TypeDefKind::Resource => bail!("Cannot instantiate resource as type."),
wit_parser::TypeDefKind::Handle(x) => match x {
wit_parser::Handle::Own(t) => Self::Own(ResourceType::from_resolve(
name,
*t,
component,
resource_map,
)?),
wit_parser::Handle::Borrow(t) => Self::Borrow(ResourceType::from_resolve(
name,
*t,
component,
resource_map,
)?),
},
wit_parser::TypeDefKind::Flags(x) => {
Self::Flags(FlagsType::from_component(name, x, component)?)
}
wit_parser::TypeDefKind::Tuple(x) => {
Self::Tuple(TupleType::from_component(name, x, component, resource_map)?)
}
wit_parser::TypeDefKind::Variant(x) => Self::Variant(VariantType::from_component(
name,
x,
component,
resource_map,
)?),
wit_parser::TypeDefKind::Enum(x) => {
Self::Enum(EnumType::from_component(name, x, component)?)
}
wit_parser::TypeDefKind::Option(x) => Self::Option(OptionType::new(
Self::from_component(x, component, resource_map)?,
)),
wit_parser::TypeDefKind::Result(x) => Self::Result(ResultType::new(
match &x.ok {
Some(t) => Some(Self::from_component(t, component, resource_map)?),
None => None,
},
match &x.err {
Some(t) => Some(Self::from_component(t, component, resource_map)?),
None => None,
},
)),
wit_parser::TypeDefKind::List(x) => Self::List(ListType::new(Self::from_component(
x,
component,
resource_map,
)?)),
wit_parser::TypeDefKind::Future(_) => bail!("Unimplemented."),
wit_parser::TypeDefKind::Stream(_) => bail!("Unimplemented."),
wit_parser::TypeDefKind::Type(x) => Self::from_component(x, component, resource_map)?,
wit_parser::TypeDefKind::Unknown => unreachable!(),
})
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ListType {
element: Arc<ValueType>,
}
impl ListType {
pub fn new(element_ty: ValueType) -> Self {
Self {
element: Arc::new(element_ty),
}
}
pub fn element_ty(&self) -> ValueType {
(*self.element).clone()
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RecordType {
pub(crate) fields: Arc<[(usize, Arc<str>, ValueType)]>,
name: Option<TypeIdentifier>,
}
impl RecordType {
pub fn new<S: Into<Arc<str>>>(
name: Option<TypeIdentifier>,
fields: impl IntoIterator<Item = (S, ValueType)>,
) -> Result<Self> {
let mut to_sort = fields
.into_iter()
.enumerate()
.map(|(i, (name, val))| (i, Into::<Arc<str>>::into(name), val))
.collect::<Arc<_>>();
Arc::get_mut(&mut to_sort)
.expect("Could not get exclusive reference.")
.sort_by(|a, b| a.1.cmp(&b.1));
for pair in to_sort.windows(2) {
ensure!(pair[0].1 != pair[1].1, "Duplicate field names");
}
Ok(Self {
fields: to_sort,
name,
})
}
pub fn field_ty(&self, name: impl AsRef<str>) -> Option<ValueType> {
self.fields
.iter()
.filter(|&(_, x, _val)| (&**x == name.as_ref()))
.map(|(_, _x, val)| val.clone())
.next()
}
pub fn name(&self) -> Option<&TypeIdentifier> {
self.name.as_ref()
}
pub fn fields(&self) -> impl ExactSizeIterator<Item = (&str, ValueType)> {
self.fields
.iter()
.map(|(_, name, val)| (&**name, val.clone()))
}
pub(crate) fn new_sorted(
name: Option<TypeIdentifier>,
fields: impl IntoIterator<Item = (Arc<str>, ValueType)>,
) -> Result<Self> {
let result = Self {
fields: fields
.into_iter()
.enumerate()
.map(|(i, (a, b))| (i, a, b))
.collect(),
name,
};
for pair in result.fields.windows(2) {
ensure!(pair[0].0 != pair[1].0, "Duplicate field names");
}
Ok(result)
}
fn from_component(
name: Option<TypeIdentifier>,
ty: &wit_parser::Record,
component: &ComponentInner,
resource_map: Option<&FxHashMap<ResourceType, ResourceType>>,
) -> Result<Self> {
let mut to_sort = ty
.fields
.iter()
.enumerate()
.map(|(i, x)| {
Ok((
i,
Into::<Arc<str>>::into(x.name.as_str()),
ValueType::from_component(&x.ty, component, resource_map)?,
))
})
.collect::<Result<Arc<_>>>()?;
Arc::get_mut(&mut to_sort)
.expect("Could not get exclusive reference.")
.sort_by(|a, b| a.1.cmp(&b.1));
for pair in to_sort.windows(2) {
ensure!(pair[0].0 != pair[1].0, "Duplicate field names");
}
Ok(Self {
fields: to_sort,
name,
})
}
}
impl PartialEq for RecordType {
fn eq(&self, other: &Self) -> bool {
self.fields == other.fields
}
}
impl Eq for RecordType {}
impl Hash for RecordType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.fields.hash(state);
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TupleType {
fields: Arc<[ValueType]>,
name: Option<TypeIdentifier>,
}
impl TupleType {
pub fn new(name: Option<TypeIdentifier>, fields: impl IntoIterator<Item = ValueType>) -> Self {
Self {
name,
fields: fields.into_iter().collect(),
}
}
pub fn fields(&self) -> &[ValueType] {
&self.fields
}
pub fn name(&self) -> Option<&TypeIdentifier> {
self.name.as_ref()
}
fn from_component(
name: Option<TypeIdentifier>,
ty: &wit_parser::Tuple,
component: &ComponentInner,
resource_map: Option<&FxHashMap<ResourceType, ResourceType>>,
) -> Result<Self> {
let fields = ty
.types
.iter()
.map(|x| ValueType::from_component(x, component, resource_map))
.collect::<Result<_>>()?;
Ok(Self { name, fields })
}
}
impl PartialEq for TupleType {
fn eq(&self, other: &Self) -> bool {
self.fields == other.fields
}
}
impl Eq for TupleType {}
impl Hash for TupleType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.fields.hash(state);
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct VariantCase {
name: Arc<str>,
ty: Option<ValueType>,
}
impl VariantCase {
pub fn new(name: impl Into<Arc<str>>, ty: Option<ValueType>) -> Self {
Self {
name: name.into(),
ty,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn ty(&self) -> Option<ValueType> {
self.ty.clone()
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct VariantType {
cases: Arc<[VariantCase]>,
name: Option<TypeIdentifier>,
}
impl VariantType {
pub fn new(
name: Option<TypeIdentifier>,
cases: impl IntoIterator<Item = VariantCase>,
) -> Result<Self> {
let cases: Arc<_> = cases.into_iter().collect();
for i in 0..cases.len() {
for j in 0..i {
ensure!(cases[i].name() != cases[j].name(), "Duplicate case names.");
}
}
Ok(Self { name, cases })
}
pub fn cases(&self) -> &[VariantCase] {
&self.cases
}
pub fn name(&self) -> Option<&TypeIdentifier> {
self.name.as_ref()
}
fn from_component(
name: Option<TypeIdentifier>,
ty: &wit_parser::Variant,
component: &ComponentInner,
resource_map: Option<&FxHashMap<ResourceType, ResourceType>>,
) -> Result<Self> {
let cases: Arc<_> = ty
.cases
.iter()
.map(|x| {
Ok(VariantCase {
name: x.name.as_str().into(),
ty: match &x.ty {
Some(t) => Some(ValueType::from_component(t, component, resource_map)?),
None => None,
},
})
})
.collect::<Result<_>>()?;
for i in 0..cases.len() {
for j in 0..i {
ensure!(cases[i].name() != cases[j].name(), "Duplicate case names.");
}
}
Ok(Self { name, cases })
}
}
impl PartialEq for VariantType {
fn eq(&self, other: &Self) -> bool {
self.cases == other.cases
}
}
impl Eq for VariantType {}
impl Hash for VariantType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.cases.hash(state);
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EnumType {
cases: Arc<[Arc<str>]>,
name: Option<TypeIdentifier>,
}
impl EnumType {
pub fn new<S: Into<Arc<str>>>(
name: Option<TypeIdentifier>,
cases: impl IntoIterator<Item = S>,
) -> Result<Self> {
let res = Self {
name,
cases: cases
.into_iter()
.map(|x| Into::<Arc<str>>::into(x))
.collect(),
};
for i in 0..res.cases.len() {
for j in 0..i {
ensure!(res.cases[i] != res.cases[j], "Duplicate case names.");
}
}
Ok(res)
}
pub fn name(&self) -> Option<&TypeIdentifier> {
self.name.as_ref()
}
pub fn cases(&self) -> impl ExactSizeIterator<Item = &str> {
self.cases.iter().map(|x| &**x)
}
fn from_component(
name: Option<TypeIdentifier>,
ty: &wit_parser::Enum,
_component: &ComponentInner,
) -> Result<Self> {
Self::new(name, ty.cases.iter().map(|x| x.name.as_str()))
}
}
impl PartialEq for EnumType {
fn eq(&self, other: &Self) -> bool {
self.cases == other.cases
}
}
impl Eq for EnumType {}
impl Hash for EnumType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.cases.hash(state)
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct OptionType {
ty: Arc<ValueType>,
}
impl OptionType {
pub fn new(ty: ValueType) -> Self {
Self { ty: Arc::new(ty) }
}
pub fn some_ty(&self) -> ValueType {
(*self.ty).clone()
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ResultType {
ok_err: Arc<(Option<ValueType>, Option<ValueType>)>,
}
impl ResultType {
pub fn new(ok: Option<ValueType>, err: Option<ValueType>) -> Self {
Self {
ok_err: Arc::new((ok, err)),
}
}
pub fn ok_ty(&self) -> Option<ValueType> {
self.ok_err.0.clone()
}
pub fn err_ty(&self) -> Option<ValueType> {
self.ok_err.1.clone()
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct FlagsType {
names: Arc<[Arc<str>]>,
pub(crate) indices: Arc<FxHashMap<Arc<str>, usize>>,
name: Option<TypeIdentifier>,
}
impl FlagsType {
pub fn new<S: Into<Arc<str>>>(
name: Option<TypeIdentifier>,
names: impl IntoIterator<Item = S>,
) -> Result<Self> {
let names: Arc<_> = names
.into_iter()
.map(|x| Into::<Arc<str>>::into(x))
.collect();
for i in 0..names.len() {
for j in 0..i {
ensure!(names[i] != names[j], "Duplicate case names.");
}
}
let indices = Arc::new(
names
.iter()
.enumerate()
.map(|(i, val)| (val.clone(), i))
.collect(),
);
Ok(Self {
name,
names,
indices,
})
}
pub fn name(&self) -> Option<&TypeIdentifier> {
self.name.as_ref()
}
pub fn names(&self) -> impl ExactSizeIterator<Item = &str> {
self.names.iter().map(|x| &**x)
}
fn from_component(
name: Option<TypeIdentifier>,
ty: &wit_parser::Flags,
_component: &ComponentInner,
) -> Result<Self> {
Self::new(name, ty.flags.iter().map(|x| x.name.as_ref()))
}
}
impl PartialEq for FlagsType {
fn eq(&self, other: &Self) -> bool {
self.names == other.names
}
}
impl Eq for FlagsType {}
impl Hash for FlagsType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.names.hash(state)
}
}
static RESOURCE_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
#[derive(Clone, Debug)]
pub struct ResourceType {
kind: ResourceKindValue,
name: Option<TypeIdentifier>,
}
impl ResourceType {
pub fn new<T: 'static + Send + Sync + Sized>(name: Option<TypeIdentifier>) -> Self {
Self {
name,
kind: ResourceKindValue::Host {
resource_id: RESOURCE_ID_COUNTER.fetch_add(1, Ordering::AcqRel),
type_id: TypeId::of::<T>(),
associated_store: None,
},
}
}
pub fn with_destructor<T: 'static + Send + Sync + Sized, C: AsContextMut>(
mut ctx: C,
name: Option<TypeIdentifier>,
destructor: impl 'static
+ Send
+ Sync
+ Fn(StoreContextMut<'_, C::UserState, C::Engine>, T) -> Result<()>,
) -> Result<Self> {
let store_id = ctx.as_context().inner.data().id;
let destructor = wasm_runtime_layer::Func::new(
ctx.as_context_mut().inner,
wasm_runtime_layer::FuncType::new([wasm_runtime_layer::ValueType::I32], [])
.with_name("destructor"),
move |mut ctx, val, _res| {
let resource = wasm_runtime_layer::AsContextMut::as_context_mut(&mut ctx)
.data_mut()
.host_resources
.remove(
require_matches!(val[0], wasm_runtime_layer::Value::I32(x), x) as usize,
);
destructor(
StoreContextMut { inner: ctx },
*resource
.downcast()
.expect("Resource was of incorrect type."),
)
},
);
Ok(Self {
name,
kind: ResourceKindValue::Host {
resource_id: RESOURCE_ID_COUNTER.fetch_add(1, Ordering::AcqRel),
type_id: TypeId::of::<T>(),
associated_store: Some((store_id, destructor)),
},
})
}
pub fn name(&self) -> Option<&TypeIdentifier> {
self.name.as_ref()
}
pub(crate) fn valid_for<T: 'static + Send + Sync>(&self, store_id: u64) -> bool {
if let ResourceKindValue::Host {
type_id,
associated_store,
..
} = &self.kind
{
*type_id == TypeId::of::<T>()
&& associated_store
.as_ref()
.map(|(id, _)| *id == store_id)
.unwrap_or(true)
} else {
false
}
}
pub(crate) fn is_owned_by_instance(&self, instance: u64) -> bool {
if let ResourceKindValue::Instantiated { instance: a, .. } = &self.kind {
instance == *a
} else {
false
}
}
pub(crate) fn from_resolve(
name: Option<TypeIdentifier>,
id: Id<wit_parser::TypeDef>,
component: &ComponentInner,
resource_map: Option<&FxHashMap<ResourceType, ResourceType>>,
) -> Result<Self> {
let resolve_type = &component.resolve.types[id];
if resolve_type.kind == wit_parser::TypeDefKind::Resource {
let ab = Self {
name,
kind: ResourceKindValue::Abstract {
id: id.index(),
component: component.id,
},
};
if let Some(map) = resource_map {
Ok(map[&ab].clone())
} else {
Ok(ab)
}
} else if let wit_parser::TypeDefKind::Type(wit_parser::Type::Id(x)) = resolve_type.kind {
Self::from_resolve(name, x, component, resource_map)
} else {
bail!("Unrecognized resource type.")
}
}
pub(crate) fn host_destructor(&self) -> Option<Option<wasm_runtime_layer::Func>> {
if let ResourceKindValue::Host {
associated_store, ..
} = &self.kind
{
Some(associated_store.as_ref().map(|(_, x)| x.clone()))
} else {
None
}
}
pub(crate) fn instantiate(&self, instance: u64) -> Result<Self> {
if let ResourceKindValue::Abstract { id, component: _ } = &self.kind {
Ok(Self {
name: self.name.clone(),
kind: ResourceKindValue::Instantiated { id: *id, instance },
})
} else {
bail!("Resource was not abstract.");
}
}
pub(crate) fn is_instantiated(&self) -> bool {
!matches!(&self.kind, ResourceKindValue::Abstract { .. })
}
}
impl Hash for ResourceType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.kind.hash(state);
}
}
impl PartialEq for ResourceType {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
}
}
impl Eq for ResourceType {}
#[cfg(feature = "serde")]
impl Serialize for ResourceType {
fn serialize<S: Serializer>(&self, _: S) -> Result<S::Ok, S::Error> {
use serde::ser::*;
std::result::Result::Err(S::Error::custom("Cannot serialize resources."))
}
}
#[cfg(feature = "serde")]
impl<'a> Deserialize<'a> for ResourceType {
fn deserialize<D: Deserializer<'a>>(_: D) -> Result<Self, D::Error> {
use serde::de::*;
std::result::Result::Err(D::Error::custom("Cannot deserialize resources."))
}
}
#[derive(Clone, Debug)]
enum ResourceKindValue {
Abstract {
id: usize,
component: u64,
},
Instantiated {
id: usize,
instance: u64,
},
Host {
resource_id: u64,
type_id: TypeId,
associated_store: Option<(u64, wasm_runtime_layer::Func)>,
},
}
impl PartialEq for ResourceKindValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(
ResourceKindValue::Abstract {
id: a,
component: b,
},
ResourceKindValue::Abstract {
id: x,
component: y,
},
) => a == x && b == y,
(
ResourceKindValue::Instantiated { id: a, instance: b },
ResourceKindValue::Instantiated { id: x, instance: y },
) => a == x && b == y,
(
ResourceKindValue::Host { resource_id: a, .. },
ResourceKindValue::Host { resource_id: x, .. },
) => a == x,
_ => false,
}
}
}
impl Eq for ResourceKindValue {}
impl Hash for ResourceKindValue {
fn hash<H: Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);
match self {
ResourceKindValue::Abstract { id, component } => {
id.hash(state);
component.hash(state);
}
ResourceKindValue::Instantiated { id, instance } => {
id.hash(state);
instance.hash(state);
}
ResourceKindValue::Host { resource_id, .. } => resource_id.hash(state),
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct FuncType {
len_params: usize,
params_results: Arc<[ValueType]>,
}
impl std::fmt::Debug for FuncType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("FuncType")
.field("params", &self.params())
.field("results", &self.results())
.finish()
}
}
impl Display for FuncType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let params = self.params();
let results = self.results();
let mut first = true;
write!(f, "func(")?;
for param in params {
if !first {
write!(f, ", ")?;
} else {
first = false;
}
write!(f, "{param}")?;
}
write!(f, ")")?;
let mut first = true;
for result in results {
if !first {
write!(f, ", ")?;
} else {
first = false;
write!(f, " -> ")?;
}
write!(f, "{result}")?;
}
std::fmt::Result::Ok(())
}
}
impl FuncType {
pub(crate) fn from_component(
func: &wit_parser::Function,
component: &ComponentInner,
resource_map: Option<&FxHashMap<ResourceType, ResourceType>>,
) -> Result<Self> {
let mut params_results = func
.params
.iter()
.map(|(_, ty)| ValueType::from_component(ty, component, resource_map))
.collect::<Result<Vec<_>>>()?;
let len_params = params_results.len();
for result in func
.results
.iter_types()
.map(|ty| ValueType::from_component(ty, component, resource_map))
{
params_results.push(result?);
}
Ok(Self {
params_results: params_results.into(),
len_params,
})
}
pub fn new<P, R>(params: P, results: R) -> Self
where
P: IntoIterator<Item = ValueType>,
R: IntoIterator<Item = ValueType>,
{
let mut params_results = params.into_iter().collect::<Vec<_>>();
let len_params = params_results.len();
params_results.extend(results);
Self {
params_results: params_results.into(),
len_params,
}
}
pub fn params(&self) -> &[ValueType] {
&self.params_results[..self.len_params]
}
pub fn results(&self) -> &[ValueType] {
&self.params_results[self.len_params..]
}
pub(crate) fn match_params(&self, params: &[crate::values::Value]) -> Result<()> {
if self.params().len() != params.len() {
bail!("Incorrect parameter length.");
}
if self
.params()
.iter()
.cloned()
.ne(params.iter().map(crate::values::Value::ty))
{
bail!("Incorrect parameter types.");
}
Ok(())
}
pub(crate) fn match_results(&self, results: &[crate::values::Value]) -> Result<()> {
if self.results().len() != results.len() {
bail!("Incorrect result length.");
}
if self
.results()
.iter()
.cloned()
.ne(results.iter().map(crate::values::Value::ty))
{
bail!("Incorrect result types.");
}
Ok(())
}
}
pub trait ComponentList: 'static + Sized {
const LEN: usize;
fn into_tys(types: &mut [ValueType]);
fn into_values(self, values: &mut [crate::values::Value]) -> Result<()>;
fn from_values(values: &[crate::values::Value]) -> Result<Self>;
}
impl ComponentList for () {
const LEN: usize = 0;
fn into_tys(_types: &mut [ValueType]) {}
fn from_values(_values: &[crate::values::Value]) -> Result<Self> {
Ok(())
}
fn into_values(self, _values: &mut [crate::values::Value]) -> Result<()> {
Ok(())
}
}
impl<T: UnaryComponentType> ComponentList for T {
const LEN: usize = 1;
fn into_tys(types: &mut [ValueType]) {
assert!(types.len() == 1);
types[0] = T::ty();
}
fn into_values(self, values: &mut [crate::values::Value]) -> Result<()> {
assert!(values.len() == 1);
values[0] = T::into_value(self)?;
Ok(())
}
fn from_values(values: &[crate::values::Value]) -> Result<Self> {
assert!(values.len() == 1);
T::from_value(&values[0])
}
}
#[allow(clippy::extra_unused_type_parameters)]
const fn one<T>() -> usize {
1
}
macro_rules! impl_component_list {
( $( ($name:ident, $extra:ident) )+ ) => {
impl<$($name: ComponentType),+> ComponentList for ($($name,)+)
{
const LEN: usize = { $(one::<$name>() + )+ 0 };
#[allow(warnings)]
fn into_tys(types: &mut [ValueType]) {
let mut counter = 0;
$(types[{ let res = counter; counter += 1; res }] = $name::ty();)+
}
#[allow(warnings)]
fn into_values(self, values: &mut [crate::values::Value]) -> Result<()> {
let ($($extra,)+) = self;
let mut counter = 0;
$(values[{ let res = counter; counter += 1; res }] = $extra.into_value()?;)+
Ok(())
}
#[allow(warnings)]
fn from_values(values: &[crate::values::Value]) -> Result<Self> {
let mut counter = 0;
Ok(($($name::from_value(&values[{ let res = counter; counter += 1; res }])?, )+))
}
}
};
}
impl_component_list!((A, a));
impl_component_list!((A, a)(B, b));
impl_component_list!((A, a)(B, b)(C, c));
impl_component_list!((A, a)(B, b)(C, c)(D, d));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e)(F, f));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e)(F, f)(G, g));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e)(F, f)(G, g)(H, h));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e)(F, f)(G, g)(H, h)(I, i));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e)(F, f)(G, g)(H, h)(I, i)(J, j));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e)(F, f)(G, g)(H, h)(I, i)(J, j)(K, k));
impl_component_list!((A, a)(B, b)(C, c)(D, d)(E, e)(F, f)(G, g)(H, h)(I, i)(J, j)(K, k)(L, l));