Skip to main content

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;