linked/
macros.rs

1// Copyright (c) Microsoft Corporation.
2// Copyright (c) Folo authors.
3
4/// Defines the template used to create every instance in a linked object family.
5///
6/// You are expected to use this in the constructor of a [linked object][crate],
7/// except when you want to always express the linked object via trait objects (`dyn Xyz`),
8/// in which case you should use [`linked::new_box`][crate::new_box].
9///
10/// The macro body must be a struct-expression of the `Self` type. Any variables the macro body
11/// captures must be thread-safe (`Send` + `Sync` + `'static`). The returned object itself does
12/// not need to be thread-safe.
13///
14/// # Example
15///
16/// ```
17/// use std::sync::{Arc, Mutex};
18///
19/// #[linked::object]
20/// struct TokenCache {
21///     tokens_created: usize,
22///     name: String,
23///     master_key: Arc<Mutex<String>>,
24///     is_multidimensional: bool,
25/// }
26///
27/// impl TokenCache {
28///     fn new(name: String, is_multidimensional: bool) -> Self {
29///         // Any shared data referenced by the macro body must be thread-safe.
30///         let master_key = Arc::new(Mutex::new(String::new()));
31///
32///         linked::new!(Self {
33///             tokens_created: 0,
34///             name: name.clone(),
35///             master_key: Arc::clone(&master_key),
36///             is_multidimensional,
37///         })
38///     }
39/// }
40/// ```
41///
42/// Complex expressions are supported within the `Self` struct-expression:
43///
44/// ```
45/// #[linked::object]
46/// struct TokenCache {
47///     token_sources: Vec<linked::Box<dyn TokenSource>>,
48/// }
49/// # trait TokenSource {}
50///
51/// impl TokenCache {
52///     fn new(source_families: Vec<linked::Family<linked::Box<dyn TokenSource>>>) -> Self {
53///         linked::new!(Self {
54///             token_sources: source_families
55///                 .iter()
56///                 .cloned()
57///                 .map(linked::Family::into)
58///                 .collect()
59///         })
60///     }
61/// }
62/// ```
63///
64/// For a complete example, see `examples/linked_basic.rs`.
65#[macro_export]
66macro_rules! new {
67    // `new!()` is forwarded to `new!(Self {})`
68    (Self) => {
69        $crate::new!(Self {})
70    };
71    // Special case if there are no field initializers (for proper comma handling).
72    (Self {}) => {
73        $crate::__private::new(move |__private_linked_link| Self {
74            __private_linked_link,
75        })
76    };
77    // Typical case - struct expression with zero or more field initializers.
78    // Each field initializer is processed as per the `@expand` rules below,
79    // which essentially does not touch/change them.
80    (Self { $($field:ident $( : $value:expr )?),* $(,)? }) => {
81        $crate::__private::new(move |__private_linked_link| Self {
82            $($field: $crate::new!(@expand $field $( : $value )?)),*,
83            __private_linked_link,
84        })
85    };
86    (@expand $field:ident : $value:expr) => {
87        $value
88    };
89    (@expand $field:ident) => {
90        $field
91    };
92}