use crate::rust::util::*;
use crate::rust::{Attribute, ItemFn, ItemImpl, ItemMod, ItemStruct};
#[derive(Clone, Debug)]
pub enum Item {
Fn(ItemFn),
Impl(ItemImpl),
Mod(ItemMod),
Struct(ItemStruct),
}
impl Parse for Item {
fn parse(input: ParseStream) -> Result<Self> {
Self::parse_remaining(input, false)
}
}
impl Item {
fn parse_remaining(input: ParseStream, filtered: bool) -> Result<Self> {
let mut attr = Attribute::default();
attr.parse_outer(input)?;
let vis = input.parse()?;
let fork = input.fork();
let const_ = fork.parse::<Option<Token![const]>>();
let async_ = fork.parse::<Option<Token![async]>>();
let extern_ = fork.parse::<Option<Token![extern]>>();
let abi = fork.parse::<Option<LitStr>>();
let unsafe_ = fork.parse::<Option<Token![unsafe]>>();
let fn_ = fork.parse::<Token![fn]>();
if const_.is_ok()
&& async_.is_ok()
&& extern_.is_ok()
&& abi.is_ok()
&& unsafe_.is_ok()
&& fn_.is_ok()
{
let async_ = async_.unwrap();
if let Some(async_) = async_ {
return Err(Error::new(async_.span, "unsupported async function"));
} else if extern_.unwrap().is_some() {
if let Some(abi) = abi.unwrap() {
let abi_str = abi.value();
if abi_str != "C" {
return Err(Error::new(
abi.span(),
"unsupported \"{abi_str}\" ABI type. replace with `extern \"C\"`, `extern`, or remove the `extern` keyword"
));
}
}
}
input.advance_to(&fork);
let const_ = const_.unwrap();
let unsafe_ = unsafe_.unwrap();
return Ok(Self::Fn(ItemFn::parse_remaining(
input, attr, vis, None, const_, unsafe_,
)?));
}
let fork = input.fork();
let unsafe_ = fork.parse::<Option<Token![unsafe]>>();
let impl_ = fork.parse::<Token![impl]>();
if unsafe_.is_ok() && impl_.is_ok() {
input.advance_to(&fork);
let unsafe_ = unsafe_.unwrap();
return Ok(Self::Impl(ItemImpl::parse_remaining(input, attr, unsafe_)?));
}
let fork = input.fork();
let struct_ = fork.parse::<Token![struct]>();
if struct_.is_ok() {
input.advance_to(&fork);
return Ok(Self::Struct(ItemStruct::parse_remaining(input, attr)?));
}
if cfg!(not(feature = "macro")) {
let fork = input.fork();
let unsafe_ = fork.parse::<Option<Token![unsafe]>>();
let mod_ = fork.parse::<Token![mod]>();
if unsafe_.is_ok() && mod_.is_ok() {
input.advance_to(&fork);
return Ok(Self::Mod(ItemMod::parse_remaining(input, attr, filtered)?));
}
}
Err(input.error("failed to parse item: expected `fn`, `impl`"))
}
pub fn parse_many(input: ParseStream, filtered: bool) -> Result<Vec<Self>> {
let mut items = Vec::new();
while !input.is_empty() {
let fork = input.fork();
if let Ok(item) = Item::parse_remaining(&fork, filtered) {
input.advance_to(&fork);
if filtered {
match &item {
Item::Fn(ItemFn { attr, .. })
| Item::Impl(ItemImpl { attr, .. })
| Item::Struct(ItemStruct { attr, .. }) => {
if attr.has_deno_bindgen() {
items.push(item)
}
},
Item::Mod(_) => items.push(item),
}
} else {
items.push(item);
}
} else {
input.call(syn::Item::parse)?;
}
}
Ok(items)
}
}
#[cfg(test)]
mod parse_tests {
use super::*;
#[test]
fn test_item_fn() {
dbg_quote!(Item, fn test_fn() {});
}
#[test]
fn test_item_fn_with_attrs_and_vis() {
dbg_quote!(
Item,
#[outer_attr]
pub fn test_fn() {
#![innter_attr]
}
);
}
#[test]
fn test_item_impl_() {
dbg_quote!(Item,
impl CustomType {
fn test_fn() {}
}
);
}
#[test]
fn test_item_impl_with_attrs_and_vis() {
dbg_quote!(
Item,
#[outer_attr]
pub impl CustomType {
#![innter_attr]
#[outer_attr]
pub fn test_fn() {
#![innter_attr]
}
}
);
}
#[test]
fn test_struct() {
dbg_quote!(Item, struct CustomType;);
}
#[test]
#[should_panic]
#[cfg(feature = "macro")]
fn test_unsupported() {
dbg_quote!(Item, const _: () = {};);
}
#[test]
fn test_full() {
dbg_quote!(
Item,
#[this_mod]
mod my_mod {
#[doc = "deno_bindgen"]
#[doc = "some_documentation"]
fn my_fn() {}
fn ignored_function() {}
#[doc = "deno_bindgen"]
struct CustomType {}
struct IgnoredStruct {}
#[doc = "deno_bindgen"]
impl CustomType {
fn some_fn() {}
}
}
);
}
}
impl Item {
pub fn transform(&mut self) {
match self {
Item::Fn(item_fn) => item_fn.transform(),
Item::Impl(item_impl) => item_impl.transform(),
_ => (), }
}
}
impl ToTokens for Item {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(match self {
Item::Fn(item_fn) => item_fn.to_token_stream(),
Item::Impl(item_impl) => item_impl.to_token_stream(),
Item::Struct(item_struct) => item_struct.to_token_stream(),
_ => TokenStream::new(), });
}
}
#[cfg(test)]
mod print_tests {}