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}