Skip to main content

token_metadata/
lib.rs

1#![doc = include_str!("../README.md")]
2
3extern crate alloc;
4
5use ::alloc::vec::Vec;
6use ::core::{
7	fmt::Debug,
8	ops::{
9		Deref,
10		DerefMut,
11	},
12};
13use ::proc_macro2::{
14	Delimiter,
15	Group,
16	Ident,
17	Literal,
18	Punct,
19	Span,
20	TokenStream,
21	TokenTree,
22	extra::DelimSpan,
23};
24
25/// A version of [`Group`] with arbitrary attached metadata. The tokens within
26/// this [`GroupWithMetadata`] also have metadata.
27///
28/// The fields of this struct are public, unlike [`Group`]'s. There are no
29/// getter/setter methods: use the fields directly.
30///
31///  See [`proc_macro2`]'s documentation for more information on [`Group`].
32#[derive(Clone, Debug)]
33pub struct GroupWithMetadata<G, I = G, P = G, L = I> {
34	/// See [`Group::delimiter`].
35	pub delimiter: Delimiter,
36	/// A vector holding the tokens within this group, each with their own
37	/// metadata.
38	pub contents: TokenWithMetadataVec<G, I, P, L>,
39	/// See [`Group::span`].
40	/// This span covers the entire group, including the delimiters.
41	pub span: Span,
42	/// The associated metadata.
43	pub metadata: G,
44}
45
46impl<G, I, P, L> GroupWithMetadata<G, I, P, L> {
47	/// Strips the metadata from this [`GroupWithMetadata`], returning an
48	/// ordinary [`Group`].
49	///
50	/// The tokens within the group will also be stripped of their metadata.
51	#[must_use = "If you meant to drop this value, use `std::mem::drop` instead."]
52	pub fn strip_metadata(self) -> Group {
53		let mut group = Group::new(
54			self.delimiter,
55			token_with_metadata_iter_ext::iter_tokens_strip_metadata(self.contents).collect(),
56		);
57		group.set_span(self.span);
58		group
59	}
60
61	/// See [`Group::delimiter`].
62	#[inline(always)]
63	#[deprecated(note = "Use the `delimiter` field directly.")]
64	pub fn delimiter(&self) -> Delimiter {
65		self.delimiter
66	}
67
68	/// See [`Group::span`].
69	#[inline(always)]
70	#[must_use]
71	#[deprecated(note = "Use the `span` field directly.")]
72	pub fn span(&self) -> Span {
73		self.span
74	}
75
76	/// See [`Group::span_open`].
77	#[must_use]
78	pub fn span_open(&self) -> Span {
79		// Unfortunately, proc-macro2 does not expose span_open/spam_close methods.
80		// We need to create a dummy Group to access them.
81		let mut dummy = Group::new(self.delimiter, TokenStream::new());
82		dummy.set_span(self.span);
83		dummy.span_open()
84	}
85
86	/// See [`Group::span_close`].
87	#[must_use]
88	pub fn span_close(&self) -> Span {
89		let mut dummy = Group::new(self.delimiter, TokenStream::new());
90		dummy.set_span(self.span);
91		dummy.span_close()
92	}
93
94	/// See [`Group::delim_span`].
95	#[must_use]
96	pub fn delim_span(&self) -> DelimSpan {
97		let mut dummy = Group::new(self.delimiter, TokenStream::new());
98		dummy.set_span(self.span);
99		dummy.delim_span()
100	}
101
102	/// See [`Group::set_span`].
103	#[inline(always)]
104	#[deprecated(note = "Use the `span` field directly.")]
105	pub fn set_span(&mut self, span: Span) {
106		self.span = span;
107	}
108}
109
110impl<G, I, P, L> From<Group> for GroupWithMetadata<G, I, P, L>
111where
112	G: Default,
113	I: Default,
114	P: Default,
115	L: Default,
116{
117	fn from(value: Group) -> Self {
118		Self {
119			delimiter: value.delimiter(),
120			contents: token_with_metadata_iter_ext::iter_tokens_add_default_metadata(value.stream()).collect(),
121			span: value.span(),
122			metadata: G::default(),
123		}
124	}
125}
126
127impl<T> From<(Group, &T)> for GroupWithMetadata<T>
128where
129	T: Clone,
130{
131	fn from((value, metadata): (Group, &T)) -> Self {
132		Self {
133			delimiter: value.delimiter(),
134			contents: token_with_metadata_iter_ext::iter_tokens_add_metadata(value.stream(), metadata).collect(),
135			span: value.span(),
136			metadata: metadata.clone(),
137		}
138	}
139}
140
141impl<G, I, P, L> From<(Group, &G, &I, &P, &L)> for GroupWithMetadata<G, I, P, L>
142where
143	G: Clone,
144	I: Clone,
145	P: Clone,
146	L: Clone,
147{
148	fn from((value, g, i, p, l): (Group, &G, &I, &P, &L)) -> Self {
149		Self {
150			delimiter: value.delimiter(),
151			contents: token_with_metadata_iter_ext::iter_tokens_add_specific_metadata(value.stream(), g, i, p, l).collect(),
152			span: value.span(),
153			metadata: g.clone(),
154		}
155	}
156}
157
158/// A simple struct holding a token and its associated metadata.
159///
160/// Though [`TokenWithMetadata::token`] is generic, it should be a token from
161/// [`proc_macro2`] other than [`Group`] ([`Ident`], [`Punct`], or [`Literal`]).
162///
163/// To get the token without metadata, simply read the
164/// [`TokenWithMetadata::token`] field.
165#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
166pub struct TokenWithMetadata<T, U> {
167	/// The token.
168	pub token: T,
169	/// The associated metadata.
170	pub metadata: U,
171}
172
173/// Allow accessing the token's methods directly.
174impl<T, U> Deref for TokenWithMetadata<T, U> {
175	type Target = T;
176
177	#[inline(always)]
178	fn deref(&self) -> &Self::Target {
179		&self.token
180	}
181}
182
183/// Allow accessing the token's methods directly.
184impl<T, U> DerefMut for TokenWithMetadata<T, U> {
185	#[inline(always)]
186	fn deref_mut(&mut self) -> &mut Self::Target {
187		&mut self.token
188	}
189}
190
191impl<T, U: Default> From<T> for TokenWithMetadata<T, U> {
192	#[inline(always)]
193	fn from(token: T) -> Self {
194		Self { token, metadata: U::default() }
195	}
196}
197
198impl<T, U> From<(T, U)> for TokenWithMetadata<T, U> {
199	#[inline(always)]
200	fn from((token, metadata): (T, U)) -> Self {
201		Self { token, metadata }
202	}
203}
204
205/// A version of [`TokenTree`] with arbitrary attached metadata.
206///
207/// Each variant holds metadata of a different type. The types are:
208/// - `G`: For [`GroupWithMetadata`]s (in [`proc_macro2`], [`Group`]s).
209/// - `I`: For [`Ident`] tokens (defaults to the same type as `G`).
210/// - `P`: For [`Punct`] tokens (defaults to the same type as `G`).
211/// - `L`: For [`Literal`] tokens (defaults to the same type as `I`).
212///
213/// See [`proc_macro2`]'s documentation for more information.
214#[derive(Clone, Debug)]
215pub enum TokenTreeWithMetadata<G, I = G, P = G, L = I> {
216	/// A [`GroupWithMetadata`] token with its corresponding metadata.
217	/// The tokens within the group, correspondingly, also have metadata, with
218	/// the same types.
219	Group(GroupWithMetadata<G, I, P, L>),
220	/// An [`Ident`] token with its corresponding metadata.
221	Ident(TokenWithMetadata<Ident, I>),
222	/// A [`Punct`] token with its corresponding metadata.
223	Punct(TokenWithMetadata<Punct, P>),
224	/// A [`Literal`] token with its corresponding metadata.
225	Literal(TokenWithMetadata<Literal, L>),
226}
227
228impl<G, I, P, L> TokenTreeWithMetadata<G, I, P, L> {
229	/// Strips the metadata from this [`TokenTreeWithMetadata`], returning an
230	/// ordinary [`TokenTree`]. Child [`GroupWithMetadata`]s will also be
231	/// stripped of their metadata.
232	#[inline]
233	#[must_use = "If you meant to drop this value, use `std::mem::drop` instead."]
234	pub fn strip_metadata(self) -> TokenTree {
235		match self {
236			| TokenTreeWithMetadata::Group(group) => TokenTree::Group(group.strip_metadata()),
237			| TokenTreeWithMetadata::Ident(twm) => TokenTree::Ident(twm.token),
238			| TokenTreeWithMetadata::Punct(twm) => TokenTree::Punct(twm.token),
239			| TokenTreeWithMetadata::Literal(twm) => TokenTree::Literal(twm.token),
240		}
241	}
242
243	/// Gets the span of this token.
244	///
245	/// See [`TokenTree::span`].
246	#[inline]
247	#[must_use]
248	pub fn span(&self) -> Span {
249		match self {
250			| TokenTreeWithMetadata::Group(group) => group.span,
251			| TokenTreeWithMetadata::Ident(twm) => twm.token.span(),
252			| TokenTreeWithMetadata::Punct(twm) => twm.token.span(),
253			| TokenTreeWithMetadata::Literal(twm) => twm.token.span(),
254		}
255	}
256
257	/// Sets the span of this token.
258	///
259	/// See [`TokenTree::set_span`].
260	#[inline]
261	pub fn set_span(&mut self, span: Span) {
262		match self {
263			| TokenTreeWithMetadata::Group(group) => group.span = span,
264			| TokenTreeWithMetadata::Ident(twm) => twm.token.set_span(span),
265			| TokenTreeWithMetadata::Punct(twm) => twm.token.set_span(span),
266			| TokenTreeWithMetadata::Literal(twm) => twm.token.set_span(span),
267		}
268	}
269}
270
271impl<T> TokenTreeWithMetadata<T> {
272	/// Consumes self and returns the metadata associated with this token.
273	/// Only available when all metadata types are the same.
274	#[inline]
275	#[must_use = "If you meant to drop this value, use `std::mem::drop` instead."]
276	pub fn get_metadata(self) -> T {
277		match self {
278			| Self::Group(group) => group.metadata,
279			| Self::Ident(twm) => twm.metadata,
280			| Self::Punct(twm) => twm.metadata,
281			| Self::Literal(twm) => twm.metadata,
282		}
283	}
284
285	/// Returns a reference to the metadata associated with this token.
286	/// Only available when all metadata types are the same.
287	#[inline]
288	#[must_use]
289	pub fn get_metadata_ref(&self) -> &T {
290		match self {
291			| Self::Group(group) => &group.metadata,
292			| Self::Ident(twm) => &twm.metadata,
293			| Self::Punct(twm) => &twm.metadata,
294			| Self::Literal(twm) => &twm.metadata,
295		}
296	}
297
298	/// Returns a mutable reference to the metadata associated with this token.
299	/// Only available when all metadata types are the same.
300	#[inline]
301	#[must_use]
302	pub fn get_metadata_mut(&mut self) -> &mut T {
303		match self {
304			| Self::Group(group) => &mut group.metadata,
305			| Self::Ident(twm) => &mut twm.metadata,
306			| Self::Punct(twm) => &mut twm.metadata,
307			| Self::Literal(twm) => &mut twm.metadata,
308		}
309	}
310
311	/// Sets the metadata associated with this token.
312	/// Only available when all metadata types are the same.
313	#[inline]
314	pub fn set_metadata(&mut self, metadata: T) {
315		match self {
316			| Self::Group(group) => group.metadata = metadata,
317			| Self::Ident(twm) => twm.metadata = metadata,
318			| Self::Punct(twm) => twm.metadata = metadata,
319			| Self::Literal(twm) => twm.metadata = metadata,
320		}
321	}
322}
323
324impl<G, I, P, L> From<TokenTree> for TokenTreeWithMetadata<G, I, P, L>
325where
326	G: Default,
327	I: Default,
328	P: Default,
329	L: Default,
330{
331	#[inline]
332	fn from(tree: TokenTree) -> Self {
333		match tree {
334			| TokenTree::Group(group) => Self::Group(group.into()),
335			| TokenTree::Ident(ident) => Self::Ident(ident.into()),
336			| TokenTree::Punct(punct) => Self::Punct(punct.into()),
337			| TokenTree::Literal(literal) => Self::Literal(literal.into()),
338		}
339	}
340}
341
342impl<T> From<(TokenTree, &T)> for TokenTreeWithMetadata<T>
343where
344	T: Clone,
345{
346	#[inline]
347	fn from((tree, metadata): (TokenTree, &T)) -> Self {
348		match tree {
349			| TokenTree::Group(group) => Self::Group((group, metadata).into()),
350			| TokenTree::Ident(ident) => Self::Ident((ident, metadata.clone()).into()),
351			| TokenTree::Punct(punct) => Self::Punct((punct, metadata.clone()).into()),
352			| TokenTree::Literal(literal) => Self::Literal((literal, metadata.clone()).into()),
353		}
354	}
355}
356
357impl<G, I, P, L> From<(TokenTree, &G, &I, &P, &L)> for TokenTreeWithMetadata<G, I, P, L>
358where
359	G: Clone,
360	I: Clone,
361	P: Clone,
362	L: Clone,
363{
364	#[inline]
365	fn from((tree, g, i, p, l): (TokenTree, &G, &I, &P, &L)) -> Self {
366		match tree {
367			| TokenTree::Group(group) => Self::Group((group, g, i, p, l).into()),
368			| TokenTree::Ident(ident) => Self::Ident((ident, i.clone()).into()),
369			| TokenTree::Punct(punct) => Self::Punct((punct, p.clone()).into()),
370			| TokenTree::Literal(literal) => Self::Literal((literal, l.clone()).into()),
371		}
372	}
373}
374
375impl<G, I, P, L> From<Group> for TokenTreeWithMetadata<G, I, P, L>
376where
377	G: Default,
378	I: Default,
379	P: Default,
380	L: Default,
381{
382	#[inline(always)]
383	fn from(group: Group) -> Self {
384		Self::Group(group.into())
385	}
386}
387
388impl<T> From<(Group, &T)> for TokenTreeWithMetadata<T>
389where
390	T: Clone,
391{
392	#[inline(always)]
393	fn from(group_and_val: (Group, &T)) -> Self {
394		Self::Group(group_and_val.into())
395	}
396}
397
398impl<G, I, P, L> From<(Group, &G, &I, &P, &L)> for TokenTreeWithMetadata<G, I, P, L>
399where
400	G: Clone,
401	I: Clone,
402	P: Clone,
403	L: Clone,
404{
405	#[inline(always)]
406	fn from(group_and_vals: (Group, &G, &I, &P, &L)) -> Self {
407		Self::Group(group_and_vals.into())
408	}
409}
410
411impl<G, I, P, L> From<Ident> for TokenTreeWithMetadata<G, I, P, L>
412where
413	I: Default,
414{
415	#[inline(always)]
416	fn from(ident: Ident) -> Self {
417		Self::Ident(ident.into())
418	}
419}
420
421impl<G, I, P, L> From<(Ident, I)> for TokenTreeWithMetadata<G, I, P, L> {
422	#[inline(always)]
423	fn from((ident, metadata): (Ident, I)) -> Self {
424		Self::Ident((ident, metadata).into())
425	}
426}
427
428impl<G, I, P, L> From<Punct> for TokenTreeWithMetadata<G, I, P, L>
429where
430	P: Default,
431{
432	#[inline(always)]
433	fn from(punct: Punct) -> Self {
434		Self::Punct(punct.into())
435	}
436}
437
438impl<G, I, P, L> From<(Punct, P)> for TokenTreeWithMetadata<G, I, P, L> {
439	#[inline(always)]
440	fn from((punct, metadata): (Punct, P)) -> Self {
441		Self::Punct((punct, metadata).into())
442	}
443}
444
445impl<G, I, P, L> From<Literal> for TokenTreeWithMetadata<G, I, P, L>
446where
447	L: Default,
448{
449	#[inline(always)]
450	fn from(literal: Literal) -> Self {
451		Self::Literal(literal.into())
452	}
453}
454
455impl<G, I, P, L> From<(Literal, L)> for TokenTreeWithMetadata<G, I, P, L> {
456	#[inline(always)]
457	fn from((literal, metadata): (Literal, L)) -> Self {
458		Self::Literal((literal, metadata).into())
459	}
460}
461
462/// A type alias for a [`Vec`] of [`TokenTreeWithMetadata`]s.
463///
464/// Since [`TokenTreeWithMetadata`]s are not obtained from a [`TokenStream`]
465/// directly, and are built manually or derived from obtained [`TokenTree`]s, it
466/// doesn't make much sense to use a restrictive "token with metadata
467/// stream" type. Instead, use vectors of tokens with metadata.
468pub type TokenWithMetadataVec<G, I = G, P = G, L = I> = Vec<TokenTreeWithMetadata<G, I, P, L>>;
469
470/// Extension module for [`TokenWithMetadataVec`], or more generally, for
471/// iterators of [`TokenTreeWithMetadata`]s.
472pub mod token_with_metadata_iter_ext {
473	use super::*;
474
475	/// Strips the metadata from an iterator of [`TokenTreeWithMetadata`]s,
476	/// returning an iterator of ordinary [`TokenTree`]s.
477	pub fn iter_tokens_strip_metadata<G, I, P, L>(iter: impl IntoIterator<Item = TokenTreeWithMetadata<G, I, P, L>>) -> impl Iterator<Item = TokenTree> {
478		iter.into_iter().map(|ttwm| ttwm.strip_metadata())
479	}
480
481	/// Converts an iterator of ordinary [`TokenTree`]s into an iterator of
482	/// [`TokenTreeWithMetadata`]s with default-initialized metadata.
483	pub fn iter_tokens_add_default_metadata<G, I, P, L>(iter: impl IntoIterator<Item = TokenTree>) -> impl Iterator<Item = TokenTreeWithMetadata<G, I, P, L>>
484	where
485		G: Default,
486		I: Default,
487		P: Default,
488		L: Default,
489	{
490		iter.into_iter().map(|tt| tt.into())
491	}
492
493	/// Converts an iterator of ordinary [`TokenTree`]s into an iterator of
494	/// [`TokenTreeWithMetadata`]s with the given metadata.
495	pub fn iter_tokens_add_metadata<T>(iter: impl IntoIterator<Item = TokenTree>, metadata: &T) -> impl Iterator<Item = TokenTreeWithMetadata<T>>
496	where
497		T: Clone,
498	{
499		iter.into_iter().map(move |tt| (tt, metadata).into())
500	}
501
502	/// Converts an iterator of ordinary [`TokenTree`]s into an iterator of
503	/// [`TokenTreeWithMetadata`]s with the given specific metadata for each
504	/// token type.
505	pub fn iter_tokens_add_specific_metadata<G, I, P, L>(
506		iter: impl IntoIterator<Item = TokenTree>,
507		group: &G,
508		ident: &I,
509		punct: &P,
510		literal: &L,
511	) -> impl Iterator<Item = TokenTreeWithMetadata<G, I, P, L>>
512	where
513		G: Clone,
514		I: Clone,
515		P: Clone,
516		L: Clone,
517	{
518		iter.into_iter().map(move |tt| (tt, group, ident, punct, literal).into())
519	}
520}