interthread/lib.rs
1
2
3
4//! # Intro
5//!
6//! This document covers the usage of the crate's macros, it does
7//! not delve into the detailed logic of the generated code.
8//!
9//! For a comprehensive understanding of the underlying
10//! concepts and implementation details of the Actor Model,
11//! it's recommended to read the article [Actors with Tokio](https://ryhl.io/blog/actors-with-tokio/)
12//! by Alice Ryhl ( also known as _Darksonn_ ) also a great
13//! talk by the same author on the same subject if a more
14//! interactive explanation is prefered
15//! [Actors with Tokio – a lesson in ownership - Alice Ryhl](https://www.youtube.com/watch?v=fTXuGRP1ee4)
16//! (video).
17//! This article not only inspired the development of the
18//! `interthread` crate but serves as foundation
19//! for the Actor Model implementation logic in it.
20
21
22//! ## What is an Actor ?
23//!
24//! Despite being a fundamental concept in concurrent programming,
25//! defining exactly what an actor is can be ambiguous.
26//!
27//! - *Carl Hewitt*, often regarded as the father of the Actor Model,
28//! [The Actor Model](https://www.youtube.com/watch?v=7erJ1DV_Tlo) (video).
29//!
30//! - Wikipidia [Actor Model](https://en.wikipedia.org/wiki/Actor_model)
31//!
32//!
33//! a quote from [Actors with Tokio](https://ryhl.io/blog/actors-with-tokio/):
34//!
35//! > "The basic idea behind an actor is to spawn a
36//! self-contained task that performs some job independently
37//! of other parts of the program. Typically these actors
38//! communicate with the rest of the program through
39//! the use of message passing channels. Since each actor
40//! runs independently, programs designed using them are
41//! naturally parallel."
42//! > - Alice Ryhl
43//!
44//! ## What is the problem ?
45//!
46//! To achieve parallel execution of individual objects
47//! within the same program, it is challenging due
48//! to the need for various types that are capable of
49//! working across threads. The main difficulty
50//! lies in the fact that as you introduce thread-related types,
51//! you can quickly lose sight of the main program
52//! idea as the focus shifts to managing thread-related
53//! concerns.
54//!
55//! It involves using constructs like threads, locks, channels,
56//! and other synchronization primitives. These additional
57//! types and mechanisms introduce complexity and can obscure
58//! the core logic of the program.
59//!
60//!
61//! ## Solution
62//!
63//! The [`actor`](./attr.actor.html) macro - when applied to the
64//! implementation block of a given "MyActor" object,
65//! generates additional Struct types
66//! that enable communication between threads.
67//!
68//! A notable outcome of applying this macro is the
69//! creation of the `MyActorLive` struct ("ActorName" + "Live"),
70//! which acts as an interface/handle to the `MyActor` object.
71//! `MyActorLive` retains the exact same public method signatures
72//! as `MyActor`, allowing users to interact with the actor as if
73//! they were directly working with the original object.
74//!
75//! ### Examples
76//!
77//!
78//! Filename: Cargo.toml
79//!
80//!```text
81//![dependencies]
82//!interthread = "3.1.0"
83//!oneshot = "0.1.11"
84//!```
85//!
86//! Filename: main.rs
87//!```rust no_run
88//!pub struct MyActor {
89//! value: i8,
90//!}
91//!
92//!#[interthread::actor]
93//!impl MyActor {
94//!
95//! pub fn new( v: i8 ) -> Self {
96//! Self { value: v }
97//! }
98//! pub fn increment(&mut self) {
99//! self.value += 1;
100//! }
101//! pub fn add_number(&mut self, num: i8) -> i8 {
102//! self.value += num;
103//! self.value
104//! }
105//! pub fn get_value(&self) -> i8 {
106//! self.value
107//! }
108//!}
109//!
110//!fn main() {
111//!
112//! let actor = MyActorLive::new(5);
113//!
114//! let mut actor_a = actor.clone();
115//! let mut actor_b = actor.clone();
116//!
117//! let handle_a = std::thread::spawn( move || {
118//! actor_a.increment();
119//! });
120//!
121//! let handle_b = std::thread::spawn( move || {
122//! actor_b.add_number(5);
123//! });
124//!
125//! let _ = handle_a.join();
126//! let _ = handle_b.join();
127//!
128//! assert_eq!(actor.get_value(), 11)
129//!}
130//!
131//! ```
132//!
133//! An essential point to highlight is that when invoking
134//! `MyActorLive::new`, not only does it return an instance
135//! of `MyActorLive`, but it also spawns a new thread that
136//! contains an instance of `MyActor` in it.
137//! This introduces parallelism to the program.
138//!
139//! The code generated by the [`actor`](./attr.actor.html) takes
140//! care of the underlying message routing and synchronization,
141//! allowing developers to rapidly prototype their application's
142//! core functionality. This fast sketching capability is
143//! particularly useful when exploring different design options,
144//! experimenting with concurrency models, or implementing
145//! proof-of-concept systems. Not to mention, the cases where
146//! the importance of the program lies in the result of its work
147//! rather than its execution.
148//!
149//!
150//! # SDPL Framework
151//!
152//!
153//! The code generated by the [`actor`](./attr.actor.html) macro
154//! can be divided into four more or less important but distinct
155//! parts: [`script`](#script) ,[`direct`](#direct),
156//! [`play`](#play), [`live`](#live) .
157//!
158//! This categorization provides an intuitive
159//! and memorable way to understand the different aspects
160//! of the generated code.
161//!
162//! Expanding the above example, uncomment the [`example`](./attr.example.html)
163//! placed above the `main` function, go to `examples/inter/main.rs` in your
164//! root directory and find `MyActor` along with additional SDPL parts :
165//!
166//! # `script`
167//!
168//! Think of script as a message type definition.
169//!
170//! The declaration of an `ActorName + Script` enum, which is
171//! serving as a collection of variants that represent
172//! different messages that may be sent across threads through a
173//! channel.
174//!
175//! Each variant corresponds to a struct with fields
176//! that capture the input and/or output parameters of
177//! the respective public methods of the Actor.
178//!
179//!
180//! ```rust no_run
181//!
182//! pub enum MyActorScript {
183//! Increment {},
184//! AddNumber { num: i8, inter_send: oneshot::Sender<i8> },
185//! GetValue { inter_send: oneshot::Sender<i8> },
186//! }
187//!
188//! ```
189//!
190//! > **Note**: Method `new` not included as a variant in the `script`.
191//!
192//!
193//! # direct
194//! The implementation block of `script`struct, specifically
195//! the `direct` method which allows
196//! for direct invocation of the Actor's methods by mapping
197//! the enum variants to the corresponding function calls.
198//!
199//!
200//!```rust no_run
201//!impl MyActorScript {
202//! pub fn direct(self, actor: &mut MyActor) {
203//! match self {
204//! MyActorScript::Increment {} => {
205//! actor.increment();
206//! }
207//! MyActorScript::AddNumber { num, inter_send } => {
208//! inter_send
209//! .send(actor.add_number(num))
210//! .unwrap_or_else(|_error| {
211//! core::panic!(
212//! "'MyActorScript::AddNumber.direct'. Sending on a closed channel."
213//! )
214//! });
215//! }
216//! MyActorScript::GetValue { inter_send } => {
217//! inter_send
218//! .send(actor.get_value())
219//! .unwrap_or_else(|_error| {
220//! core::panic!(
221//! "'MyActorScript::GetValue.direct'. Sending on a closed channel."
222//! )
223//! });
224//! }
225//! }
226//! }
227//!}
228//!```
229//!
230//! # play
231//! The implementation block of `script`struct, specifically
232//! the `play` associated (static) method responsible for
233//! continuously receiving `script` variants from
234//! a dedicated channel and `direct`ing them.
235//!
236//! Also this function serves as the home for the Actor itself.
237//!
238//!
239//!```rust no_run
240//!impl MyActorScript {
241//! pub fn play(receiver: std::sync::mpsc::Receiver<MyActorScript>,
242//! mut actor: MyActor) {
243//! while let std::result::Result::Ok(msg) = receiver.recv() {
244//! msg.direct(&mut actor);
245//! }
246//! eprintln!("MyActor the end ...");
247//! }
248//!}
249//!```
250//!
251//! When using the [`edit`](./attr.actor.html#edit) argument in the [`actor`](./attr.actor.html)
252//! macro, such as
253//!
254//!```rust no_run
255//!#[interthread::actor(edit(script(imp(play))))]
256//!```
257//!
258//! it allows for manual implementation of the `play` part, which
259//! gives the flexibility to customize and modify
260//! the behavior of the `play` to suit any requared logic.
261//!
262//!
263//!
264//! # live
265//! A struct `ActorName + Live`, which serves as an interface/handler
266//! replicating the public method signatures of the original Actor.
267//!
268//! Invoking a method on a live instance, it's triggering the eventual
269//! invocation of the corresponding method within the Actor.
270//!
271//! The special method of `live` method `new`
272//! - initiates a new channel
273//! - initiates an instace of the Actor
274//! - spawns the `play` component in a separate thread
275//! - returns an instance of `Self`
276//!
277//!
278//! ```rust no_run
279//!
280//!#[derive(Clone)]
281//!pub struct MyActorLive {
282//! sender: std::sync::mpsc::Sender<MyActorScript>,
283//!}
284//!impl MyActorLive {
285//! pub fn new(v: i8) -> Self {
286//! let actor = MyActor::new(v);
287//! let (sender, receiver) = std::sync::mpsc::channel();
288//! std::thread::spawn(move || { MyActorScript::play(receiver, actor) });
289//! Self { sender }
290//! }
291//! pub fn increment(&mut self) {
292//! let msg = MyActorScript::Increment {};
293//! let _ = self
294//! .sender
295//! .send(msg)
296//! .expect("'MyActorLive::method.send'. Channel is closed!");
297//! }
298//! pub fn add_number(&mut self, num: i8) -> i8 {
299//! let (inter_send, inter_recv) = oneshot::channel();
300//! let msg = MyActorScript::AddNumber {
301//! num,
302//! inter_send,
303//! };
304//! let _ = self
305//! .sender
306//! .send(msg)
307//! .expect("'MyActorLive::method.send'. Channel is closed!");
308//! inter_recv
309//! .recv()
310//! .unwrap_or_else(|_error| {
311//! core::panic!("'MyActor::add_number' from inter_recv. Channel is closed!")
312//! })
313//! }
314//! pub fn get_value(&self) -> i8 {
315//! let (inter_send, inter_recv) = oneshot::channel();
316//! let msg = MyActorScript::GetValue {
317//! inter_send,
318//! };
319//! let _ = self
320//! .sender
321//! .send(msg)
322//! .expect("'MyActorLive::method.send'. Channel is closed!");
323//! inter_recv
324//! .recv()
325//! .unwrap_or_else(|_error| {
326//! core::panic!("'MyActor::get_value' from inter_recv. Channel is closed!")
327//! })
328//! }
329//!}
330//!
331//! ```
332//! The methods of `live` type have same method signature
333//! as Actor's own methods
334//! - initiate a `oneshot` channel
335//! - create a `msg` specific `script` variant
336//! - send the `msg` via `live`'s channel
337//! - receive and return the output if any
338//!
339//! # Panics
340//!
341//! The model will panic if an attempt is made to send or
342//! receive on the channel after it has been dropped.
343//! Generally, such issues are unlikely to occur, but
344//! if the `interact` option is used, it introduces a
345//! potential scenario for encountering this situation.
346//!
347//!
348//! # Macro Implicit Dependencies
349//!
350//! The [`actor`](./attr.actor.html) macro generates code
351//! that utilizes channels for communication. However,
352//! the macro itself does not provide any channel implementations.
353//! Therefore, depending on the libraries used in your project,
354//! you may need to import additional crates.
355//!
356//!### Crate Compatibility
357//!<table>
358//! <thead>
359//! <tr>
360//! <th>lib</th>
361//! <th><a href="https://docs.rs/oneshot">oneshot</a></th>
362//! <th><a href="https://docs.rs/async-channel">async_channel</a></th>
363//! </tr>
364//! </thead>
365//! <tbody>
366//! <tr>
367//! <td>std</td>
368//! <td style="text-align: center;">✓</td>
369//! <td style="text-align: center;"><b>-</b></td>
370//! </tr>
371//! <tr>
372//! <td><a href="https://crates.io/crates/smol">smol</a></td>
373//! <td style="text-align: center;">✓</td>
374//! <td style="text-align: center;">✓</td>
375//! </tr>
376//! <tr>
377//! <td><a href="https://docs.rs/tokio">tokio</a></td>
378//! <td style="text-align: center;"><b>-</b></td>
379//! <td style="text-align: center;"><b>-</b></td>
380//! </tr>
381//! <tr>
382//! <td><a href="https://crates.io/crates/async-std">async-std</a></td>
383//! <td style="text-align: center;">✓</td>
384//! <td style="text-align: center;"><b>-</b></td>
385//! </tr>
386//! </tbody>
387//!</table>
388//!
389//!
390//!>**Note:** The table shows the compatibility of
391//!>the macro with different libraries, indicating whether
392//!>the dependencies are needed (✔) or not.
393//!>The macros will provide helpful messages indicating
394//!>the necessary crate imports based on your project's dependencies.
395//!
396//!
397//! Checkout `interthread` on [](https://github.com/NimonSour/interthread)
398//!
399
400
401mod use_macro;
402mod write;
403mod file;
404mod check;
405mod error;
406mod parse;
407mod model;
408
409static INTERTHREAD: &'static str = "interthread";
410static INTER_EXAMPLE_DIR_NAME: &'static str = "INTER_EXAMPLE_DIR_NAME";
411static INTER: &'static str = "inter";
412// static WEB_ACTOR: &'static str = "web_actor";
413
414static ACTOR: &'static str = "actor";
415static FAMILY: &'static str = "family";
416
417static EXAMPLE: &'static str = "example";
418static EXAMPLES: &'static str = "examples";
419
420const RWLOCK: &str = "RwLock";
421const MUTEX: &str = "Mutex";
422const ARC: &str = "Arc";
423
424// vars
425static INTER_SEND: &'static str = "inter_send";
426static INTER_RECV: &'static str = "inter_recv";
427
428// Some of Attributes Arguments
429static EDIT: &'static str = "edit";
430static FILE: &'static str = "file";
431
432
433
434#[cfg(windows)]
435const LINE_ENDING: &'static str = "\r\n";
436#[cfg(not(windows))]
437const LINE_ENDING: &'static str = "\n";
438
439/// # Code transparency and exploration
440///
441/// [`example`](./attr.example.html) simplifies exploring and interacting with
442/// expanded macro-generated code. It generates example files with expanded
443/// content of `interthread` macros, making it easy for developers to debug, test, and experiment.
444///
445/// Consider a macro [`actor`](./attr.actor.html) inside the project
446/// in `src/my_file.rs`.
447///
448///Filename: my_file.rs
449///```rust no_run
450///
451///pub struct MyActor;
452///
453/// // you can have "example" macro in the same file
454/// // #[interthread::example(path="src/my_file.rs")]
455///
456///#[interthread::actor]
457///impl MyActor {
458/// pub fn new(value: u32) -> Self {Self}
459///}
460///
461///```
462///
463///Filename: main.rs
464///```rust no_run
465///#[interthread::example(path="src/my_file.rs")]
466///fn main(){
467///}
468///
469///```
470///
471/// The macro will create and write to `examples/inter/my_file.rs`
472/// the content of `src/my_file.rs` with the
473/// [`actor`](./attr.actor.html) macro expanded.
474///
475///
476///```text
477///my_project/
478///├── src/
479///│ ├── my_file.rs <--- macro "actor"
480///| |
481///│ └── main.rs <--- macro "example"
482///|
483///├── examples/
484/// ├── ...
485/// └── inter/
486/// ├── my_file.rs <--- expanded "src/my_file.rs"
487///```
488///
489/// When specifying the `main` argument
490/// in the `example` macro. It generates two files within
491/// the `examples/inter` directory: the expanded code file
492/// and an additional `main.rs` file.
493///
494///```rust no_run
495///#[example(main,path="my_file.rs")]
496///```
497///
498/// This option is particularly useful for debugging and experimentation.
499/// It allows developers to quickly run and interact with the generated code by executing:
500///
501///```terminal
502///$ cargo run --example inter
503///```
504///
505/// The expanded code file will be located at
506/// `examples/inter/my_file.rs`, while the `main.rs` file
507/// serves as an entry point for running the example.
508///
509/// ## Configuration Options
510///```text
511///
512///#[interthread::example(
513///
514/// main | mod *
515///
516/// path = "path/to/file.rs"
517///
518/// expand(actor,family) *
519/// )]
520///
521/// * - default
522///
523///```
524///
525/// # Arguments
526///
527/// - [`path`](#path)
528///
529/// - [`expand`](#expand) (default)
530///
531/// # path
532///
533/// The `path` argument is a required parameter of the [`example`](./attr.example.html) macro.
534/// It expects the path to the file that needs to be expanded.
535///
536/// This argument is essential as it specifies the target file
537/// for code expansion.
538///
539/// [`example`](./attr.example.html) macro can be
540/// placed on any item in any file within your `src` directory.
541///
542///
543/// # expand
544///
545/// This argument allows the user to specify which
546/// `interthread` macros to expand.
547///
548/// By default, the value of `expand` includes
549/// the [`actor`](./attr.actor.html) and
550/// [`family`](./attr.family.html) macros.
551///
552/// For example, if you want to expand only the
553/// [`actor`](./attr.actor.html) macro in generated
554/// example code, you can use the following attribute:
555///
556/// ```rust no_run
557/// #[example(path="my_file.rs",expand(actor))]
558/// ```
559/// This will generate an example code file that includes
560/// the expanded code of the [`actor`](./attr.actor.html) macro,
561/// while excluding other macros like
562/// [`family`](./attr.family.html).
563///
564
565
566#[proc_macro_error::proc_macro_error]
567#[proc_macro_attribute]
568pub fn example( attr: proc_macro::TokenStream, _item: proc_macro::TokenStream ) -> proc_macro::TokenStream {
569
570 let nested = syn::parse_macro_input!(attr with syn::punctuated::Punctuated::<syn::Meta,syn::Token![,]>::parse_terminated);
571 let mut eaa = model::attribute::ExampleAttributeArguments::from(nested);
572
573 let (file, lib) = file::expand_macros(&eaa.get_path(),&eaa.expand);
574
575 let some_lib = if eaa.main { Some(lib)} else { None };
576
577 let path = write::example_show(file, &eaa.get_path(), some_lib );
578
579 let msg = format!("The file has been SUCCESSFULLY created at {}",path.to_string_lossy());
580 let note = "To avoid potential issues and improve maintainability, it is recommended to comment out the macro after its successful execution. To proceed, please comment out the macro and re-run the compilation.";
581
582 proc_macro_error::abort!( proc_macro2::Span::call_site(),msg; note = note);
583
584}
585
586
587/// ## Evolves a regular object into an actor
588///
589/// The macro is placed upon an implement block of an object
590/// (`struct` or `enum`),
591/// which has a public or restricted method named `new` returning `Self`.
592///
593/// In case if the initialization could potentially fail,
594/// the method can be named `try_new`
595/// and return `Option<Self>` or `Result<Self>`.
596///
597/// The macro will copy method signatures from all
598/// public methods with receivers `&self` or `&mut self`
599/// and static methods.
600///
601/// The model is primarily designed to work for public methods with
602/// borrowed receivers (e.g., `&self` or `&mut self`) however
603/// `Self`-consuming receiver (e.g., `self`) can be incorporated
604/// see [`What Does a Self-Consuming Method Mean for the Model`](#self-consuming-methods)
605///
606/// If only a subset of methods is required to be
607/// accessible across threads, split the `impl` block
608/// into two parts. By applying the macro to a specific block,
609/// the macro will only consider the methods within that block, also see options
610/// [`include-exclude`](#include-exclude).
611///
612/// ## Configuration Options
613///```text
614///
615///#[interthread::actor(
616///
617/// channel = 0 *
618/// n (usize)
619///
620/// lib = "std" *
621/// "smol"
622/// "tokio"
623/// "async_std"
624///
625/// edit(
626/// script(..)
627/// live(..)
628/// )
629///
630/// file = "path/to/current/file.rs"
631///
632/// name = ""
633///
634/// show
635///
636/// include | exclude
637///
638/// debut
639///
640/// interact
641///)]
642///
643///* - default
644///
645///
646///```
647///
648/// # Arguments
649///
650///
651/// - [`channel`](#channel)
652/// - [`lib`](#lib)
653/// - [`edit`](#edit)
654/// - [`file`](#file)
655/// - [`name`](#name)
656/// - [`show`](#show)
657/// - [`include|exclude`](#include|exclude)
658/// - [`debut`](#debut)
659/// - [`interact`](#interact)
660///
661///
662///
663/// # channel
664///
665/// The `channel` argument specifies the type of channel.
666///
667/// - `0` (default)
668/// - [`usize`] ( buffer size)
669///
670/// The two macros
671/// ```rust no_run
672/// #[actor]
673/// ```
674/// and
675/// ```rust no_run
676/// #[actor(channel=0)]
677/// ```
678/// are in fact identical, both specifying same unbounded channel.
679///
680/// When specifying an [`usize`] value for the `channel` argument
681/// in the [`actor`](./attr.actor.html) macro, such as
682/// ```rust no_run
683/// #[actor(channel=4)]
684/// ```
685/// the actor will use a bounded channel with a buffer size of 4.
686/// This means that the channel can hold up to 4 messages in its
687/// buffer before blocking/suspending the sender.
688///
689/// Using a bounded channel with a specific buffer size allows
690/// for control over the memory usage and backpressure behavior
691/// of the model. When the buffer is full, any further attempts
692/// to send messages will block/suspend until there is available space.
693/// This provides a natural form of backpressure, allowing the
694/// sender to slow down or pause message production when the
695/// buffer is near capacity.
696///
697/// # lib
698///
699/// The `lib` argument specifies the 'async' library to use.
700///
701/// - `"std"` (default)
702/// - `"smol"`
703/// - `"tokio"`
704/// - `"async_std"`
705///
706///## Examples
707///```rust no_run
708///use interthread::actor;
709///
710///struct MyActor;
711///
712///#[actor(channel=10, lib ="tokio")]
713///impl MyActor{
714/// pub fn new() -> Self{Self}
715///}
716///#[tokio::main]
717///async fn main(){
718/// let my_act = MyActorLive::new();
719///}
720///```
721///
722/// # edit
723///
724/// The `edit` argument specifies the available editing options.
725/// When using this argument, the macro expansion will
726/// **exclude** the code related to `edit` options
727/// allowing the user to manually implement and
728/// customize those parts according to their specific needs.
729///
730///
731/// The SDPL Model encompasses two main structs, namely `ActorScript` and `ActorLive`.
732/// Within the `edit` statement, these are referenced as `script`
733/// and `live` respectively.
734///
735/// Each struct comprises three distinct sections:
736/// - `def` - definition
737/// - `imp` - implementation block
738/// - `trt` - implemented traits
739///
740/// ```rust no_run
741/// edit(
742/// script(
743/// def, // <- script definition
744/// imp(..), // <- list of methods in impl block
745/// trt(..) // <- list of traits
746/// ),
747///
748/// live(
749/// def, // <- live definition
750/// imp(..), // <- list of methods in impl block
751/// trt(..) // <- list of traits
752/// )
753/// )
754/// ```
755///
756/// So this option instructs the macro to:
757///
758/// - Exclude specified sections of code from the generated model.
759///
760/// Examples:
761/// - `edit(script)`: Excludes the entire Script enum.
762/// - `edit(live(imp))`: Excludes the entire implementation block of the Live struct.
763/// - `edit(live(def, imp(new)))`: Excludes both the definition of the Live struct and the method 'new.'
764/// - `edit(script(imp(play)), live(imp(new)))`: Excludes the 'play' method from the Script enum and the 'new' method from the Live struct.
765///
766/// Exclusion of code becomes necessary when the user has already
767/// customized specific sections of the model.
768/// To facilitate the exclusion of parts from the generated
769/// model and enable printing them to the file for further
770/// user customization, consider the [`file`](#file) option,
771/// which works in conjunction with the `edit` option.
772///
773/// # file
774/// This argument is designed to address proc macro file blindness. It requires
775/// a string path to the current file as its value. Additionally, within the `edit` argument,
776/// one can use the keyword `file` to specify which portion of the excluded code should be written
777/// to the current module, providing the user with a starting point for customization.
778///
779///
780/// ## Examples
781///
782/// Filename: main.rs
783///
784///```rust no_run
785///pub struct MyActor(u8);
786///
787///#[interthread::actor(
788/// file="src/main.rs",
789/// edit(live(imp( file(increment) )))
790///)]
791///
792///impl MyActor {
793///
794/// pub fn new() -> Self {Self(0)}
795///
796/// pub fn increment(&mut self){
797/// self.0 += 1;
798/// }
799///}
800///```
801/// This is the output after saving:
802///
803/// ```rust no_run
804///
805///pub struct MyActor(u8);
806///
807///#[interthread::actor(
808/// file="src/main.rs",
809/// edit(live(imp(increment)))
810///)]
811///
812///impl MyActor {
813///
814/// pub fn new() -> Self {Self(0)}
815///
816/// pub fn increment(&mut self){
817/// self.0 += 1;
818/// }
819///}
820///
821/// //++++++++++++++++++[ Interthread Write to File ]+++++++++++++++++//
822/// // Object Name : MyActor
823/// // Initiated By : #[interthread::actor(file="src/main.rs",edit(live(imp(file(increment)))))]
824///
825///
826/// impl MyActorLive {
827/// pub fn increment(&mut self) {
828/// let msg = MyActorScript::Increment {};
829/// let _ = self
830/// .sender
831/// .send(msg)
832/// .expect("'MyActorLive::method.send'. Channel is closed!");
833/// }
834/// }
835///
836/// // *///.............[ Interthread End of Write ].................//
837///
838/// ```
839///
840/// To specify the part of your model that should be written to
841/// the file, simply enclose it within `file(..)` inside the `edit`
842/// argument. Once the desired model parts are written,
843/// the macro will automatically clean the `file` arguments,
844/// adjusting itself to the correct state.
845///
846///
847/// Attempting to nest `file` arguments like:
848/// ```rust no_run
849/// edit( file( script( file( def))))
850/// ```
851/// will result in an error.
852///
853///
854/// A special case of the `edit` and `file` conjunction,
855/// using `edit(file)` results in the macro being replaced with
856/// the generated code on the file.
857///
858///
859///
860/// > **Note:** While it is possible to have multiple actor macros
861/// within the same module, only one of the macro can have `file`
862/// active arguments (`file` within `edit`) at a time.
863///
864///
865/// # name
866///
867/// The `name` attribute allows developers to provide a
868/// custom name for `actor`, overriding the default
869/// naming conventions of the crate. This can be useful
870/// when there are naming conflicts or when a specific
871/// naming scheme is desired.
872///
873/// - "" (default): No name specified
874///
875/// ## Examples
876///```rust no_run
877///use interthread::actor;
878///
879///pub struct MyActor;
880///
881///#[actor(name="OtherActor")]
882///impl MyActor {
883///
884/// pub fn new() -> Self {Self}
885///}
886///fn main () {
887/// let other_act = OtherActorLive::new();
888///}
889///```
890///
891///
892/// # show
893///
894/// The `show` option is particularly useful for users who are just starting to
895/// work with this crate. When enabled, the model will generate doc comments
896/// for every block of code it produces, containing the code produce, with the
897/// exception of traits, which are simply listed.
898///
899/// Your text editor handles the rest.
900///
901/// By default, the model carries over the user's documentation comments from
902/// the actor object methods.
903/// Enabling `show` will add additional information, detailing the exact
904/// code generated by the model.
905/// Try hovering over `AaLive` and its `new` method to see the generated code.
906///
907/// ## Examples
908///```rust no_run
909///use interthread::actor;
910///pub struct Aa;
911///
912///#[actor(show)]
913///impl Aa {
914/// /// This is my comment
915/// /// Creates a new instance of AaLive.
916/// pub fn new() -> Self { Self{} }
917///
918///}
919///
920///fn main() {
921/// let bb = AaLive::new();
922///}
923///
924///```
925/// Disable `show` to avoid performance overhead and excessive code generation,
926/// when the option is no longer needed.
927///
928///
929/// # include-exclude
930/// The include and exclude options are mutually exclusive filters that control
931/// which methods are included in the generated model. Only one of these
932/// options can be used at a time.
933///
934/// Usage
935///
936/// - include: Specifies the methods to include in the generated model.
937/// - exclude: Specifies the methods to exclude from the generated model.
938///
939/// For a given list of actor's methods `[a, b, c, d]`:
940///
941/// - Using `include(a)` will generate a model that only includes the method `a`.
942/// - Using `exclude(a,b)` will generate a model that includes the methods `c`, and `d`.
943///
944/// ```rust no_run
945/// #[interthread::actor( exclude(foo,bar))]
946/// ```
947///
948/// # debut
949///
950/// The generated code is designed to
951/// compile successfully on Rust versions as early as 1.63.0.
952///
953/// When declared `debut`, the following additions and implementations
954/// are generated:
955///
956///
957/// Within the [`live`](index.html#live) struct definition, the following
958/// fields are generated:
959///
960/// - `pub debut: std::time::SystemTime`
961/// - `pub name: String`
962///
963/// The following traits are implemented for the [`live`](index.html#live) struct:
964///
965/// - `PartialEq`
966/// - `PartialOrd`
967/// - `Eq`
968/// - `Ord`
969///
970/// These traits allow for equality and ordering
971/// comparisons based on the `debut`value.
972/// The `name` field is provided for user needs only and is not
973/// taken into account when performing comparisons.
974/// It serves as a descriptive attribute or label
975/// associated with each instance of the live struct.
976///
977/// In the [`script`](index.html#script) struct implementation block, which
978/// encapsulates the functionality of the model,
979/// a static method named `debut` is generated. This
980/// method returns the current system time and is commonly
981/// used to set the `debut` field when initializing
982/// instances of the [`live`](index.html#live) struct.
983///
984///
985/// Use macro [`example`](./attr.example.html) to see the generated code.
986///
987///
988/// ## Examples
989///
990///```rust no_run
991///use std::thread::spawn;
992///pub struct MyActor ;
993///
994///#[interthread::actor( debut )]
995///impl MyActor {
996/// pub fn new() -> Self { Self{} }
997///}
998///fn main() {
999///
1000/// let actor_1 = MyActorLive::new();
1001///
1002/// let handle_2 = spawn( move || {
1003/// MyActorLive::new()
1004/// });
1005/// let actor_2 = handle_2.join().unwrap();
1006///
1007/// let handle_3 = spawn( move || {
1008/// MyActorLive::new()
1009/// });
1010/// let actor_3 = handle_3.join().unwrap();
1011///
1012/// // they are the same type objects
1013/// // but serving differrent threads
1014/// // different actors !
1015/// assert!(actor_1 != actor_2);
1016/// assert!(actor_2 != actor_3);
1017/// assert!(actor_3 != actor_1);
1018///
1019/// // since we know the order of invocation
1020/// // we correctly presume
1021/// assert_eq!(actor_1 > actor_2, true );
1022/// assert_eq!(actor_2 > actor_3, true );
1023/// assert_eq!(actor_3 < actor_1, true );
1024///
1025/// // but if we check the order by `debute` value
1026/// assert_eq!(actor_1.debut < actor_2.debut, true );
1027/// assert_eq!(actor_2.debut < actor_3.debut, true );
1028/// assert_eq!(actor_3.debut > actor_1.debut, true );
1029///
1030/// // This is because the 'debut'
1031/// // is a time record of initiation
1032/// // Charles S Chaplin (1889)
1033/// // Keanu Reeves (1964)
1034///
1035///
1036/// // we can count `live` instances for
1037/// // every model
1038/// use std::sync::Arc;
1039/// let mut a11 = actor_1.clone();
1040/// let mut a12 = actor_1.clone();
1041///
1042/// let mut a31 = actor_3.clone();
1043///
1044/// assert_eq!(Arc::strong_count(&actor_1.debut), 3 );
1045/// assert_eq!(Arc::strong_count(&actor_2.debut), 1 );
1046/// assert_eq!(Arc::strong_count(&actor_3.debut), 2 );
1047///
1048///
1049/// // or use getter `count`
1050/// assert_eq!(actor_1.inter_get_count(), 3 );
1051/// assert_eq!(actor_2.inter_get_count(), 1 );
1052/// assert_eq!(actor_3.inter_get_count(), 2 );
1053///
1054///
1055/// use std::time::SystemTime;
1056///
1057/// // getter `debut` to get its timestamp
1058/// let _debut1: SystemTime = actor_1.inter_get_debut();
1059///
1060///
1061/// // the name field is not taken
1062/// // into account when comparison is
1063/// // perfomed
1064/// assert!( a11 == a12);
1065/// assert!( a11 != a31);
1066///
1067/// a11.name = String::from("Alice");
1068/// a12.name = String::from("Bob");
1069///
1070/// a31.name = String::from("Alice");
1071///
1072/// assert_eq!(a11 == a12, true );
1073/// assert_eq!(a11 != a31, true );
1074///
1075/// // setter `name` accepts any ToString
1076/// a11.inter_set_name('t');
1077/// a12.inter_set_name(84u32);
1078/// a31.inter_set_name(3.14159);
1079///
1080/// // getter `name`
1081/// assert_eq!(a11.inter_get_name(), "t" );
1082/// assert_eq!(a12.inter_get_name(), "84" );
1083/// assert_eq!(a31.inter_get_name(), "3.14159" );
1084///
1085///}
1086///```
1087///
1088///
1089///
1090///
1091/// Using `debut` will generate fore additional
1092///methods in `live` implement block:
1093///
1094/// 1. `inter_set_name(s: ToString)`: Sets the value of the
1095/// name field.
1096/// 2. `inter_get_name() -> &str`: Retrieves the value of the
1097/// name field.
1098/// 3. `inter_get_debut() -> std::time::SystemTime`: Retrieves
1099/// the value of the debut field, which represents a timestamp.
1100/// 4. `inter_get_count() -> usize`: Provides the strong
1101/// reference count for the debut field.
1102///
1103///This convention allows
1104///- easy identification in text editor methods that
1105///solely manipulate the internal state of the live struct and/or
1106///methods that are added by the `interthread` macros
1107///- it mitigates the risk of potential naming conflicts in case if there
1108///is or will be a custom method `get_name`
1109///- helps the macro identify methods that are intended
1110///to be used within its context (see [`interact`](#interact))
1111///
1112/// # interact
1113///
1114/// The `interact` option is designed to provide the model with
1115/// comprehensive non-blocking functionality, along with convenient
1116/// internal getter calls to access the state of the `live` instance via
1117/// so called `inter variables` in actor methods.
1118///
1119/// ### Rules and Definitions
1120///
1121/// 1. The interact variables should be prefixed with `inter_`.
1122/// 2. Special interact variables are `inter_send` and `inter_recv`.
1123/// 3. Declaring an `inter_variable_name : Type`, within actor method
1124/// arguments implies that the `live` instance has a method
1125/// `fn inter_get_variable_name(&self) -> Type` which takes no arguments
1126/// and returns the `Type`. Exceptions to this rule apply for special
1127/// interact variables.
1128/// 4. If the actor method returns a type, accessing special interact variables
1129/// is not allowed.
1130/// 5. Only one end of special interact variables can be accessed at a time.
1131///
1132///
1133///
1134/// The primary purpose of `interact` is to leverage its oneshot `inter_send`
1135/// and `inter_recv` ends. This allows for
1136/// a form of non-blocking behavior: one end of the channel will be directly
1137/// sent into the respective method, while the other end will be returned
1138/// from the live instance method.
1139///
1140///
1141/// ## Examples
1142/// ```rust no_run
1143///
1144///pub struct MyActor;
1145///
1146///// opt `interact`
1147///#[interthread::actor( interact )]
1148///impl MyActor {
1149///
1150/// pub fn new() -> Self { Self{} }
1151///
1152/// // oneshot channel can be accessed
1153/// // in methods that do not return
1154/// pub fn heavy_work(&self, inter_send: oneshot::Sender<u8>){
1155///
1156/// std::thread::spawn(move||{
1157/// // do some havy computation
1158/// let _ = inter_send.send(5);
1159/// });
1160/// }
1161///}
1162///
1163///fn main () {
1164///
1165/// let actor = MyActorLive::new();
1166///
1167/// // the signature is different
1168/// let recv: oneshot::Receiver<u8> = actor.heavy_work();
1169/// let int = recv.recv().unwrap();
1170///
1171/// assert_eq!(5u8, int);
1172///}
1173///
1174/// ```
1175///
1176/// While a method that does not return a type (see original `heavy_work`)
1177/// typically does not require a oneshot channel, the
1178/// model will accommodate the user's request by instantiating
1179/// a channel pair.
1180///
1181///```rust no_run
1182///
1183///pub fn heavy_work(&self) -> oneshot::Receiver<u8> {
1184/// let (inter_send, inter_recv) = oneshot::channel::<u8>();
1185/// let msg = MyActorScript::HeavyWork {
1186/// input: (inter_send),
1187/// };
1188/// let _ = self
1189/// .sender
1190/// .send(msg)
1191/// .expect("'MyActorLive::method.send'. Channel is closed!");
1192/// inter_recv
1193///}
1194///```
1195///
1196///
1197/// Also `interact` will detect interact variables in actor methods
1198/// and subsequently call required getters within respective
1199/// method of the `live` instance.
1200///
1201/// ## Examples
1202/// ```rust no_run
1203/// pub struct MyActor(String);
1204///
1205/// #[interthread::actor(debut, interact )]
1206/// impl MyActor {
1207///
1208/// pub fn new() -> Self { Self("".to_string()) }
1209///
1210/// // We know there is a getter `inter_get_name`
1211/// // Using argument `inter_name` we imply
1212/// // we want the return type of that getter
1213/// pub fn set_value(&mut self, inter_name: String){
1214/// self.0 = inter_name;
1215/// }
1216/// pub fn get_value(&self) -> String {
1217/// self.0.clone()
1218/// }
1219/// }
1220///
1221/// fn main () {
1222///
1223/// let mut actor = MyActorLive::new();
1224///
1225/// // Setting name for `live` instance
1226/// actor.inter_set_name("cloud");
1227///
1228/// // Setting actor's value now
1229/// // Note the signature, it's not the same
1230/// actor.set_value();
1231///
1232/// assert_eq!("cloud".to_string(), actor.get_value());
1233/// }
1234/// ```
1235///
1236///
1237/// Here is how `live` instance method `set_value` will look like:
1238///
1239///
1240/// ```rust no_run
1241///
1242/// pub fn set_value(&mut self) {
1243/// let inter_name = self.inter_get_name();
1244/// let msg = MyActorScript::SetValue {
1245/// input: inter_name,
1246/// };
1247/// let _ = self
1248/// .sender
1249/// .send(msg)
1250/// .expect("'MyActorLive::method.send'. Channel is closed!");
1251/// }
1252///
1253/// ```
1254///
1255///
1256/// The signature has changed; it no longer takes arguments, as the
1257/// getter call is happening inside providing the required type.
1258/// It will work for any custom getter as long as it adheres to rule 3.
1259///
1260///
1261///
1262/// # Self Consuming Methods
1263///
1264/// For every method in an `Actor` object that consumes `Actor`, the model generates
1265/// a corresponding method in the `ActorLive` interface object that consumes both itself and the associated `Actor`.
1266///
1267/// However, this design introduces challenges. The model inherently allows
1268/// multiple `ActorLive` instances to send messages to a single `Actor` instance
1269/// running in a separate thread. When an `ActorLive` instance consumes itself and
1270/// its associated `Actor`, it effectively leaves other `ActorLive` instances without
1271/// a functional `Actor`, disrupting the model operation.
1272///
1273/// To safely implement such self-consuming methods, the following conditions must be met:
1274///
1275/// ### Safety Conditions for Self-Consuming Methods
1276///
1277/// 1. **Enable the `debut` Option**
1278/// The model must have the `debut` option enabled (e.g., ```interthread::actor(debut)```),
1279/// which allows it to track the number of active `ActorLive` instances.
1280///
1281/// 2. **Return a Valid Result Type**
1282/// Self-consuming methods must return one of the following types:
1283/// - `Option<T>`
1284/// - `Result<T, String>`
1285/// - `Result<T, &'static str>`
1286///
1287/// This requirement enables the model to inject a reference count check for `ActorLive`.
1288/// If there are multiple active `ActorLive` instances, the method will return `Option::None`
1289/// or `Result::Err`, indicating that the operation cannot proceed safely.
1290///
1291/// ### Limitations for Non-Compliant Methods
1292///
1293/// If a self-consuming method deviates from the above rules, the model enforces the following restrictions:
1294///
1295/// 1. **No Cloning**
1296/// The model will disallow the `Clone` trait for `ActorLive` object.
1297///
1298/// 2. **Private Visibility**
1299/// Self-consuming methods will be restricted to private visibility, making them inaccessible outside the module.
1300///
1301/// ## Examples
1302///
1303/// Some examples of compliant self-consuming methods:
1304///
1305/// ```rust no_run
1306/// pub fn method(self, args, ...) -> Option<T>;
1307///
1308/// pub fn method(self, args, ...) -> Result<T, String>;
1309///
1310/// pub fn method(self, args, ...) -> Result<T, &'static str>;
1311/// ```
1312///
1313/// These examples illustrate the required return types and demonstrate how
1314/// `self`-consuming methods can be safely integrated into the actor model.
1315
1316#[proc_macro_error::proc_macro_error]
1317#[proc_macro_attribute]
1318pub fn actor( attr: proc_macro::TokenStream, item: proc_macro::TokenStream ) -> proc_macro::TokenStream {
1319
1320 let item_impl = syn::parse_macro_input!(item as syn::ItemImpl);
1321
1322 let nested = syn::parse_macro_input!(attr with syn::punctuated::Punctuated::<syn::Meta,syn::Token![,]>::parse_terminated);
1323 let mut aaa = model::attribute::ActorAttributeArguments::from(nested, crate::model::Mac::Actor);
1324 aaa.cross_check();
1325
1326 check::channels_import( &aaa.lib );
1327
1328 let edit_attr = aaa.edit.attr.clone();
1329 let mut model_sdpl = crate::model::generate_model( aaa, &item_impl);
1330 let (code,edit_sdpl) = model_sdpl.get_code_edit();
1331 if let Some( edit_attr ) = edit_attr {
1332
1333 parse::edit_write( &edit_attr, &item_impl, edit_sdpl);
1334 }
1335
1336 quote::quote!{
1337 #item_impl
1338 #code
1339 }.into()
1340
1341}
1342
1343
1344
1345/// ## A Wrapper for Managing Parallel ActorLive Instances
1346///
1347/// The `family` macro is designed as a convenient wrapper for initializing a
1348/// set of `ActorLive` instances that operate in parallel, all serving the same Actor.
1349/// The core idea behind the `family` concept can be summarized as `Exclusive Access to the Actor`.
1350///
1351///
1352/// ## Configuration Options
1353/// The `family` macro provides the same configuration options as the `actor` macro,
1354/// ( with few exceptions ) and are inherited by `actor`'s declared within its body (e.g., `actor(first_name = "User", ...)`) which behaves exactly like the standalone `actor` macro. It allows defining individual `actor`s within the `family`.
1355///
1356/// Options not explicitly specified in the `actor` configuration will be inherited from the `family` macro. For example, if `channel` is defined in family but omitted in `actor`, the channel value from `family` will be applied to the `actor`.
1357///
1358/// If the same-named options are present in both `family` and `actor`, they are treated independently.
1359///
1360/// ```text
1361/// #[interthread::family(
1362///
1363/// ~ channel = 0 *
1364/// n (usize)
1365///
1366/// lib = std *
1367/// tokio
1368/// async_std
1369///
1370/// edit(
1371/// def,
1372/// imp(..),
1373/// trt(..),
1374/// )
1375///
1376/// Mutex | RwLock *
1377///
1378/// file = path/to/current/file.rs
1379///
1380/// name = ""
1381///
1382/// show
1383///
1384/// debut
1385///
1386/// actor(
1387/// first_name = ""
1388///
1389/// edit(
1390/// script(..)
1391/// live(..)
1392/// )
1393///
1394/// include|exclude
1395///
1396/// show
1397///
1398/// interact
1399/// )
1400///
1401/// )]
1402///
1403/// ~ - override
1404/// * - default
1405/// ```
1406///
1407/// Options marked with `~` in the schema are inherited by default but can be overridden in the `actor` configuration.
1408///
1409/// The original `actor`'s option `name` is different (`first_name` mandatory ) whereas `name` is
1410/// optional part of `family`. The naming convention for an object named Actor is:
1411/// - for family `Actor + Family` ( if not `name` specified )
1412/// - for actors `FirstName + Actor + Live|Script`
1413///
1414/// Consider the following example of a `family` macro:
1415/// ```text
1416/// #[interthread::family(
1417/// name = "MyActor",
1418/// Mutex,
1419/// edit(file),
1420/// lib,
1421/// channel,
1422/// debut,
1423///
1424/// actor(first_name = "User", include(foo)),
1425/// actor(first_name = "Admin", include(foo, bar)),
1426/// )]
1427///
1428/// ```
1429/// will generate types named:
1430///
1431/// ```rust no_run
1432///
1433/// struct MyActorFamily {
1434/// pub user: UserMyActorLive,
1435/// pub admin: AdminMyActorLive,
1436/// }
1437/// // the script parts
1438/// UserMyActorScript
1439/// AdminMyActorScript
1440///
1441/// ```
1442/// Behind the scenes, individual Actor Models are created for each member of the `family`,
1443/// sharing the same `Actor` object which is wrapped in either an `Arc<Mutex<Actor>>`
1444/// or an `Arc<RwLock<Actor>>`, depending on the specified lock type.
1445///
1446/// Within the `Script::direct` method, immediately after the `Script` variant match,
1447/// the `Actor` object is locked, and the corresponding method is invoked.
1448///
1449/// For developers seeking full control over the locking mechanism, the `family`
1450/// macro provides a convention for defining static methods with a specific receiver.
1451///
1452/// If a static method in the `Actor` implementation body uses a receiver
1453/// named `actor` and its type matches the shared model type (`Arc<Mutex<Actor>>` or `Arc<RwLock<Actor>>`),
1454/// the macro interprets this as a custom model method rather than a standard static method.
1455///
1456/// For example, consider the following method inside an Actor implementation:
1457/// ```rust no_run
1458/// impl Actor {
1459/// pub fn method(actor: &Arc<RwLock<Self>>, s: Type) -> Type {
1460/// let actor = actor.read().unwrap();
1461/// // Perform operations using the actor
1462/// }
1463/// }
1464/// ```
1465/// When processed by the macro, this method will be interpreted in `ActorLive` instance as:
1466///
1467/// ```rust no_run
1468/// impl ActorLive {
1469/// pub fn method(&self, s: Type) -> Type {
1470/// ...
1471/// }
1472/// }
1473/// ```
1474/// and processed correspondingly in `ActorScript`.
1475///
1476/// ### Supported Runtimes
1477/// The macro supports the following runtimes, each using its respective `Mutex` implementation:
1478///
1479///
1480/// | Runtime | Mutex | RwLock |
1481/// |:------------------------:|:----------:|:----------:|
1482/// | `std` (standard library) | `std::sync::Mutex`|`std::sync::RwLock` |
1483/// | `tokio` | `tokio::sync::Mutex`|`tokio::sync::RwLock` |
1484/// | `async-std` | `async_std::sync::Mutex`|`async_std::sync::RwLock` |
1485///
1486/// The `smol` runtime does not support the `family` macro.
1487
1488
1489#[proc_macro_error::proc_macro_error]
1490#[proc_macro_attribute]
1491pub fn family( attr: proc_macro::TokenStream, item: proc_macro::TokenStream ) -> proc_macro::TokenStream {
1492
1493 let item_impl = syn::parse_macro_input!(item as syn::ItemImpl);
1494
1495 let nested = syn::parse_macro_input!(attr with syn::punctuated::Punctuated::<syn::Meta,syn::Token![,]>::parse_terminated);
1496 let mut aaa = model::attribute::ActorAttributeArguments::from(nested, crate::model::Mac::Family);
1497 aaa.cross_check();
1498
1499 check::channels_import( &aaa.lib );
1500
1501 let edit_attr = aaa.edit.attr.clone();
1502 let mut model_sdpl = crate::model::generate_model( aaa, &item_impl);
1503 let (code,edit_sdpl) = model_sdpl.get_code_edit();
1504
1505 if let Some( edit_attr ) = edit_attr {
1506
1507 parse::edit_write( &edit_attr, &item_impl, edit_sdpl);
1508 }
1509
1510 quote::quote!{
1511 #item_impl
1512 #code
1513 }.into()
1514
1515}
1516
1517
1518
1519
1520
1521
1522
1523
1524