linked/
__private.rs

1// Copyright (c) Microsoft Corporation.
2// Copyright (c) Folo authors.
3
4//! This module contains logically private things that must be technically public
5//! because they are accessed from macro-generated code.
6
7use std::fmt::{self, Debug, Formatter};
8use std::sync::Arc;
9
10use negative_impl::negative_impl;
11
12use crate::{Handle, Object};
13
14/// Re-export so we can use it via macros in projects that do not have a reference to `paste`.
15pub use ::paste::paste;
16
17/// This is meant to be used via the [`linked::new!`][crate::new] macro, never directly called.
18///
19/// Creates a family of linked objects, the instances for which are created using a callback whose
20/// captured state connects all members of the linked object family.
21///
22/// The instance factory must be thread-safe, which implies that all captured state in this factory
23/// function must be `Send` + `Sync` + `'static`. The instances it returns do not need to be thread-
24/// safe, however.
25#[inline]
26pub fn new<T>(instance_factory: impl Fn(Link<T>) -> T + Send + Sync + 'static) -> T {
27    Link::new(Arc::new(instance_factory)).into_instance()
28}
29
30/// This is meant to be used via the `#[linked::object]` macro, never directly called.
31///
32/// Clones a linked object. They require a specific pattern to clone, so the `#[linked::object]`
33/// macro wires up a suitable `Clone` implementation for all such types to avoid mistakes.
34#[inline]
35pub fn clone<T>(value: &T) -> T
36where
37    T: Object + From<Handle<T>>,
38{
39    value.handle().into()
40}
41
42pub(crate) type InstanceFactory<T> = Arc<dyn Fn(Link<T>) -> T + Send + Sync + 'static>;
43
44/// An object that connects an instance to other instances in the same linked object family.
45///
46/// This type serves the linked object infrastructure and is not meant to be used by user code.
47/// It is a private public type because it is used in macro-generated code.
48pub struct Link<T> {
49    pub(super) instance_factory: InstanceFactory<T>,
50}
51
52impl<T> Debug for Link<T> {
53    #[cfg_attr(test, mutants::skip)] // We have no API contract for this.
54    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
55        f.debug_struct("Link")
56            .field(
57                "instance_factory",
58                &format_args!(
59                    "Arc<dyn Fn(Link<{t}>) -> {t}>",
60                    t = std::any::type_name::<T>()
61                ),
62            )
63            .finish()
64    }
65}
66
67// A `Link` is a single-threaded object to avoid accidentally passing a linked object across
68// threads. Instead, use `Handle` (from `Linked::handle()`) to send instances across threads.
69#[negative_impl]
70impl<T> !Send for Link<T> {}
71#[negative_impl]
72impl<T> !Sync for Link<T> {}
73
74impl<T> Link<T> {
75    #[must_use]
76    pub(super) fn new(instance_factory: InstanceFactory<T>) -> Self {
77        Self { instance_factory }
78    }
79
80    #[must_use]
81    pub(super) fn into_instance(self) -> T {
82        let instance_factory = Arc::clone(&self.instance_factory);
83        (instance_factory)(self)
84    }
85
86    // This type deliberately does not implement `Clone` to discourage accidental implementation of
87    // cloning of type `T` via `#[derive(Clone)]`. The expected pattern is to use `#[linked::object]`
88    // which generates both a `Linked` implementation and a specialized `Clone` implementation.
89    #[must_use]
90    fn clone(&self) -> Self {
91        Self {
92            instance_factory: Arc::clone(&self.instance_factory),
93        }
94    }
95
96    #[inline]
97    #[must_use]
98    pub fn handle(&self) -> Handle<T> {
99        Handle::new(self.clone())
100    }
101}