use crate::forbidden::is_forbidden_name;
use crate::service::model::{ReceiverKind, ServiceModel};
use quote::ToTokens;
use syn::{ImplItem, ItemImpl};
impl ServiceModel {
pub fn validate(&self, input: &ItemImpl) -> syn::Result<()> {
self.validate_async_constraints(input)?;
self.validate_forbidden_names()?;
Ok(())
}
fn validate_async_constraints(&self, input: &ItemImpl) -> syn::Result<()> {
if self.is_async {
for method in &self.methods {
if matches!(method.receiver_kind, ReceiverKind::Mutable) {
let error_span = if let Some(ImplItem::Fn(method_fn)) = input
.items
.iter()
.find(|item| if let ImplItem::Fn(f) = item { f.sig.ident == method.name } else { false })
{
if let Some(first_param) = method_fn.sig.inputs.first() {
first_param.to_token_stream()
} else {
method_fn.sig.ident.to_token_stream()
}
} else {
input.to_token_stream()
};
return Err(syn::Error::new_spanned(error_span, "Async services cannot have methods with &mut self. Use &self instead."));
}
}
}
Ok(())
}
fn validate_forbidden_names(&self) -> syn::Result<()> {
for constructor in &self.constructors {
if is_forbidden_name(constructor.name.to_string()) {
return Err(syn::Error::new_spanned(&constructor.name, format!("Using the name '{}' can cause conflicts in generated code.", constructor.name)));
}
for param in &constructor.inputs {
if is_forbidden_name(param.name.to_string()) {
return Err(syn::Error::new_spanned(¶m.name, format!("Using the name '{}' can cause conflicts in generated code.", param.name)));
}
}
}
for method in &self.methods {
if is_forbidden_name(method.name.to_string()) {
return Err(syn::Error::new_spanned(&method.name, format!("Using the name '{}' can cause conflicts in generated code.", method.name)));
}
for param in &method.inputs {
if is_forbidden_name(param.name.to_string()) {
return Err(syn::Error::new_spanned(¶m.name, format!("Using the name '{}' can cause conflicts in generated code.", param.name)));
}
}
}
Ok(())
}
}