11use proc_macro:: TokenStream ;
22use quote:: { format_ident, quote} ;
3- use syn:: { Expr , Ident , ItemFn , ItemStatic , ReturnType , parse_macro_input} ;
3+ use syn:: { Ident , ItemFn , ItemStatic , ReturnType , parse_macro_input} ;
44
55/// Wraps a `static mut` variable as a reactive signal (similar to a property)
66/// with getter and setter functions.
@@ -175,8 +175,7 @@ pub fn memo(_attr: TokenStream, item: TokenStream) -> TokenStream {
175175 }
176176
177177 let ident = format_ident ! ( "{}" , ident. to_string( ) . to_uppercase( ) ) ;
178- let ty =
179- quote ! { reactive_cache:: Lazy <reactive_cache:: Memo <#output_ty, fn ( ) -> #output_ty>> } ;
178+ let ty = quote ! { reactive_cache:: Lazy <reactive_cache:: Memo <#output_ty, fn ( ) -> #output_ty>> } ;
180179 let expr = quote ! { reactive_cache:: Lazy :: new( || reactive_cache:: Memo :: new( || #block) ) } ;
181180
182181 let expanded = quote ! {
@@ -192,95 +191,6 @@ pub fn memo(_attr: TokenStream, item: TokenStream) -> TokenStream {
192191 expanded. into ( )
193192}
194193
195- /// Creates a reactive effect from a closure or function pointer.
196- ///
197- /// The `effect!` procedural macro is a convenient wrapper around `reactive_cache::Effect::new`.
198- /// It allows you to quickly register a reactive effect that automatically tracks
199- /// dependencies and re-runs when they change.
200- ///
201- /// # Requirements
202- ///
203- /// - The argument must be either:
204- /// 1. A closure (e.g., `|| { ... }`), or
205- /// 2. A function pointer / function name with zero arguments.
206- /// - The closure or function must return `()` (no return value required).
207- ///
208- /// # Examples
209- ///
210- /// ```rust
211- /// use std::{cell::Cell, rc::Rc};
212- /// use reactive_macros::{effect, signal};
213- ///
214- /// signal!(static mut A: i32 = 1;);
215- ///
216- /// // Track effect runs
217- /// let counter = Rc::new(Cell::new(0));
218- /// let counter_clone = counter.clone();
219- ///
220- /// let e = effect!(move || {
221- /// let _ = A(); // reading the signal
222- /// counter_clone.set(counter_clone.get() + 1); // increment effect counter
223- /// });
224- ///
225- /// let ptr = Rc::into_raw(e); // actively leak to avoid implicitly dropping the effect
226- ///
227- /// // Effect runs immediately upon creation
228- /// assert_eq!(counter.get(), 1);
229- ///
230- /// // Changing A triggers the effect again
231- /// assert!(A_set(10));
232- /// assert_eq!(counter.get(), 2);
233- ///
234- /// // Setting the same value does NOT trigger the effect
235- /// assert!(!A_set(10));
236- /// assert_eq!(counter.get(), 2);
237- /// ```
238- ///
239- /// # SAFETY
240- ///
241- /// The macro internally uses `reactive_cache::Effect`, which relies on
242- /// `static` tracking and is **not thread-safe**. Only use in single-threaded contexts.
243- ///
244- /// # Warning
245- ///
246- /// **Do not set any signal that is part of the same effect chain.**
247- ///
248- /// Effects automatically run whenever one of their dependent signals changes.
249- /// If an effect modifies a signal that it (directly or indirectly) observes,
250- /// it creates a circular dependency. This can lead to:
251- /// - an infinite loop of updates, or
252- /// - conflicting updates that the system cannot resolve.
253- ///
254- /// In the general case, it is impossible to automatically determine whether
255- /// such an effect will ever terminate—this is essentially a version of the
256- /// halting problem. Therefore, you must ensure manually that effects do not
257- /// update signals within their own dependency chain.
258- #[ proc_macro]
259- pub fn effect ( input : TokenStream ) -> TokenStream {
260- let expr = parse_macro_input ! ( input as Expr ) ;
261-
262- let expanded = match expr {
263- Expr :: Path ( path) if path. path . get_ident ( ) . is_some ( ) => {
264- let ident = path. path . get_ident ( ) . unwrap ( ) ;
265- quote ! {
266- reactive_cache:: Effect :: new( #ident)
267- }
268- }
269- Expr :: Closure ( closure) => {
270- quote ! {
271- reactive_cache:: Effect :: new( #closure)
272- }
273- }
274- _ => {
275- return syn:: Error :: new_spanned ( & expr, "Expected a variable name or a closure" )
276- . to_compile_error ( )
277- . into ( ) ;
278- }
279- } ;
280-
281- expanded. into ( )
282- }
283-
284194/// Evaluates a zero-argument function and optionally reports when the value changes.
285195///
286196/// The `#[evaluate(print_fn)]` attribute macro transforms a function into a reactive
0 commit comments