- Rust 100%
| .forgejo/workflows | ||
| src | ||
| .gitignore | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
| rustfmt.toml | ||
syn-path

This crate contains macros to construct syn-types that contain paths inside a
procedural macro.
-
The
path!macro constructs asyn::Path.Example:
use syn_path::path; let path = path!(::std::option::Option<::std::string::String>); -
The
type_path!macro constructs asyn::TypePath.Example:
use syn_path::type_path; let type_path = type_path!(<i64 as ::std::str::FromStr>::Err); -
The
ty!macro constructs asyn::Type.Example:
use syn_path::ty; let ty = ty!(<i64 as ::std::str::FromStr>::Err);
While we can just type whatever we need into quote! most of the time when writing
procedural macros, sometimes we need a certain syn type. The macros from this crate
help you out in these situations.
Example: Making a type optional
Some derive macros might need to transform a type to an optional type. For example,
this function takes a Field and returns its type or an option of its
type based on the nullable parameter:
use syn_path::type_path;
fn field_ty(field: &Field, nullable: bool) -> Type {
let mut ty = field.ty.clone();
if nullable {
let mut args = Punctuated::new();
args.push(GenericArgument::Type(ty));
let mut type_path = type_path!(::core::option::Option);
type_path.path.segments.last_mut().unwrap().arguments = PathArguments::AngleBracketed(
AngleBracketedGenericArguments {
colon2_token: None,
lt_token: Default::default(),
args,
gt_token: Default::default()
}
);
ty = Type::Path(type_path);
}
ty
}
let field = // x: String
let ty = field_ty(field, true);
assert_eq!(ty, syn::parse2(quote!(::core::option::Option<String>)).unwrap());
This example is adopted from the
openapi_type_derive
crate. The full example can be found
here.
Example: Adding a where clause
This example shows how to add T: Send clauses for each field of a struct. We cannot
just write where T: Send into quote! since there might or might
not be a where clause for the struct our derive macro received as an input.
use syn_path::path;
fn where_predicate_t_send(t: Type) -> WherePredicate {
WherePredicate::Type(PredicateType {
lifetimes: None,
bounded_ty: t,
colon_token: Default::default(),
bounds: [TypeParamBound::Trait(TraitBound {
paren_token: None,
modifier: TraitBoundModifier::None,
lifetimes: None,
path: path!(::std::marker::Send)
})].into_iter().collect()
})
}
let strukt =
struct Foo<T> where T: Hash + Eq { foo: HashSet<T> }
let ident = strukt.ident;
let (impl_generics, ty_generics, where_clause) = strukt.generics.split_for_impl();
let mut where_clause = where_clause.cloned().unwrap_or(WhereClause {
where_token: Default::default(),
predicates: Default::default()
});
for field in strukt.fields {
where_clause.predicates.push(where_predicate_t_send(field.ty));
}
assert_eq!(
quote!(impl #impl_generics MyTrait for #ident #ty_generics #where_clause {}).to_string(),
quote!(impl<T> MyTrait for Foo<T> where T: Hash + Eq, HashSet<T>: ::std::marker::Send {}).to_string()
)