Skip to main content

reifydb_macro_impl/
generate.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 ReifyDB
3
4use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
5
6pub fn ident(name: &str) -> TokenTree {
7	TokenTree::Ident(Ident::new(name, Span::call_site()))
8}
9
10pub fn underscore() -> TokenTree {
11	"_".parse::<TokenStream>().unwrap().into_iter().next().unwrap()
12}
13
14#[allow(dead_code)]
15pub fn ident_raw(name: &str) -> TokenTree {
16	if let Some(stripped) = name.strip_prefix("r#") {
17		TokenTree::Ident(Ident::new_raw(stripped, Span::call_site()))
18	} else {
19		TokenTree::Ident(Ident::new(name, Span::call_site()))
20	}
21}
22
23pub fn punct(ch: char) -> TokenTree {
24	TokenTree::Punct(Punct::new(ch, Spacing::Alone))
25}
26
27pub fn punct_joint(ch: char) -> TokenTree {
28	TokenTree::Punct(Punct::new(ch, Spacing::Joint))
29}
30
31pub fn literal_str(s: &str) -> TokenTree {
32	TokenTree::Literal(Literal::string(s))
33}
34
35pub fn literal_usize(n: usize) -> TokenTree {
36	TokenTree::Literal(Literal::usize_unsuffixed(n))
37}
38
39pub fn group(delimiter: Delimiter, tokens: impl IntoIterator<Item = TokenTree>) -> TokenTree {
40	TokenTree::Group(Group::new(delimiter, tokens.into_iter().collect()))
41}
42
43pub fn parens(tokens: impl IntoIterator<Item = TokenTree>) -> TokenTree {
44	group(Delimiter::Parenthesis, tokens)
45}
46
47pub fn braces(tokens: impl IntoIterator<Item = TokenTree>) -> TokenTree {
48	group(Delimiter::Brace, tokens)
49}
50
51pub fn brackets(tokens: impl IntoIterator<Item = TokenTree>) -> TokenTree {
52	group(Delimiter::Bracket, tokens)
53}
54
55pub fn path_sep() -> impl Iterator<Item = TokenTree> {
56	[punct_joint(':'), punct(':')].into_iter()
57}
58
59pub fn path(segments: &[&str]) -> Vec<TokenTree> {
60	let mut expanded: Vec<&str> = Vec::new();
61	for seg in segments {
62		if seg.is_empty() {
63			expanded.push("");
64		} else {
65			for part in seg.split("::") {
66				expanded.push(part);
67			}
68		}
69	}
70
71	let mut tokens = Vec::new();
72	let mut prev_was_empty = false;
73
74	for (i, seg) in expanded.iter().enumerate() {
75		let need_sep = if i == 0 {
76			seg.is_empty()
77		} else {
78			!prev_was_empty
79		};
80
81		if need_sep {
82			tokens.extend(path_sep());
83		}
84
85		if !seg.is_empty() {
86			tokens.push(ident(seg));
87		}
88
89		prev_was_empty = seg.is_empty();
90	}
91	tokens
92}
93
94pub fn arrow() -> impl Iterator<Item = TokenTree> {
95	[punct_joint('-'), punct('>')].into_iter()
96}
97
98pub fn fat_arrow() -> impl Iterator<Item = TokenTree> {
99	[punct_joint('='), punct('>')].into_iter()
100}
101
102#[allow(dead_code)]
103pub fn generics(inner: impl IntoIterator<Item = TokenTree>) -> Vec<TokenTree> {
104	let mut tokens = vec![punct('<')];
105	tokens.extend(inner);
106	tokens.push(punct('>'));
107	tokens
108}
109
110#[allow(dead_code)]
111pub fn extend(tokens: &mut Vec<TokenTree>, iter: impl IntoIterator<Item = TokenTree>) {
112	tokens.extend(iter);
113}
114
115pub fn compile_error(message: &str) -> TokenStream {
116	let tokens = vec![ident("compile_error"), punct('!'), parens([literal_str(message)])];
117	tokens.into_iter().collect()
118}