A simple macro to define a syn::Path at compile time
Find a file
Dominic f553fcb82f
All checks were successful
Rust / readme (push) Successful in 21s
Rust / rustfmt (push) Successful in 53s
Rust / Test (Rust Nightly) (push) Successful in 1m5s
Rust / Test (Rust Stable) (push) Successful in 1m2s
ci: enable email notifications
2025-11-29 15:21:45 +01:00
.forgejo/workflows ci: enable email notifications 2025-11-29 15:21:45 +01:00
src more examples 2025-09-09 12:49:36 +02:00
.gitignore initial commit 2022-04-10 00:11:52 +02:00
Cargo.toml Fix args in path! macro; Add examples to rustdoc/readme 2025-09-09 11:22:16 +02:00
LICENSE initial commit 2022-04-10 00:11:52 +02:00
README.md more examples 2025-09-09 12:49:36 +02:00
rustfmt.toml initial commit 2022-04-10 00:11:52 +02:00

syn-path License: 0BSD syn-path on crates.io syn-path on docs.rs Source Code Repository

This crate contains macros to construct syn-types that contain paths inside a procedural macro.

  • The path! macro constructs a syn::Path.

    Example:

    use syn_path::path;
    let path = path!(::std::option::Option<::std::string::String>);
    
  • The type_path! macro constructs a syn::TypePath.

    Example:

    use syn_path::type_path;
    let type_path = type_path!(<i64 as ::std::str::FromStr>::Err);
    
  • The ty! macro constructs a syn::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()
)