use std::hash::{Hash, Hasher};
use syn::{
parse::{Parse, ParseStream},
Attribute, FnArg, ItemFn, Result, ReturnType, Token, TypePath,
};
pub struct PluginImplementation {
pub target_plugin: TypePath,
pub functions: Vec<MaybeUnsafeFn>,
}
impl Hash for PluginImplementation {
fn hash<H: Hasher>(&self, state: &mut H) {
let type_ident = self
.target_plugin
.path
.segments
.last()
.unwrap()
.ident
.clone();
type_ident.hash(state);
let mut functions = self.functions.clone();
functions.sort_by(|a, b| a.func.sig.ident.cmp(&b.func.sig.ident));
for maybe_unsafe_func in functions {
let function = maybe_unsafe_func.func;
"fn".hash(state);
function.sig.ident.hash(state);
for inp in function.sig.inputs {
if let FnArg::Typed(typed) = inp {
let ty = typed.ty;
"arg".hash(state);
crate::hash_type(state, *ty);
}
}
if let ReturnType::Type(_, ty) = function.sig.output {
"ret".hash(state);
crate::hash_type(state, *ty);
}
}
}
}
impl Parse for PluginImplementation {
fn parse(input: ParseStream) -> Result<Self> {
let target_plugin = input.parse()?;
let _: Token![,] = input.parse()?;
let mut functions = vec![];
while !input.is_empty() {
functions.push(input.parse()?);
}
Ok(Self {
target_plugin,
functions,
})
}
}
#[derive(Clone)]
pub struct MaybeUnsafeFn {
pub _attrs: Vec<Attribute>,
pub _unsafe: Option<Token![unsafe]>,
pub func: ItemFn,
}
impl Parse for MaybeUnsafeFn {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
_attrs: Attribute::parse_outer(input)?,
_unsafe: input.parse()?,
func: input.parse()?,
})
}
}