use proc_macro2::Span;
use syn::{braced, parse::Parse, punctuated::Punctuated, Ident, LitStr, Token};
use crate::vendor::wasmtime_component_macro::bindgen::Config as WitBindgenConfig;
use crate::wit::{WitFnList, WitNamespaceName, WitPackageName};
use crate::{ImplStructName, LatticeExposedInterface, WasmcloudContract};
pub(crate) struct ProviderBindgenConfig {
pub(crate) impl_struct: ImplStructName,
pub(crate) contract: WasmcloudContract,
pub(crate) wit_ns: Option<WitNamespaceName>,
pub(crate) wit_pkg: Option<WitPackageName>,
pub(crate) exposed_interface_allow_list: Vec<LatticeExposedInterface>,
pub(crate) exposed_interface_deny_list: Vec<LatticeExposedInterface>,
pub(crate) wit_bindgen_cfg: Option<WitBindgenConfig>,
pub(crate) replace_witified_maps: bool,
}
impl Parse for ProviderBindgenConfig {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let call_site = Span::call_site();
if !input.peek(syn::token::Brace) {
return Err(syn::Error::new::<String>(
call_site,
"bindgen configuration should start with a brace ('{')".into(),
));
}
let values;
braced!(values in input);
let entries =
Punctuated::<ProviderBindgenConfigOption, Token![,]>::parse_terminated(&values)?;
let mut contract: Option<WasmcloudContract> = None;
let mut impl_struct: Option<ImplStructName> = None;
let mut wit_ns: Option<WitNamespaceName> = None;
let mut wit_pkg: Option<WitPackageName> = None;
let mut wit_bindgen_cfg: Option<WitBindgenConfig> = None;
let mut exposed_interface_allow_list: Option<WitFnList> = None;
let mut exposed_interface_deny_list: Option<WitFnList> = None;
let mut replace_witified_maps: bool = false;
for entry in entries.into_pairs() {
match entry.into_value() {
ProviderBindgenConfigOption::Contract(c) => {
contract = Some(c.value());
}
ProviderBindgenConfigOption::WitNamespace(ns) => {
wit_ns = Some(ns.value());
}
ProviderBindgenConfigOption::WitPackage(pkg) => {
wit_pkg = Some(pkg.value());
}
ProviderBindgenConfigOption::ExposedFnAllowList(list) => {
exposed_interface_allow_list = Some(list)
}
ProviderBindgenConfigOption::ExposedFnDenyList(list) => {
exposed_interface_deny_list = Some(list)
}
ProviderBindgenConfigOption::ImplStruct(s) => impl_struct = Some(s.to_string()),
ProviderBindgenConfigOption::WitBindgenCfg(cfg) => {
wit_bindgen_cfg = Some(cfg);
}
ProviderBindgenConfigOption::ReplaceWitifiedMaps(opt) => {
replace_witified_maps = opt.value();
}
}
}
syn::Result::Ok(ProviderBindgenConfig {
impl_struct: impl_struct.ok_or_else(|| {
syn::Error::new(
call_site,
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"missing/invalid 'impl_struct' bindgen option",
),
)
})?,
contract: contract.ok_or_else(|| {
syn::Error::new(
call_site,
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"missing/invalid 'contract' bindgen option",
),
)
})?,
wit_ns,
wit_pkg,
exposed_interface_allow_list: exposed_interface_allow_list.unwrap_or_default().into(),
exposed_interface_deny_list: exposed_interface_deny_list.unwrap_or_default().into(),
wit_bindgen_cfg: Some(wit_bindgen_cfg.ok_or_else(|| {
syn::Error::new(
call_site,
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"missing/invalid 'wit_bindgen_cfg' arguments",
),
)
})?),
replace_witified_maps,
})
}
}
mod keywords {
syn::custom_keyword!(contract);
syn::custom_keyword!(wit_namespace);
syn::custom_keyword!(wit_package);
syn::custom_keyword!(impl_struct);
syn::custom_keyword!(wit_bindgen_cfg);
syn::custom_keyword!(exposed_interface_allow_list);
syn::custom_keyword!(exposed_interface_deny_list);
syn::custom_keyword!(replace_witified_maps);
}
#[allow(clippy::large_enum_variant)]
pub(crate) enum ProviderBindgenConfigOption {
Contract(LitStr),
ImplStruct(Ident),
WitNamespace(LitStr),
WitPackage(LitStr),
WitBindgenCfg(WitBindgenConfig),
ExposedFnAllowList(WitFnList),
ExposedFnDenyList(WitFnList),
ReplaceWitifiedMaps(syn::LitBool),
}
impl Parse for ProviderBindgenConfigOption {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let l = input.lookahead1();
if l.peek(keywords::contract) {
input.parse::<keywords::contract>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::Contract(input.parse()?))
} else if l.peek(keywords::impl_struct) {
input.parse::<keywords::impl_struct>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::ImplStruct(input.parse()?))
} else if l.peek(keywords::exposed_interface_allow_list) {
input.parse::<keywords::exposed_interface_allow_list>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::ExposedFnAllowList(
input.parse()?,
))
} else if l.peek(keywords::exposed_interface_deny_list) {
input.parse::<keywords::exposed_interface_deny_list>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::ExposedFnDenyList(
input.parse()?,
))
} else if l.peek(keywords::wit_bindgen_cfg) {
input.parse::<keywords::wit_bindgen_cfg>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::WitBindgenCfg(input.parse()?))
} else if l.peek(keywords::wit_namespace) {
input.parse::<keywords::wit_namespace>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::WitNamespace(input.parse()?))
} else if l.peek(keywords::wit_package) {
input.parse::<keywords::wit_package>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::WitPackage(input.parse()?))
} else if l.peek(keywords::replace_witified_maps) {
input.parse::<keywords::replace_witified_maps>()?;
input.parse::<Token![:]>()?;
Ok(ProviderBindgenConfigOption::ReplaceWitifiedMaps(
input.parse()?,
))
} else {
Err(syn::Error::new(
Span::call_site(),
"unrecognized keyword provided to wasmcloud_provider_wit_bindgen",
))
}
}
}