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