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