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