rune_macros/
lib.rs

1//! <img alt="rune logo" src="https://raw.githubusercontent.com/rune-rs/rune/main/assets/icon.png" />
2//! <br>
3//! <a href="https://github.com/rune-rs/rune"><img alt="github" src="https://img.shields.io/badge/github-rune--rs/rune-8da0cb?style=for-the-badge&logo=github" height="20"></a>
4//! <a href="https://crates.io/crates/rune-macros"><img alt="crates.io" src="https://img.shields.io/crates/v/rune-macros.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20"></a>
5//! <a href="https://docs.rs/rune-macros"><img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-rune--macros-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20"></a>
6//! <a href="https://discord.gg/v5AeNkT"><img alt="chat on discord" src="https://img.shields.io/discord/558644981137670144.svg?logo=discord&style=flat-square" height="20"></a>
7//! <br>
8//! Minimum support: Rust <b>1.87+</b>.
9//! <br>
10//! <br>
11//! <a href="https://rune-rs.github.io"><b>Visit the site 🌐</b></a>
12//! &mdash;
13//! <a href="https://rune-rs.github.io/book/"><b>Read the book 📖</b></a>
14//! <br>
15//! <br>
16//!
17//! Macros for the Rune Language, an embeddable dynamic programming language for Rust.
18//!
19//! <br>
20//!
21//! ## Usage
22//!
23//! This is part of the [Rune Language](https://rune-rs.github.io).
24
25#![allow(clippy::manual_map)]
26#![allow(clippy::too_many_arguments)]
27
28mod any;
29mod const_value;
30mod context;
31mod from_value;
32mod function;
33mod hash;
34mod inst_display;
35mod item;
36mod macro_;
37mod module;
38mod opaque;
39mod parse;
40mod path_in;
41mod quote;
42mod spanned;
43mod to_tokens;
44mod to_value;
45
46use self::context::{Context, Tokens};
47
48use ::quote::format_ident;
49use proc_macro2::TokenStream;
50use syn::{Generics, Path};
51
52const RUNE: &str = "rune";
53
54#[proc_macro]
55#[doc(hidden)]
56pub fn quote(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
57    let input = proc_macro2::TokenStream::from(input);
58    let parser = crate::quote::Quote::new();
59
60    let output = match parser.parse(input) {
61        Ok(output) => output,
62        Err(e) => return proc_macro::TokenStream::from(e.to_compile_error()),
63    };
64
65    output.into()
66}
67
68#[proc_macro_attribute]
69#[doc(hidden)]
70pub fn function(
71    attrs: proc_macro::TokenStream,
72    item: proc_macro::TokenStream,
73) -> proc_macro::TokenStream {
74    let attrs = syn::parse_macro_input!(attrs with crate::function::FunctionAttrs::parse);
75    let function = syn::parse_macro_input!(item with crate::function::Function::parse);
76
77    let output = match function.expand(attrs) {
78        Ok(output) => output,
79        Err(e) => return proc_macro::TokenStream::from(e.to_compile_error()),
80    };
81
82    output.into()
83}
84
85#[proc_macro_attribute]
86#[doc(hidden)]
87pub fn macro_(
88    attrs: proc_macro::TokenStream,
89    item: proc_macro::TokenStream,
90) -> proc_macro::TokenStream {
91    let attrs = syn::parse_macro_input!(attrs with crate::macro_::Config::parse);
92    let macro_ = syn::parse_macro_input!(item with crate::macro_::Macro::parse);
93
94    let output = match macro_.expand(attrs, format_ident!("function")) {
95        Ok(output) => output,
96        Err(e) => return proc_macro::TokenStream::from(e.to_compile_error()),
97    };
98
99    output.into()
100}
101
102#[proc_macro_attribute]
103#[doc(hidden)]
104pub fn module(
105    attrs: proc_macro::TokenStream,
106    item: proc_macro::TokenStream,
107) -> proc_macro::TokenStream {
108    let attrs = syn::parse_macro_input!(attrs with crate::module::ModuleAttrs::parse);
109    let module = syn::parse_macro_input!(item with crate::module::Module::parse);
110
111    let output = match module.expand(attrs) {
112        Ok(output) => output,
113        Err(e) => return proc_macro::TokenStream::from(e.to_compile_error()),
114    };
115
116    output.into()
117}
118
119#[proc_macro_attribute]
120#[doc(hidden)]
121pub fn attribute_macro(
122    attrs: proc_macro::TokenStream,
123    item: proc_macro::TokenStream,
124) -> proc_macro::TokenStream {
125    let attrs = syn::parse_macro_input!(attrs with crate::macro_::Config::parse);
126    let macro_ = syn::parse_macro_input!(item with crate::macro_::Macro::parse);
127
128    let output = match macro_.expand(attrs, format_ident!("attribute")) {
129        Ok(output) => output,
130        Err(e) => return proc_macro::TokenStream::from(e.to_compile_error()),
131    };
132
133    output.into()
134}
135
136#[proc_macro_derive(ToTokens, attributes(rune))]
137#[doc(hidden)]
138pub fn to_tokens(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
139    let derive = syn::parse_macro_input!(input as to_tokens::Derive);
140    Context::build(|cx| derive.expand(cx)).into()
141}
142
143#[proc_macro_derive(Parse, attributes(rune))]
144#[doc(hidden)]
145pub fn parse(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
146    let derive = syn::parse_macro_input!(input as parse::Derive);
147    Context::build(|cx| derive.expand(cx)).into()
148}
149
150/// Helper derive to implement `Spanned`.
151#[proc_macro_derive(Spanned, attributes(rune))]
152pub fn spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
153    let derive = syn::parse_macro_input!(input as spanned::Derive);
154    Context::build(|cx| derive.expand(cx, false)).into()
155}
156
157#[proc_macro_derive(OptionSpanned, attributes(rune))]
158#[doc(hidden)]
159pub fn option_spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
160    let derive = syn::parse_macro_input!(input as spanned::Derive);
161    Context::build(|cx| derive.expand(cx, true)).into()
162}
163
164#[proc_macro_derive(Opaque, attributes(rune))]
165#[doc(hidden)]
166pub fn opaque(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
167    let derive = syn::parse_macro_input!(input as opaque::Derive);
168    Context::build(|cx| derive.expand(cx)).into()
169}
170
171#[proc_macro_derive(FromValue, attributes(rune))]
172#[doc(hidden)]
173pub fn from_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
174    let input = syn::parse_macro_input!(input as syn::DeriveInput);
175    Context::build(|cx| from_value::expand(cx, &input)).into()
176}
177
178#[proc_macro_derive(ToValue, attributes(rune))]
179#[doc(hidden)]
180pub fn to_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
181    let input = syn::parse_macro_input!(input as syn::DeriveInput);
182    Context::build(|cx| to_value::expand(cx, &input)).into()
183}
184
185#[proc_macro_derive(Any, attributes(rune))]
186#[doc(hidden)]
187pub fn any(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
188    let derive = syn::parse_macro_input!(input as any::Derive);
189
190    let stream = Context::build(|cx| {
191        let attr = cx.type_attrs(&derive.input.attrs);
192        let tokens = cx.tokens_with_module(attr.module.as_ref());
193        Ok(derive.into_any_builder(cx, &attr, &tokens)?.expand())
194    });
195
196    stream.into()
197}
198
199#[proc_macro_derive(ToConstValue, attributes(const_value))]
200#[doc(hidden)]
201pub fn const_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
202    let derive = syn::parse_macro_input!(input as const_value::Derive);
203    Context::build(|cx| Ok(derive.into_builder(cx)?.expand())).into()
204}
205
206#[proc_macro]
207#[doc(hidden)]
208pub fn hash(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
209    let args = syn::parse_macro_input!(input as self::hash::Arguments);
210
211    let stream = Context::build(|cx| {
212        let Tokens { hash, .. } = cx.tokens_with_module(None);
213        let value = args.build_type_hash(cx)?.into_inner();
214        Ok(::quote::quote!(#hash(#value)))
215    });
216
217    stream.into()
218}
219
220#[proc_macro]
221#[doc(hidden)]
222pub fn hash_in(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
223    let path_in::PathIn { in_crate, item, .. } =
224        syn::parse_macro_input!(input as path_in::PathIn<self::hash::Arguments>);
225
226    let stream = Context::build(|cx| {
227        let value = item.build_type_hash(cx)?.into_inner();
228        Ok(::quote::quote!(#in_crate::Hash(#value)))
229    });
230
231    stream.into()
232}
233
234#[proc_macro]
235#[doc(hidden)]
236pub fn item(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
237    let path = syn::parse_macro_input!(input as syn::Path);
238
239    let stream = match self::item::build_item(&path) {
240        Ok(hash) => {
241            ::quote::quote!(unsafe { rune::Item::from_bytes(&#hash) })
242        }
243        Err(error) => to_compile_errors([error]),
244    };
245
246    stream.into()
247}
248
249#[proc_macro]
250#[doc(hidden)]
251pub fn item_in(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
252    let path_in::PathIn { in_crate, item, .. } = syn::parse_macro_input!(input as path_in::PathIn);
253
254    let stream = match self::item::build_item(&item) {
255        Ok(hash) => {
256            ::quote::quote!(unsafe { #in_crate::Item::from_bytes(&#hash) })
257        }
258        Err(error) => to_compile_errors([error]),
259    };
260
261    stream.into()
262}
263
264#[proc_macro]
265#[doc(hidden)]
266pub fn binding(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
267    let derive = syn::parse_macro_input!(input as any::InternalCall);
268
269    let stream = Context::build_with_crate(|cx| {
270        let mut stream = TokenStream::default();
271        let tokens = cx.tokens_with_module(None);
272
273        for builder in derive.into_any_builders(cx, &tokens) {
274            stream.extend(builder.expand());
275        }
276
277        Ok(stream)
278    });
279
280    stream.into()
281}
282
283#[proc_macro_attribute]
284#[doc(hidden)]
285pub fn stable(
286    _attr: proc_macro::TokenStream,
287    item: proc_macro::TokenStream,
288) -> proc_macro::TokenStream {
289    item
290}
291
292#[proc_macro_attribute]
293#[doc(hidden)]
294pub fn unstable(
295    _attr: proc_macro::TokenStream,
296    item: proc_macro::TokenStream,
297) -> proc_macro::TokenStream {
298    item
299}
300
301#[proc_macro_derive(InstDisplay, attributes(inst_display))]
302#[doc(hidden)]
303pub fn inst_display(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
304    let derive = syn::parse_macro_input!(input as inst_display::Derive);
305    derive.expand().unwrap_or_else(to_compile_errors).into()
306}
307
308/// Adds the `path` as trait bound to each generic
309fn add_trait_bounds(generics: &mut Generics, path: &Path) {
310    for ty in &mut generics.type_params_mut() {
311        ty.bounds.push(syn::TypeParamBound::Trait(syn::TraitBound {
312            paren_token: None,
313            modifier: syn::TraitBoundModifier::None,
314            lifetimes: None,
315            path: path.clone(),
316        }));
317    }
318}
319
320fn to_compile_errors<I>(errors: I) -> proc_macro2::TokenStream
321where
322    I: IntoIterator<Item = syn::Error>,
323{
324    let compile_errors = errors.into_iter().map(syn::Error::into_compile_error);
325    ::quote::quote!(#(#compile_errors)*)
326}