crux_macros/
lib.rs

1#![deny(clippy::pedantic)]
2
3mod capability;
4mod effect;
5mod effect_derive;
6mod export;
7
8use capability::capability_impl;
9use export::export_impl;
10use proc_macro::TokenStream;
11use proc_macro_error::proc_macro_error;
12use syn::{parse_macro_input, Ident, ItemEnum};
13
14/// Deprecated: use the `effect` attribute macro instead.
15///
16/// Procedural macro to derive an Effect enum, with a variant for
17/// each non-skipped capability.
18///
19/// The default name of the Effect enum is "Effect", but this can be
20/// overridden with the `name` attribute.
21///
22/// The default name of the app struct is "App", but this can be
23/// overridden with the `app` attribute.
24///
25/// No Effect variant will be generated for fields annotated with
26/// `#[effect(skip)]`.
27///
28/// e.g.
29/// ```rust
30/// # use crux_core::{Capability, render::Render, compose::Compose};
31/// # use crux_core::macros::Effect;
32/// # #[derive(Default)]
33/// # struct MyApp;
34/// # pub enum MyEvent {None}
35/// # impl crux_core::App for MyApp {
36/// #     type Event = MyEvent;
37/// #     type Model = ();
38/// #     type ViewModel = ();
39/// #     type Capabilities = MyCapabilities;
40/// #     type Effect = MyEffect;
41/// #     fn update(
42/// #         &self,
43/// #         _event: Self::Event,
44/// #         _model: &mut Self::Model,
45/// #         _caps: &Self::Capabilities,
46/// #     ) -> crux_core::Command<MyEffect, MyEvent> {
47/// #         unimplemented!()
48/// #     }
49/// #     fn view(&self, _model: &Self::Model) -> Self::ViewModel {
50/// #         unimplemented!()
51/// #     }
52/// # }
53/// #[derive(Effect)]
54/// #[effect(name = "MyEffect")]
55/// pub struct MyCapabilities {
56///     pub http: crux_http::Http<MyEvent>,
57///     pub render: Render<MyEvent>,
58///     #[effect(skip)]
59///     pub compose: Compose<MyEvent>,
60/// }
61#[proc_macro_derive(Effect, attributes(effect))]
62#[proc_macro_error]
63pub fn effect_derive(input: TokenStream) -> TokenStream {
64    effect_derive::effect_impl(&parse_macro_input!(input)).into()
65}
66
67/// Generates an effect type matching the enum definition provided,
68/// whilst supplying all the necessary decorations and additional trait implementations.
69///
70/// Use `typegen` as an argument if you want to opt in to the built-in foreign type generation.
71///
72/// e.g.
73/// ```rust
74/// # use crux_core::{Capability, render::RenderOperation, compose::Compose};
75/// # use crux_core::macros::effect;
76/// # use crux_http::protocol::HttpRequest;
77/// # #[derive(Default)]
78/// # struct MyApp;
79/// # pub enum MyEvent {None}
80/// # impl crux_core::App for MyApp {
81/// #     type Event = MyEvent;
82/// #     type Model = ();
83/// #     type ViewModel = ();
84/// #     type Capabilities = ();
85/// #     type Effect = MyEffect;
86/// #     fn update(
87/// #         &self,
88/// #         _event: Self::Event,
89/// #         _model: &mut Self::Model,
90/// #         _caps: &Self::Capabilities,
91/// #     ) -> crux_core::Command<MyEffect, MyEvent> {
92/// #         unimplemented!()
93/// #     }
94/// #     fn view(&self, _model: &Self::Model) -> Self::ViewModel {
95/// #         unimplemented!()
96/// #     }
97/// # }
98/// #[effect(typegen)]
99/// pub enum MyEffect {
100///     Render(RenderOperation),
101///     Http(HttpRequest),
102/// }
103/// ```
104#[proc_macro_attribute]
105pub fn effect(args: TokenStream, input: TokenStream) -> TokenStream {
106    let args = parse_macro_input!(args as Option<Ident>);
107    let input = parse_macro_input!(input as ItemEnum);
108    effect::effect_impl(args, input).into()
109}
110
111#[proc_macro_derive(Export)]
112#[proc_macro_error]
113pub fn export(input: TokenStream) -> TokenStream {
114    export_impl(&parse_macro_input!(input)).into()
115}
116
117/// Deprecated: use the `effect` attribute macro instead.
118#[proc_macro_derive(Capability)]
119#[proc_macro_error]
120pub fn capability(input: TokenStream) -> TokenStream {
121    capability_impl(&parse_macro_input!(input)).into()
122}
123
124#[cfg(test)]
125fn pretty_print(ts: &proc_macro2::TokenStream) -> String {
126    let file = syn::parse_file(&ts.to_string()).unwrap();
127    prettyplease::unparse(&file)
128}