pub mod collection;
pub mod error;
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use std::ops::Deref;
use syn::Token;
use syn::{
AngleBracketedGenericArguments, Expr, ExprClosure, Fields, GenericArgument, GenericParam,
Ident, Pat, PatType, Path, PathSegment, Type,
parse::{Parse, ParseStream},
spanned::Spanned,
};
pub const NJECT_MODULE_MACRO_PREFIX: &str = "__absolute_path_required_for_nject_module_";
pub const NJECT_MODULE_MACRO_LOCAL_PREFIX: &str = "__local_nject_module_";
pub struct DeriveInput(syn::DeriveInput);
impl Deref for DeriveInput {
type Target = syn::DeriveInput;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Parse for DeriveInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let input = input.parse()?;
Ok(Self(input))
}
}
impl ToTokens for DeriveInput {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.0.to_tokens(tokens)
}
}
impl DeriveInput {
pub fn fields(&self) -> &Fields {
match &self.data {
syn::Data::Struct(d) => &d.fields,
_ => panic!("Unsupported type. Macro should be used on a struct"),
}
}
pub fn field_types(&self) -> Vec<&Type> {
self.fields().iter().map(|f| &f.ty).collect::<Vec<_>>()
}
pub fn field_idents(&self) -> Vec<&Ident> {
self.fields()
.iter()
.filter_map(|f| f.ident.as_ref())
.collect::<Vec<_>>()
}
pub fn generic_params(&self) -> Vec<&GenericParam> {
self.generics.params.iter().collect::<Vec<_>>()
}
pub fn generic_keys(&self) -> Vec<TokenStream> {
self.generics
.params
.iter()
.map(|p| match p {
GenericParam::Type(t) => {
let identity = &t.ident;
quote! { #identity }
}
GenericParam::Const(c) => {
let identity = &c.ident;
quote! { #identity }
}
GenericParam::Lifetime(l) => quote! { #l },
})
.collect::<Vec<_>>()
}
pub fn lifetime_keys(&self) -> Vec<TokenStream> {
self.generics
.params
.iter()
.filter_map(|p| match p {
GenericParam::Lifetime(l) => Some(quote! { #l }),
_ => None,
})
.collect::<Vec<_>>()
}
}
pub struct FactoryExpr {
pub inputs: Vec<PatType>,
pub body: Box<Expr>,
}
impl Parse for FactoryExpr {
fn parse(input: ParseStream) -> syn::Result<Self> {
let expr: ExprClosure = input.parse()?;
let mut inputs = Vec::with_capacity(expr.inputs.len());
let span = expr.span();
for input in expr.inputs {
if let Pat::Type(pat_type) = input {
inputs.push(pat_type);
} else {
return Err(syn::Error::new(
span,
format!("Invalid input: {}", input.to_token_stream()),
));
}
}
Ok(FactoryExpr {
inputs,
body: expr.body,
})
}
}
pub enum FieldFactoryExpr {
None,
Type(Type),
TypeExpr(Type, Ident, Box<Expr>),
}
impl Parse for FieldFactoryExpr {
fn parse(input: ParseStream) -> syn::Result<Self> {
if input.is_empty() {
return Ok(Self::None);
}
let parsed_type = input.parse()?;
if !input.peek(Token![,]) {
return Ok(Self::Type(parsed_type));
}
input.parse::<Token![,]>()?;
let expr = input.parse::<ExprClosure>()?;
if expr.inputs.is_empty() {
return Err(syn::Error::new(expr.span(), "Missing factory input."));
}
if expr.inputs.len() > 1 {
return Err(syn::Error::new(expr.span(), "More than one input found"));
}
let input = &expr.inputs[0];
if let Pat::Ident(pat_ident) = input {
Ok(Self::TypeExpr(
parsed_type,
pat_ident.ident.to_owned(),
expr.body,
))
} else {
Err(syn::Error::new(input.span(), "Input must be an identity."))
}
}
}
pub fn substitute_in_path(path: &mut Path, from: &str, to: &str) {
for segment in path.segments.iter_mut() {
substitute_in_path_segment(segment, from, to)
}
}
pub fn substitute_in_type(ty: &mut Type, from: &str, to: &str) {
match ty {
Type::Path(p) => substitute_in_path(&mut p.path, from, to),
Type::Reference(r) => substitute_in_type(&mut r.elem, from, to),
Type::TraitObject(t) => {
for bound in &mut t.bounds {
if let syn::TypeParamBound::Trait(t) = bound {
substitute_in_path(&mut t.path, from, to)
}
}
}
_ => panic!(
"Unsupported type. Must be a Path, Reference or Trait: {}",
ty.to_token_stream()
),
};
}
fn substitute_in_path_segment(segment: &mut PathSegment, from: &str, to: &str) {
if segment.ident.to_string().eq(from) {
segment.ident = syn::Ident::new(to, segment.ident.span());
}
let arguments = &mut segment.arguments;
match arguments {
syn::PathArguments::None => (),
syn::PathArguments::AngleBracketed(b) => {
for arg in &mut b.args {
substitute_in_generic_argument(arg, from, to)
}
}
syn::PathArguments::Parenthesized(p) => {
for ty in &mut p.inputs {
substitute_in_type(ty, from, to)
}
}
};
}
fn substitute_in_angle_bracketed_generic_arguments(
args: &mut AngleBracketedGenericArguments,
from: &str,
to: &str,
) {
for arg in &mut args.args {
substitute_in_generic_argument(arg, from, to)
}
}
fn substitute_in_generic_argument(arg: &mut GenericArgument, from: &str, to: &str) {
match arg {
syn::GenericArgument::Type(ty) => substitute_in_type(ty, from, to),
syn::GenericArgument::Const(_) => (),
syn::GenericArgument::AssocType(a) => {
if let Some(args) = &mut a.generics {
substitute_in_angle_bracketed_generic_arguments(args, from, to)
}
substitute_in_type(&mut a.ty, from, to)
}
syn::GenericArgument::AssocConst(_) => (),
syn::GenericArgument::Constraint(c) => {
if let Some(args) = &mut c.generics {
substitute_in_angle_bracketed_generic_arguments(args, from, to)
}
for bound in &mut c.bounds {
match bound {
syn::TypeParamBound::Trait(t) => substitute_in_path(&mut t.path, from, to),
syn::TypeParamBound::Lifetime(_) => (),
syn::TypeParamBound::Verbatim(_) => (),
_ => (),
};
}
}
_ => (),
}
}