use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{spanned::Spanned, Attribute, ExprPath, GenericParam, Path, Token};
pub(crate) fn create_maybe_generics(generics: &syn::Generics) -> syn::Generics {
let mut outer_generics = generics.clone();
let params = &mut outer_generics.params;
if !params.empty_or_trailing() {
params.push_punct(<Token![,]>::default());
}
let param = syn::parse2(quote! { const EMPLACE: bool = false }).unwrap();
params.push(GenericParam::Const(param));
outer_generics
}
pub(crate) fn has_placing_attr(attrs: &[Attribute]) -> Result<bool, TokenStream> {
for attr in attrs.iter() {
if path_ident(attr.path()) != "placing" {
continue;
}
return match &attr.meta {
syn::Meta::Path(_) => Ok(true),
_ => Err(quote::quote_spanned! { attr.span() =>
compile_error!("[E0004, placing] invalid attr: the #[placing] attribute does not support any additional arguments"),
}.into()),
};
}
Ok(false)
}
pub(crate) fn path_ident(path: &Path) -> String {
path.to_token_stream().to_string()
}
pub(crate) fn expr_path_ident(path: &ExprPath) -> String {
path.to_token_stream().to_string()
}
pub(crate) fn strip_placing_attr(attrs: &mut Vec<Attribute>) {
attrs.retain(|attr| path_ident(attr.path()) != "placing")
}
pub(crate) fn set_path_generics(
path: &syn::TypePath,
base: &syn::Generics,
param: syn::GenericArgument,
) -> syn::TypePath {
let mut path = path.clone();
let segment = path.path.segments.last_mut().unwrap();
let ident = &segment.ident;
let params = base.params.iter().map(|param| -> syn::GenericArgument {
match param {
syn::GenericParam::Lifetime(lifetime_param) => {
let param = &lifetime_param.lifetime;
syn::parse2(quote! {#param}).unwrap()
}
syn::GenericParam::Type(type_param) => {
let param = &type_param.ident;
syn::parse2(quote! {#param}).unwrap()
}
syn::GenericParam::Const(const_param) => {
let param = &const_param.ident;
syn::parse2(quote! {#param}).unwrap()
}
}
});
*segment = syn::parse2(quote! { #ident <#(#params,)* #param> }).unwrap();
path
}
pub(crate) fn constructor_type(sig: &syn::Signature, ident: &syn::Ident) -> ConstructorKind {
match &sig.output {
syn::ReturnType::Type(_, ty) => match &**ty {
syn::Type::Path(path) => match path_ident(&path.path).as_str() {
"Box < Self >" => ConstructorKind::Pointer(PointerKind::Box),
"Self" => ConstructorKind::Inline,
s if s == ident.to_string() => ConstructorKind::Inline,
_ => ConstructorKind::Other,
},
_ => ConstructorKind::Other,
},
_ => ConstructorKind::Other,
}
}
pub(crate) enum ConstructorKind {
Inline,
Pointer(PointerKind),
Other,
}
pub(crate) enum PointerKind {
Box,
}