{"id":15067632,"url":"https://github.com/goncalerta/proc-quote","last_synced_at":"2025-04-10T14:35:46.148Z","repository":{"id":52406669,"uuid":"167612800","full_name":"Goncalerta/proc-quote","owner":"Goncalerta","description":"A procedural macro implementation of `quote!`.","archived":false,"fork":false,"pushed_at":"2023-03-20T10:59:02.000Z","size":80,"stargazers_count":22,"open_issues_count":7,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-03-23T11:22:41.010Z","etag":null,"topics":["proc-macro","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Goncalerta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-25T20:58:00.000Z","updated_at":"2024-06-21T14:24:04.011Z","dependencies_parsed_at":"2024-06-21T14:24:03.850Z","dependency_job_id":"607065c7-8432-4442-84a5-b5c1c898a8ed","html_url":"https://github.com/Goncalerta/proc-quote","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goncalerta%2Fproc-quote","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goncalerta%2Fproc-quote/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goncalerta%2Fproc-quote/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goncalerta%2Fproc-quote/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Goncalerta","download_url":"https://codeload.github.com/Goncalerta/proc-quote/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248233952,"owners_count":21069493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["proc-macro","rust"],"created_at":"2024-09-25T01:25:27.277Z","updated_at":"2025-04-10T14:35:46.130Z","avatar_url":"https://github.com/Goncalerta.png","language":"Rust","readme":"Rust Quasiquoter\n==================\n\n[![Build Status](https://travis-ci.org/Goncalerta/proc-quote.svg?branch=master)](https://travis-ci.org/Goncalerta/proc-quote)\n[![Latest Version](https://img.shields.io/crates/v/proc-quote.svg)](https://crates.io/crates/proc-quote)\n[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/proc-quote/0/proc_quote/macro.quote.html)\n\nThis crate implements the [`quote!`] macro as a procedural macro, instead of \n[the original `quote!` macro](https://github.com/dtolnay/quote), implemented \nwith `macro_rules!`. **Moreover, `proc-quote`\ntried to experiment with techniques to overcome longstanding limitations of the \noriginal `quote` crate. Those techniques have since [been incorporated](https://github.com/dtolnay/quote/releases/tag/1.0.0) \nin the original `quote` crate after a viable solution was found in `proc-quote`.**\n\nThe [`quote!`] macro turns Rust syntax tree data structures into tokens of \nsource code.\n\n[`quote!`]: https://docs.rs/proc-quote/0/proc_quote/macro.quote.html\n[`quote_spanned!`]: https://docs.rs/proc-quote/0/proc_quote/macro.quote_spanned.html\n\nProcedural macros in Rust receive a stream of tokens as input, execute arbitrary\nRust code to determine how to manipulate those tokens, and produce a stream of\ntokens to hand back to the compiler to compile into the caller's crate.\nQuasi-quoting is a solution to one piece of that -- producing tokens to return\nto the compiler.\n\nThe idea of quasi-quoting is that we write *code* that we treat as *data*.\nWithin the `quote!` macro, we can write what looks like code to our text editor\nor IDE. We get all the benefits of the editor's brace matching, syntax\nhighlighting, indentation, and maybe autocompletion. But rather than compiling\nthat as code into the current crate, we can treat it as data, pass it around,\nmutate it, and eventually hand it back to the compiler as tokens to compile into\nthe macro caller's crate.\n\nThis crate is motivated by the procedural macro use case, but it is a general-purpose \nRust quasi-quoting library and is not specific to procedural macros.\n\n## From `quote` to `proc-quote`\n\nThis crate serves the same purpose as [`quote`](https://crates.io/crates/quote)\nhowever it is implemented with procedural macros rather than `macro_rules!`. Switching \nfrom `quote` to the `proc_quote` crate **should not require any change in the code**.\n\nAfter changing your `Cargo.toml` dependency, change the following:\n```rust\nextern crate quote;\nuse quote::quote;\nuse quote::quote_spanned;\n```\nrespectively into:\n```rust\nextern crate proc_quote;\nuse proc_quote::quote;\nuse proc_quote::quote_spanned;\n```\n\nAnd that's it!\n\n[`Repeat`]: https://docs.rs/proc-quote/0/proc_quote/trait.Repeat.html\n[`Iterator\u003cT\u003e`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html\n[`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html\n[`ToTokens`]: https://docs.rs/proc-quote/0/proc_quote/trait.ToTokens.html\n[`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html\n\n\n## Syntax\n\nThe quote crate provides a `quote!` macro within which you can write Rust code\nthat gets packaged into a [`TokenStream`] and can be treated as data. You should\nthink of `TokenStream` as representing a fragment of Rust source code.\n\n[`TokenStream`]: https://docs.rs/proc-macro2/0/proc_macro2/struct.TokenStream.html\n\nWithin the `quote!` macro, interpolation is done with `#var`. Any type\nimplementing the [`quote::ToTokens`] trait can be interpolated. This includes\nmost Rust primitive types as well as most of the syntax tree types from [`syn`].\n\n[`quote::ToTokens`]: https://docs.rs/proc-quote/0/proc_quote/trait.ToTokens.html\n[`syn`]: https://github.com/dtolnay/syn\n\n```rust\nlet tokens = quote! {\n    struct SerializeWith #generics #where_clause {\n        value: \u0026'a #field_ty,\n        phantom: core::marker::PhantomData\u003c#item_ty\u003e,\n    }\n\n    impl #generics serde::Serialize for SerializeWith #generics #where_clause {\n        fn serialize\u003cS\u003e(\u0026self, serializer: S) -\u003e Result\u003cS::Ok, S::Error\u003e\n        where\n            S: serde::Serializer,\n        {\n            #path(self.value, serializer)\n        }\n    }\n\n    SerializeWith {\n        value: #value,\n        phantom: core::marker::PhantomData::\u003c#item_ty\u003e,\n    }\n};\n```\n\n## Repetition\n\nRepetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This\niterates through the elements of any variable interpolated within the repetition\nand inserts a copy of the repetition body for each one. \n\n- `#(#var)*` — no separators\n- `#(#var),*` — the character before the asterisk is used as a separator\n- `#( struct #var; )*` — the repetition can contain other things\n- `#( #k =\u003e println!(\"{}\", #v), )*` — even multiple interpolations\n- `#(let #var = self.#var;)*` - the same variable can be used more than once\n\nNote that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter\ndoes not produce a trailing comma. This matches the behavior of delimiters in\n`macro_rules!`.\n\nThe [`proc_quote::Repeat`](https://docs.rs/proc-quote/0/proc_quote/trait.Repeat.html) \ntrait defines which types are allowed to be interpolated inside a repition pattern.\n\nWhich types *do* `Repeat`:\n  - [`Iterator\u003cT\u003e`] consumes the iterator, iterating through every element.\n  - \u003ca href=\"https://doc.rust-lang.org/std/borrow/trait.Borrow.html\"\u003e`Borrow\u003c[T]\u003e`\u003c/a\u003e \n(includes [`Vec`], [`array`], and [`slice`]) iterates with the [`slice::iter`] method, \nthus not consuming the original data.\n  - [`ToTokens`], interpolates the variable in every iteration.\n\nWhich types *do NOT* `Repeat`:\n  - [`IntoIterator`], to avoid ambiguity (Ex. \"Which behavior would have been used for [`Vec`], \nwhich implements both [`IntoIterator`] and \u003ca href=\"https://doc.rust-lang.org/std/borrow/trait.Borrow.html\"\u003e\n`Borrow\u003c[T]\u003e`\u003c/a\u003e?\"; \"Which behavior would have been used for [`TokenStream`], which implements both \n[`IntoIterator`] and [`ToTokens`]?\"). To use the iterator, you may call [`IntoIterator::into_iter`] \nexplicitly.\n  - Ambiguous types that implement at least two of the `Repeat` traits. In the very unlikely case \nthis happens, disambiguate the type by wrapping it under some structure that only implements the \ntrait you desire to use.\n\n[`Iterator\u003cT\u003e`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html\n[`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html\n[`array`]: https://doc.rust-lang.org/std/primitive.array.html\n[`slice`]: https://doc.rust-lang.org/std/slice/index.html\n[`slice::iter`]: https://doc.rust-lang.org/std/primitive.slice.html#method.iter\n[`ToTokens`]: https://docs.rs/proc-quote/0/proc_quote/trait.ToTokens.html\n[`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html\n[`IntoIterator::into_iter`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html#tymethod.into_iter\n\n## Returning tokens to the compiler\n\nThe `quote!` macro evaluates to an expression of type `proc_macro2::TokenStream`. \nMeanwhile Rust procedural macros are expected to return the type `proc_macro::TokenStream`.\n\nThe difference between the two types is that `proc_macro` types are entirely\nspecific to procedural macros and cannot ever exist in code outside of a\nprocedural macro, while `proc_macro2` types may exist anywhere including tests\nand non-macro code like main.rs and build.rs. This is why even the procedural\nmacro ecosystem is largely built around `proc_macro2`, because that ensures the\nlibraries are unit testable and accessible in non-macro contexts.\n\nThere is a [`From`]-conversion in both directions so returning the output of\n`quote!` from a procedural macro usually looks like `tokens.into()` or\n`proc_macro::TokenStream::from(tokens)`.\n\n[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html\n\n## Examples\n\n### Combining quoted fragments\n\nUsually you don't end up constructing an entire final `TokenStream` in one\npiece. Different parts may come from different helper functions. The tokens\nproduced by `quote!` themselves implement `ToTokens` and so can be interpolated\ninto later `quote!` invocations to build up a final result.\n\n```rust\nlet type_definition = quote! {...};\nlet methods = quote! {...};\n\nlet tokens = quote! {\n    #type_definition\n    #methods\n};\n```\n\n### Constructing identifiers\n\nSuppose we have an identifier `ident` which came from somewhere in a macro\ninput and we need to modify it in some way for the macro output. Let's consider\nprepending the identifier with an underscore.\n\nSimply interpolating the identifier next to an underscore will not have the\nbehavior of concatenating them. The underscore and the identifier will continue\nto be two separate tokens as if you had written `_ x`.\n\n```rust\n// incorrect\nquote! {\n    let mut _#ident = 0;\n}\n```\n\nThe solution is to perform token-level manipulations using the APIs provided by\nSyn and proc-macro2.\n\n```rust\nlet concatenated = format!(\"_{}\", ident);\nlet varname = syn::Ident::new(\u0026concatenated, ident.span());\nquote! {\n    let mut #varname = 0;\n}\n```\n\n### Making method calls\n\nLet's say our macro requires some type specified in the macro input to have a\nconstructor called `new`. We have the type in a variable called `field_type` of\ntype `syn::Type` and want to invoke the constructor.\n\n```rust\n// incorrect\nquote! {\n    let value = #field_type::new();\n}\n```\n\nThis works only sometimes. If `field_type` is `String`, the expanded code\ncontains `String::new()` which is fine. But if `field_type` is something like\n`Vec\u003ci32\u003e` then the expanded code is `Vec\u003ci32\u003e::new()` which is invalid syntax.\nOrdinarily in handwritten Rust we would write `Vec::\u003ci32\u003e::new()` but for macros\noften the following is more convenient.\n\n```rust\nquote! {\n    let value = \u003c#field_type\u003e::new();\n}\n```\n\nThis expands to `\u003cVec\u003ci32\u003e\u003e::new()` which behaves correctly.\n\nA similar pattern is appropriate for trait methods.\n\n```rust\nquote! {\n    let value = \u003c#field_type as core::default::Default\u003e::default();\n}\n```\n\n## Hygiene\n\nAny interpolated tokens preserve the `Span` information provided by their\n`ToTokens` implementation. Tokens that originate within a `quote!` invocation\nare spanned with [`Span::call_site()`].\n\n[`Span::call_site()`]: https://docs.rs/proc-macro2/0/proc_macro2/struct.Span.html#method.call_site\n\nA different span can be provided explicitly through the [`quote_spanned!`]\nmacro.\n\n## License\n\nLicensed under either of\n\n * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this crate by you, as defined in the Apache-2.0 license, shall\nbe dual licensed as above, without any additional terms or conditions.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoncalerta%2Fproc-quote","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoncalerta%2Fproc-quote","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoncalerta%2Fproc-quote/lists"}