linked/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Copyright (c) Folo authors.
3
4//! Mechanisms for creating families of linked objects that can collaborate across threads,
5//! with each instance only used from a single thread.
6//!
7//! The problem this crate solves is that while writing highly efficient lock-free thread-local
8//! code can yield great performance, it comes with serious drawbacks in terms of usability and
9//! developer experience.
10//!
11//! This crate bridges the gap by providing patterns and mechanisms that facilitate thread-local
12//! behavior while presenting a simple and reasonably ergonomic API to user code:
13//!
14//! * Internally, a linked object can take advantage of lock-free thread-isolated logic for **high
15//!   performance and efficiency** because it operates as a multithreaded family of thread-isolated
16//!   objects, each of which implements local behavior on a single thread.
17//! * Externally, the linked object family can look and act very much like a single Rust object and
18//!   can hide the fact that there is collaboration happening on multiple threads,
19//!   providing **a reasonably simple API with minimal extra complexity** for both the author
20//!   and the user of a type.
21#![ doc=mermaid!( "../doc/linked.mermaid") ]
22//!
23//! The patterns and mechanisms provided by this crate are designed to make it easy to create linked
24//! object families and to provide primitives that allow these object families to be used without
25//! the user code having to understand how the objects are wired up inside or keeping track of which
26//! instance is meant to be used on which thread.
27//!
28//! This is part of the [Folo project](https://github.com/folo-rs/folo) that provides mechanisms for
29//! high-performance hardware-aware programming in Rust.
30//!
31//! # What is a linked object?
32//!
33//! Linked objects defined by types decorated with `#[linked::object]` whose instances:
34//!
35//! 1. take advantage of thread-specific state by being functionally single-threaded
36//!    (see also, [linked objects on multiple threads][multiple-threads]);
37//! 1. and are internally connected to other instances from the same family;
38//! 1. and share some state between instances in the same family, e.g. via messaging or synchronized
39//!    storage;
40//! 1. and perform all collaboration between instances in the same family without involvement of
41//!    user code (i.e. there is no `Arc` or `Mutex` that the user needs to create/operate).
42//!
43//! In most cases, as long as user code executes thread-local logic, user code can treat linked
44//! objects like any other Rust structs. The mechanisms only have an effect when
45//! [instances on multiple threads need to collaborate][multiple-threads].
46//!
47//! Despite instances of linked objects being designed for thread-local use, there may
48//! still exist multiple instances per thread in the same family because this is meaningful for
49//! some types. For example, think of messaging channels - multiple receivers should be independent,
50//! even on the same thread, even if part of the same channel.
51//!
52//! The primary mechanisms this crate provides to create instances of linked objects are:
53//!
54//! * [`linked::instances!` macro][1];
55//! * [`linked::Family<T>`][11]
56//!
57//! The above will create instances on demand, including creating multiple instances on the same
58//! thread if asked to.
59//!
60//! You can explicitly opt-in to "one per thread" behavior via these additional mechanisms:
61//!
62//! * [`linked::thread_local_rc!` macro][2]
63//! * [`linked::thread_local_arc!` macro][8] (if `T: Sync`)
64//! * [`linked::InstancePerThread<T>`][3].
65//! * [`linked::InstancePerThreadSync<T>`][9] (if `T: Sync`)
66//!
67//! # What is a family of linked objects?
68//!
69//! A family of linked objects is the unit of collaboration between instances. Each instance in a
70//! family can communicate with all other instances in the same family through shared state or other
71//! synchronization mechanisms. They act as a single distributed object, exhibiting thread-local
72//! behavior by default and internally triggering global behavior as needed.
73//!
74//! Instances are defined as belonging to the same family if they:
75//!
76//! - are created via cloning;
77//! - or are obtained from the same static variable in a [`linked::instances!`][1],
78//!   [`linked::thread_local_rc!`][2] or [`linked::thread_local_arc!`][8] macro block;
79//! - or are created from the same [`linked::InstancePerThread<T>`][3] or one of its clones;
80//! - or are created from the same [`linked::InstancePerThreadSync<T>`][9] or one of its clones;
81//! - or are created directly from a [`linked::Family<T>`][11].
82//!
83//! # Using and defining linked objects
84//!
85//! A very basic and contrived example is a `Thing` that shares a `value` between all its instances.
86//!
87//! This object can generally be used like any other Rust type. All linked objects support cloning,
88//! since that is one of the primary mechanisms for creating additional linked instances.
89//!
90//! ```rust
91//! # use std::sync::{Arc, Mutex};
92//! # #[linked::object]
93//! # struct Thing {
94//! #     value: Arc<Mutex<String>>,
95//! # }
96//! # impl Thing {
97//! #     pub fn new(initial_value: String) -> Self {
98//! #         let shared_value = Arc::new(Mutex::new(initial_value));
99//! #         linked::new!(Self {
100//! #             value: shared_value.clone(),
101//! #         })
102//! #     }
103//! #     pub fn value(&self) -> String {
104//! #         self.value.lock().unwrap().clone()
105//! #     }
106//! #     pub fn set_value(&self, value: String) {
107//! #         *self.value.lock().unwrap() = value;
108//! #     }
109//! # }
110//! // These instances are part of the same family due to cloning.
111//! let thing1 = Thing::new("hello".to_string());
112//! let thing2 = thing1.clone();
113//!
114//! assert_eq!(thing1.value(), "hello");
115//! assert_eq!(thing2.value(), "hello");
116//!
117//! thing1.set_value("world".to_string());
118//!
119//! // The value is shared between instances in the same family.
120//! assert_eq!(thing1.value(), "world");
121//! assert_eq!(thing2.value(), "world");
122//! ```
123//!
124//! We can compare this example to the linked object definition above:
125//!
126//! * The relation between instances is established via cloning.
127//! * The `value` is shared.
128//! * Implementing the collaboration between instances does not require anything from user code
129//!   (e.g. there is no `Mutex` or `mpsc::channel` that had to be written here).
130//!
131//! The implementation of this type is the following:
132//!
133//! ```rust
134//! use std::sync::{Arc, Mutex};
135//!
136//! #[linked::object]
137//! pub struct Thing {
138//!     value: Arc<Mutex<String>>,
139//! }
140//!
141//! impl Thing {
142//!     pub fn new(initial_value: String) -> Self {
143//!         let shared_value = Arc::new(Mutex::new(initial_value));
144//!
145//!         linked::new!(Self {
146//!             // Capture `shared_value` to reuse it for all instances in the family.
147//!             value: Arc::clone(&shared_value),
148//!         })
149//!     }
150//!
151//!     pub fn value(&self) -> String {
152//!         self.value.lock().unwrap().clone()
153//!     }
154//!
155//!     pub fn set_value(&self, value: String) {
156//!         *self.value.lock().unwrap() = value;
157//!     }
158//! }
159//! ```
160//!
161//! As this is a contrived example, this type is not very useful because it does not have
162//! any high-efficiency thread-local logic that would benefit from the linked object patterns.
163//! See the [Implementing local behavior][local-behavior] section for details on thread-local logic.
164//!
165//! The implementation steps to apply the pattern to a struct are:
166//!
167//! * Add [`#[linked::object]`][crate::object] to the struct. This will automatically
168//!   derive the `linked::Object` and `Clone` traits and implement various other behind-the-scenes
169//!   mechanisms required for the linked object pattern to operate.
170//! * In the constructor, call [`linked::new!`][crate::new] to create the first instance.
171//!
172//! [`linked::new!`][crate::new] is a wrapper around a `Self` struct-expression. What makes
173//! it special is that **this struct-expression will be called for every instance that is ever
174//! created in the same family of linked objects**. This expression captures the state of the
175//! constructor (e.g. in the above example, it captures `shared_value`). Use the captured
176//! state to set up any shared connections between instances in the same family (e.g. by sharing
177//! an `Arc` or connecting message channels).
178//!
179//! The captured values must be thread-safe (`Send` + `Sync` + `'static`), while the `Thing`
180//! struct itself does not need to be thread-safe. See the next chapter to understand how to
181//! implement multithreaded logic.
182//!
183//! # Linked objects on multiple threads
184//! [multiple-threads]: #multiple-threads
185//!
186//! Each instance of a linked object is expected to be optimized for thread-local logic. The purpose
187//! of this pattern is to encourage highly efficient local operation while still presenting an easy
188//! to use API to both the author and the user of the type.
189//!
190//! A single-threaded type is generally `!Send` and `!Sync`, which means it cannot be sent between
191//! threads or used from other threads. Therefore, you cannot in the general case just clone an
192//! instance to share it with a different thread. This poses an obvious question: how can we then
193//! create different instances from the same family for different threads?
194//!
195//! This crate provides several mechanisms for this:
196//!
197//! * [`linked::instances!`][1] will enrich static variables with linked object powers - you can
198//!   use a static variable to get linked instances from the same object family;
199//! * [`linked::thread_local_rc!`][2] takes it one step further and manages the bookkeeping necessary
200//!   to only maintain one instance per thread, which you can access either via `&T` shared
201//!   reference or obtain an `Rc<T>` to;
202//! * [`linked::thread_local_arc!`][8] also manages one instance per thread but is designed for
203//!   types where `T: Sync` and allows you to obtain an `Arc<T>`;
204//! * [`linked::InstancePerThread<T>`][3] is roughly equivalent to `thread_local_rc!` but does
205//!   not require you to define a static variable; this is useful when you do not know at compile
206//!   time how many object families you need to create;
207//! * [`linked::InstancePerThreadSync<T>`][9] is the same but equivalent to `thread_local_arc!`
208//!   and requires `T: Sync`;
209//! * [`linked::Family<T>`][11] is the lowest level primitive, being a handle to the object family
210//!   that can be used to create new instances on demand using custom logic.
211//!
212//! Example of using a static variable to link instances on different threads:
213//!
214//! ```rust
215//! # use std::sync::{Arc, Mutex};
216//! # #[linked::object]
217//! # struct Thing {
218//! #     value: Arc<Mutex<String>>,
219//! # }
220//! # impl Thing {
221//! #     pub fn new(initial_value: String) -> Self {
222//! #         let shared_value = Arc::new(Mutex::new(initial_value));
223//! #         linked::new!(Self {
224//! #             value: shared_value.clone(),
225//! #         })
226//! #     }
227//! #     pub fn value(&self) -> String {
228//! #         self.value.lock().unwrap().clone()
229//! #     }
230//! #     pub fn set_value(&self, value: String) {
231//! #         *self.value.lock().unwrap() = value;
232//! #     }
233//! # }
234//! use std::thread;
235//!
236//! linked::instances!(static THE_THING: Thing = Thing::new("hello".to_string()));
237//!
238//! let thing = THE_THING.get();
239//! assert_eq!(thing.value(), "hello");
240//!
241//! thing.set_value("world".to_string());
242//!
243//! thread::spawn(|| {
244//!     let thing = THE_THING.get();
245//!     assert_eq!(thing.value(), "world");
246//! }).join().unwrap();
247//! ```
248//!
249//! Example of using a [`InstancePerThread<T>`][3] to dynamically define an object family and
250//! create thread-local instances on different threads:
251//!
252//! ```rust
253//! # use std::sync::{Arc, Mutex};
254//! # #[linked::object]
255//! # struct Thing {
256//! #     value: Arc<Mutex<String>>,
257//! # }
258//! # impl Thing {
259//! #     pub fn new(initial_value: String) -> Self {
260//! #         let shared_value = Arc::new(Mutex::new(initial_value));
261//! #         linked::new!(Self {
262//! #             value: shared_value.clone(),
263//! #         })
264//! #     }
265//! #     pub fn value(&self) -> String {
266//! #         self.value.lock().unwrap().clone()
267//! #     }
268//! #     pub fn set_value(&self, value: String) {
269//! #         *self.value.lock().unwrap() = value;
270//! #     }
271//! # }
272//! use std::thread;
273//!
274//! use linked::InstancePerThread;
275//!
276//! let linked_thing = InstancePerThread::new(Thing::new("hello".to_string()));
277//!
278//! // Obtain a local instance on demand.
279//! let thing = linked_thing.acquire();
280//! assert_eq!(thing.value(), "hello");
281//!
282//! thing.set_value("world".to_string());
283//!
284//! thread::spawn({
285//!     // The new thread gets its own clone of the InstancePerThread<T>.
286//!     let linked_thing = linked_thing.clone();
287//!
288//!     move || {
289//!         let thing = linked_thing.acquire();
290//!         assert_eq!(thing.value(), "world");
291//!     }
292//! })
293//! .join()
294//! .unwrap();
295//! ```
296//!
297//! Example of using a [`linked::Family`][11] to manually create an instance on a different thread:
298//!
299//! ```rust
300//! # use std::sync::{Arc, Mutex};
301//! # #[linked::object]
302//! # struct Thing {
303//! #     value: Arc<Mutex<String>>,
304//! # }
305//! # impl Thing {
306//! #     pub fn new(initial_value: String) -> Self {
307//! #         let shared_value = Arc::new(Mutex::new(initial_value));
308//! #         linked::new!(Self {
309//! #             value: shared_value.clone(),
310//! #         })
311//! #     }
312//! #     pub fn value(&self) -> String {
313//! #         self.value.lock().unwrap().clone()
314//! #     }
315//! #     pub fn set_value(&self, value: String) {
316//! #         *self.value.lock().unwrap() = value;
317//! #     }
318//! # }
319//! use std::thread;
320//!
321//! use linked::Object; // This brings .family() into scope.
322//!
323//! let thing = Thing::new("hello".to_string());
324//! assert_eq!(thing.value(), "hello");
325//!
326//! thing.set_value("world".to_string());
327//!
328//! thread::spawn({
329//!     // You can get the object family from any instance.
330//!     let thing_family = thing.family();
331//!
332//!     move || {
333//!         // Use .into() to convert the family reference into a new instance.
334//!         let thing: Thing = thing_family.into();
335//!         assert_eq!(thing.value(), "world");
336//!     }
337//! })
338//! .join()
339//! .unwrap();
340//! ```
341//!
342//! # Implementing local behavior
343//! [local-behavior]: #local-behavior
344//!
345//! The linked object pattern does not change the fact that synchronized state is expensive.
346//! Whenever possible, linked objects should operate on local state for optimal efficiency.
347//!
348//! Let's extend `Thing` from above with a local counter that counts the number of times the value
349//! has been modified via the current instance. This is local behavior that does not require any
350//! synchronization with other instances.
351//!
352//! ```rust
353//! use std::sync::{Arc, Mutex};
354//!
355//! #[linked::object]
356//! pub struct Thing {
357//!     // Shared state - synchronized with other instances in the family.
358//!     value: Arc<Mutex<String>>,
359//!
360//!     // Local state - not synchronized with other instances in the family.
361//!     update_count: usize,
362//! }
363//!
364//! impl Thing {
365//!     pub fn new(initial_value: String) -> Self {
366//!         let shared_value = Arc::new(Mutex::new(initial_value));
367//!
368//!         linked::new!(Self {
369//!             // Capture `shared_value` to reuse it for all instances in the family.
370//!             value: Arc::clone(&shared_value),
371//!
372//!             // Local state is simply initialized to 0 for every instance.
373//!             update_count: 0,
374//!         })
375//!     }
376//!
377//!     pub fn value(&self) -> String {
378//!         self.value.lock().unwrap().clone()
379//!     }
380//!
381//!     pub fn set_value(&mut self, value: String) {
382//!         *self.value.lock().unwrap() = value;
383//!         self.update_count += 1;
384//!     }
385//!
386//!     pub fn update_count(&self) -> usize {
387//!         self.update_count
388//!     }
389//! }
390//! ```
391//!
392//! **Local behavior consists of simply operating on regular non-synchronized fields of the struct.**
393//!
394//! The above implementation works well with some of the linked object mechanisms provided by this
395//! crate, such as [`linked::instances!`][1] and [`linked::Family<T>`][11].
396//!
397//! However, the above implementation does not work with instance-per-thread mechanisms like
398//! [`linked::thread_local_rc!`][2] because these mechanisms share one instance between many
399//! callers on the same thread. This makes it impossible to obtain an exclusive `&mut self`
400//! reference (as required by `set_value()`) because exclusive access cannot be guaranteed.
401//!
402//! Types designed to be used via instance-per-thread mechanisms cannot modify the local
403//! state directly but must instead use interior mutability (e.g. [`Cell`][6] or [`RefCell`][7]).
404//!
405//! Example of the same type using [`Cell`][6] to support thread-local behavior without `&mut self`:
406//!
407//! ```rust
408//! use std::cell::Cell;
409//! use std::sync::{Arc, Mutex};
410//!
411//! #[linked::object]
412//! pub struct Thing {
413//!     // Shared state - synchronized with other instances in the family.
414//!     value: Arc<Mutex<String>>,
415//!
416//!     // Local state - not synchronized with other instances in the family.
417//!     update_count: Cell<usize>,
418//! }
419//!
420//! impl Thing {
421//!     pub fn new(initial_value: String) -> Self {
422//!         let shared_value = Arc::new(Mutex::new(initial_value));
423//!
424//!         linked::new!(Self {
425//!             // Capture `shared_value` to reuse it for all instances in the family.
426//!             value: Arc::clone(&shared_value),
427//!
428//!             // Local state is simply initialized to 0 for every instance.
429//!             update_count: Cell::new(0),
430//!         })
431//!     }
432//!
433//!     pub fn value(&self) -> String {
434//!         self.value.lock().unwrap().clone()
435//!     }
436//!
437//!     pub fn set_value(&self, value: String) {
438//!         *self.value.lock().unwrap() = value;
439//!         self.update_count.set(self.update_count.get() + 1);
440//!     }
441//!
442//!     pub fn update_count(&self) -> usize {
443//!         self.update_count.get()
444//!     }
445//! }
446//! ```
447//!
448//! # You may still need `Send` when thread-isolated
449//!
450//! There are some practical considerations that mean you often want your linked objects
451//! to be `Send` and `Sync`, just like traditional thread-safe objects are.
452//!
453//! This may be surprising - after all, the whole point of this crate is to enable thread-local
454//! behavior, which does not require `Send` or `Sync`.
455//!
456//! The primary reason is that **many APIs in the Rust crate ecosystem require `Send` from types,
457//! even in scenarios where the object is only accessed from a single thread**. This is because
458//! [the language lacks the flexibility necessary to create APIs that support both `Send` and
459//! `!Send` types][12], so many API authors simply require `Send` from all types.
460//!
461//! Implementing `Send` is therefore desirable for practical API compatibility reasons, even if the
462//! type is never sent across threads.
463//!
464//! The main impact of this is that you want to avoid fields that are `!Send` in your linked
465//! object types (e.g. the most common such type being `Rc`).
466//!
467//! # You may still need `Sync` when thread-isolated
468//!
469//! It is not only instances of linked objects themselves that may need to be passed around
470//! to 3rd party APIs that require `Send` - you may also want to pass long-lived references to
471//! the instance-per-thread linked objects (or references to your own structs that contain such
472//! references). This can be common, e.g. when passing futures to async task runtimes, with
473//! these references/types being stored as part of the future's async state machine.
474//!
475//! All linked object types support instance-per-thread behavior via [`linked::thread_local_rc!`][2]
476//! and [`linked::InstancePerThread<T>`][3] but these give you `Rc<T>` and [`linked::Ref<T>`][12],
477//! which are `!Send`. That will not work with many 3rd party APIs!
478//!
479//! Instead, you want to use [`linked::thread_local_arc!`][8] or
480//! [`linked::InstancePerThreadSync<T>`][9], which give you `Arc<T>` and [`linked::RefSync<T>`][14],
481//! which are both `Send`. This ensures compatibility with 3rd party APIs.
482//!
483//! Use of these two mechanisms requires `T: Sync`, however!
484//!
485//! Therefore, for optimal compatibility with 3rd party APIs, you will often want to design your
486//! linked object types to be both `Send` and `Sync`, even if each instance is only used from a
487//! single thread.
488//!
489//! Example extending the above example using [`AtomicUsize`][10] to become `Sync`:
490//!
491//! ```rust
492//! use std::sync::atomic::{self, AtomicUsize};
493//! use std::sync::{Arc, Mutex};
494//!
495//! #[linked::object]
496//! pub struct Thing {
497//!     // Shared state - synchronized with other instances in the family.
498//!     value: Arc<Mutex<String>>,
499//!
500//!     // Local state - not synchronized with other instances in the family.
501//!     update_count: AtomicUsize,
502//! }
503//!
504//! impl Thing {
505//!     pub fn new(initial_value: String) -> Self {
506//!         let shared_value = Arc::new(Mutex::new(initial_value));
507//!
508//!         linked::new!(Self {
509//!             // Capture `shared_value` to reuse it for all instances in the family.
510//!             value: Arc::clone(&shared_value),
511//!
512//!             // Local state is simply initialized to 0 for every instance.
513//!             update_count: AtomicUsize::new(0),
514//!         })
515//!     }
516//!
517//!     pub fn value(&self) -> String {
518//!         self.value.lock().unwrap().clone()
519//!     }
520//!
521//!     pub fn set_value(&self, value: String) {
522//!         *self.value.lock().unwrap() = value;
523//!         self.update_count.fetch_add(1, atomic::Ordering::Relaxed);
524//!     }
525//!
526//!     pub fn update_count(&self) -> usize {
527//!         self.update_count.load(atomic::Ordering::Relaxed)
528//!     }
529//! }
530//! ```
531//!
532//! This has some nonzero overhead, so avoiding it is still desirable if you are operating in a
533//! situation where 3rd party APIs do not require `Send` from your types. However, it is still
534//! much more efficient than traditional thread-safe types because while it uses thread-safe
535//! primitives like atomics, these are only ever accessed from a single thread, which is very fast.
536//!
537//! The underlying assumption of the performance claims is that you do not actually share a single
538//! thread's instance with other threads, of course.
539//!
540//! # Using linked objects via abstractions
541//!
542//! You may find yourself in a situation where you need to use a linked object type `T` through
543//! a trait object of a trait `Xyz`, where `T: Xyz`. That is, you may want to use your `T` as a
544//! `dyn Xyz`. This is a common pattern in Rust but with the linked objects pattern there is
545//! a choice you must make:
546//!
547//! * If the linked objects are **always** to be accessed via trait objects (`dyn Xyz`), wrap
548//!   the `dyn Xyz` instances in [`linked::Box`], returning such a box already in the constructor.
549//! * If the linked objects are **sometimes** to be accessed via trait objects, you can on-demand
550//!   wrap them into a [`std::boxed::Box<dyn Xyz>`][5].
551//!
552//! The difference is that [`linked::Box`] preserves the linked object functionality even for the
553//! `dyn Xyz` form - you can clone the box, obtain a [`Family<linked::Box<dyn Xyz>>`][Family] to
554//! extend the object family to another thread and store such a box in a static variable in a
555//! [`linked::instances!`][1] or [`linked::thread_local_rc!`][2] block or a
556//! [`linked::InstancePerThread<T>`][3] for automatic instance management.
557//!
558//! In contrast, when you use a [`std::boxed::Box<dyn Xyz>`][5], you lose the linked
559//! object functionality (but only for the instance that you put in the box). Internally, the boxed
560//! instance keeps working as it always did but you cannot use the linked object API on it, such
561//! as obtaining a handle.
562//!
563//! Example of using a linked object via a trait object using [`linked::Box`], for scenarios
564//! where the linked object is always accessed via a trait object:
565//!
566//! ```rust
567//! # trait ConfigSource {}
568//! # impl ConfigSource for XmlConfig {}
569//! // If using linked::Box, do not put `#[linked::object]` on the struct.
570//! // The linked::Box itself is the linked object and our struct is only its contents.
571//! struct XmlConfig {
572//!     config: String,
573//! }
574//!
575//! impl XmlConfig {
576//!     pub fn new_as_config_source() -> linked::Box<dyn ConfigSource> {
577//!         // Constructing instances works logically the same as for regular linked objects.
578//!         //
579//!         // The only differences are:
580//!         // 1. We use `linked::new_box!` instead of `linked::new!`
581//!         // 2. There is an additional parameter to the macro to name the trait object type.
582//!         linked::new_box!(
583//!             dyn ConfigSource,
584//!             Self {
585//!                 config: "xml".to_string(),
586//!             }
587//!         )
588//!     }
589//! }
590//! ```
591//!
592//! Example of using a linked object via a trait object using [`std::boxed::Box<dyn Xyz>`][5],
593//! for scenarios where the linked object is only sometimes accessed via a trait object:
594//!
595//! ```rust
596//! # trait ConfigSource {}
597//! # impl ConfigSource for XmlConfig {}
598//! #[linked::object]
599//! struct XmlConfig {
600//!     config: String,
601//! }
602//!
603//! impl XmlConfig {
604//!     // XmlConfig itself is a regular linked object, nothing special about it.
605//!     pub fn new() -> XmlConfig {
606//!         linked::new!(Self {
607//!             config: "xml".to_string(),
608//!         })
609//!     }
610//!
611//!     // When the caller wants a `dyn ConfigSource`, we can convert this specific instance into
612//!     // one. The trait object loses its linked objects API surface (though remains part of the
613//!     // family).
614//!     pub fn into_config_source(self) -> Box<dyn ConfigSource> {
615//!         Box::new(self)
616//!     }
617//! }
618//! ```
619//!
620//! # Additional examples
621//!
622//! See `examples/linked_*.rs` for more examples of using linked objects in different scenarios.
623//!
624//! [1]: crate::instances
625//! [2]: crate::thread_local_rc
626//! [3]: crate::InstancePerThread
627//! [4]: https://doc.rust-lang.org/nomicon/send-and-sync.html
628//! [5]: std::boxed::Box
629//! [6]: std::cell::Cell
630//! [7]: std::cell::RefCell
631//! [8]: crate::thread_local_arc
632//! [9]: crate::InstancePerThreadSync
633//! [10]: std::sync::atomic::AtomicUsize
634//! [11]: crate::Family
635//! [12]: https://github.com/rust-lang/rfcs/issues/2190
636//! [13]: crate::Ref
637//! [14]: crate::RefSync
638
639use simple_mermaid::mermaid;
640
641#[doc(hidden)]
642pub mod __private;
643
644mod r#box;
645mod constants;
646mod family;
647mod instance_per_thread;
648mod instance_per_thread_sync;
649mod object;
650mod static_instance_per_thread;
651mod static_instance_per_thread_sync;
652mod static_instances;
653mod thread_id_hash;
654
655pub use r#box::*;
656pub(crate) use constants::*;
657pub use family::*;
658pub use instance_per_thread::*;
659pub use instance_per_thread_sync::*;
660pub use object::*;
661pub use static_instance_per_thread::*;
662pub use static_instance_per_thread_sync::*;
663pub use static_instances::*;
664pub(crate) use thread_id_hash::*;
665
666mod macros;
667
668/// Marks a struct as implementing the [linked object pattern][crate].
669///
670/// See crate-level documentation for a high-level guide.
671///
672/// # Usage
673///
674/// Apply the attribute on a struct block. Then, in constructors, use the
675/// [`linked::new!`][crate::new] macro to create an instance of the struct.
676///
677/// # Example
678///
679/// ```
680/// #[linked::object]
681/// pub struct TokenCache {
682///     some_value: usize,
683/// }
684///
685/// impl TokenCache {
686///     pub fn new(some_value: usize) -> Self {
687///         linked::new!(Self { some_value })
688///     }
689/// }
690/// ```
691///
692/// # Effects
693///
694/// Applying this macro has the following effects:
695///
696/// 1. Generates the necessary wiring to support calling `linked::new!` in constructors to create
697///    instances. This macro disables regular `Self {}` struct-expressions and requires the use
698///    of `linked::new!`.
699/// 2. Implements `Clone` for the struct. All linked objects can be cloned to create new
700///    instances linked to the same family.
701/// 3. Implements the trait [`linked::Object`] for the struct, enabling standard linked object
702///    pattern mechanisms such as calling `.family()` on instances to access the [`Family`].
703/// 4. Implements `From<linked::Family<T>>` for the struct. This allows converting a [`Family`]
704///    into an instance of the linked object using `.into()`.
705///
706/// # Constraints
707///
708/// Only structs defined in the named fields form are supported (no tuple structs).
709pub use linked_macros::__macro_linked_object as object;
710
711// This is so procedural macros can produce code which refers to
712// ::linked::* which will work also in the current crate.
713#[doc(hidden)]
714extern crate self as linked;