template_quote/lib.rs
1#![doc(html_logo_url = "https://raw.githubusercontent.com/yasuo-ozu/template_quote/main/logo.png")]
2#![doc = include_str!("../README.md")]
3
4/// See module-level doc.
5pub use template_quote_impl::quote;
6/// [`quote_configured!`] is a configurable version of [`quote!`]. A leading
7/// `{ key: value, ... } =>` block overrides the paths and span the generated
8/// code refers to. Every key is optional; the accepted keys and their defaults
9/// are:
10///
11/// - `proc_macro2` — path to the `proc-macro2` crate (default `::proc_macro2`)
12/// - `quote` — path to this crate's re-exports (default `::template_quote`)
13/// - `core` — path to `core` (default `::core`)
14/// - `span` — an expression giving the span for emitted tokens (default
15/// `::proc_macro2::Span::call_site()`)
16///
17/// Any other key is a compile error.
18///
19/// ```ignore
20/// # use template_quote::quote_configured;
21/// quote_configured! {
22/// {
23/// proc_macro2: ::proc_macro2,
24/// quote: ::template_quote,
25/// core: ::core,
26/// span: ::proc_macro2::Span::call_site(),
27/// } =>
28/// // ... template body ...
29/// };
30/// ```
31pub use template_quote_impl::quote_configured;
32
33/// [`quote_spanned!`] emits tokens using the span given before `=>`.
34///
35/// ```ignore
36/// # use template_quote::quote_spanned;
37/// use proc_macro2::Span;
38/// let span = Span::call_site();
39/// let tokens = quote_spanned! { span => /* ... */ };
40/// ```
41pub use template_quote_impl::quote_spanned;
42
43pub use quote::ToTokens;
44
45/// Hidden runtime support referenced by the code generated by [`quote!`] and
46/// friends via `#path_quote::__private::…`. Not part of the public API.
47#[doc(hidden)]
48pub mod __private {
49 pub use crate::imp::ext;
50}
51
52mod imp {
53 /// Extension traits used by the generated repetition code to turn each
54 /// interpolated variable into an iterator.
55 ///
56 /// Modeled on `quote`'s autoref-specialization: each tier exposes the same
57 /// method `__template_quote_into_iter`, returning `(iterator, is_iterable)`
58 /// in one call. The generated code binds `let (mut it, m) = (var).…();` per
59 /// variable, zips the iterators, ORs the `m` flags and panics at runtime if
60 /// none are iterable.
61 ///
62 /// Splitting across three traits (instead of one trait with a blanket
63 /// `Borrow<[T]>` impl) is what removes the old coherence collision: a type
64 /// implementing both `Borrow<[T]>` and `ToTokens` used to match two impls
65 /// and fail with `E0283`. Here the "iterate by reference" tier is
66 /// implemented for concrete std types only, so by the orphan rule a foreign
67 /// type can never be both that tier and `ToTokens` — no ambiguity.
68 pub mod ext {
69 use quote::ToTokens;
70 use std::collections::btree_set::{self, BTreeSet};
71 use std::slice;
72
73 /// Tier 1 — real iterators, taken by value (wins method resolution with
74 /// no autoref). Reports `is_iterable = true`.
75 pub trait RepIteratorExt: Iterator + Sized {
76 fn __template_quote_into_iter(self) -> (Self, bool) {
77 (self, true)
78 }
79 }
80
81 impl<T: Iterator> RepIteratorExt for T {}
82
83 /// Tier 2 — plain [`ToTokens`] values, repeated unchanged each
84 /// iteration. `&self` receiver, so the value is never consumed.
85 /// Reports `is_iterable = false`.
86 pub trait RepToTokensExt {
87 fn __template_quote_into_iter(&self) -> (ToTokensRepeat<'_, Self>, bool) {
88 (ToTokensRepeat(self), false)
89 }
90 }
91
92 impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
93
94 /// Infinite iterator yielding the same `&T` every step.
95 pub struct ToTokensRepeat<'a, T: ?Sized>(&'a T);
96
97 impl<'a, T: ?Sized> Iterator for ToTokensRepeat<'a, T> {
98 type Item = &'a T;
99 fn next(&mut self) -> Option<Self::Item> {
100 Some(self.0)
101 }
102 }
103
104 /// Tier 3 — "iterate by reference" for concrete std container and
105 /// reference types only (never a blanket over a user trait, so it can
106 /// never coherence-collide with [`RepToTokensExt`]). `&self` receiver;
107 /// reports `is_iterable = true`.
108 pub trait RepAsIteratorExt<'q> {
109 type Iter: Iterator;
110 fn __template_quote_into_iter(&'q self) -> (Self::Iter, bool);
111 }
112
113 impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &T {
114 type Iter = T::Iter;
115 fn __template_quote_into_iter(&'q self) -> (Self::Iter, bool) {
116 <T as RepAsIteratorExt>::__template_quote_into_iter(*self)
117 }
118 }
119
120 impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &mut T {
121 type Iter = T::Iter;
122 fn __template_quote_into_iter(&'q self) -> (Self::Iter, bool) {
123 <T as RepAsIteratorExt>::__template_quote_into_iter(*self)
124 }
125 }
126
127 impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
128 type Iter = slice::Iter<'q, T>;
129 fn __template_quote_into_iter(&'q self) -> (Self::Iter, bool) {
130 (self.iter(), true)
131 }
132 }
133
134 impl<'q, T: 'q, const N: usize> RepAsIteratorExt<'q> for [T; N] {
135 type Iter = slice::Iter<'q, T>;
136 fn __template_quote_into_iter(&'q self) -> (Self::Iter, bool) {
137 (self.iter(), true)
138 }
139 }
140
141 impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
142 type Iter = slice::Iter<'q, T>;
143 fn __template_quote_into_iter(&'q self) -> (Self::Iter, bool) {
144 (self.iter(), true)
145 }
146 }
147
148 impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
149 type Iter = btree_set::Iter<'q, T>;
150 fn __template_quote_into_iter(&'q self) -> (Self::Iter, bool) {
151 (self.iter(), true)
152 }
153 }
154 }
155}