Skip to main content

doublets/decorators/
builder.rs

1//! The builder that composes decorators into a single concrete type.
2
3use std::io::Write;
4
5use data::LinkReference;
6
7use super::{
8    policy::{UniquenessPolicy, UsagesPolicy},
9    CascadeUniquenessAndUsagesResolver, CascadeUsagesResolver, InnerReferenceExistenceValidator,
10    ItselfConstantToSelfReferenceResolver, LoggingDecorator, NoExceptionsDecorator,
11    NonExistentDependenciesCreator, NonNullContentsLinkDeletionResolver,
12    NullConstantToSelfReferenceResolver, TransactionsDecorator, TransitionLog, UsagesValidator,
13};
14use crate::Doublets;
15
16/// The stack C# `ILinksExtensions.DecorateWithAutomaticUniquenessAndUsagesResolution`
17/// builds, spelled as a type.
18pub type AutomaticUniquenessAndUsagesResolution<T, L> = CascadeUniquenessAndUsagesResolver<
19    T,
20    NonNullContentsLinkDeletionResolver<T, CascadeUsagesResolver<T, L>>,
21>;
22
23/// Composes decorators around a store.
24///
25/// Every method takes the store by value and returns the *concrete* composed type, so a
26/// stack is built at compile time and every layer is a candidate for inlining:
27///
28/// ```rust
29/// use doublets::{decorators::{DecoratorsExt, Resolve}, mem, unit, Doublets};
30///
31/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
32/// let mut store = unit::Store::<usize, _>::new(mem::Global::new())?
33///     .with_uniqueness(Resolve)
34///     .with_usages_validation();
35///
36/// let a = store.create_point()?;
37/// let b = store.create_point()?;
38/// // The second `create_link` reuses the first one instead of storing a duplicate.
39/// assert_eq!(store.create_link(a, b)?, store.create_link(a, b)?);
40/// # Ok(())
41/// # }
42/// ```
43pub trait DecoratorsExt<T: LinkReference>: Doublets<T> + Sized {
44    /// Wraps the store in [`TransactionsDecorator`] and recovers its journal.
45    fn with_transactions<J: TransitionLog<T>>(
46        self,
47        journal: J,
48    ) -> Result<TransactionsDecorator<T, Self, J>, crate::Error<T>> {
49        TransactionsDecorator::new(self, journal)
50    }
51
52    /// Applies a [`UniquenessPolicy`] — [`Validate`](super::Validate),
53    /// [`Resolve`](super::Resolve) or [`CascadeResolve`](super::CascadeResolve).
54    #[inline]
55    fn with_uniqueness<P: UniquenessPolicy>(self, _policy: P) -> P::Decorator<T, Self> {
56        P::decorate(self)
57    }
58
59    /// Applies a [`UsagesPolicy`] — [`Validate`](super::Validate) or
60    /// [`CascadeResolve`](super::CascadeResolve).
61    #[inline]
62    fn with_usages<P: UsagesPolicy>(self, _policy: P) -> P::Decorator<T, Self> {
63        P::decorate(self)
64    }
65
66    /// Wraps in [`UsagesValidator`].
67    #[inline]
68    fn with_usages_validation(self) -> UsagesValidator<T, Self> {
69        UsagesValidator::new(self)
70    }
71
72    /// Wraps in [`CascadeUsagesResolver`].
73    #[inline]
74    fn with_cascade_usages_resolution(self) -> CascadeUsagesResolver<T, Self> {
75        CascadeUsagesResolver::new(self)
76    }
77
78    /// Wraps in [`InnerReferenceExistenceValidator`].
79    #[inline]
80    fn with_inner_reference_existence_validation(
81        self,
82    ) -> InnerReferenceExistenceValidator<T, Self> {
83        InnerReferenceExistenceValidator::new(self)
84    }
85
86    /// Wraps in [`NonExistentDependenciesCreator`].
87    #[inline]
88    fn with_non_existent_dependencies_creation(self) -> NonExistentDependenciesCreator<T, Self> {
89        NonExistentDependenciesCreator::new(self)
90    }
91
92    /// Wraps in [`ItselfConstantToSelfReferenceResolver`].
93    #[inline]
94    fn with_itself_constant_resolution(self) -> ItselfConstantToSelfReferenceResolver<T, Self> {
95        ItselfConstantToSelfReferenceResolver::new(self)
96    }
97
98    /// Wraps in [`NullConstantToSelfReferenceResolver`].
99    #[inline]
100    fn with_null_constant_resolution(self) -> NullConstantToSelfReferenceResolver<T, Self> {
101        NullConstantToSelfReferenceResolver::new(self)
102    }
103
104    /// Wraps in [`NonNullContentsLinkDeletionResolver`].
105    #[inline]
106    fn with_non_null_contents_deletion_resolution(
107        self,
108    ) -> NonNullContentsLinkDeletionResolver<T, Self> {
109        NonNullContentsLinkDeletionResolver::new(self)
110    }
111
112    /// Wraps in [`LoggingDecorator`], logging every mutation to `writer`.
113    #[inline]
114    fn with_logging<W: Write + Send + Sync>(self, writer: W) -> LoggingDecorator<T, Self, W> {
115        LoggingDecorator::new(self, writer)
116    }
117
118    /// Wraps in [`NoExceptionsDecorator`].
119    #[inline]
120    fn with_no_exceptions(self) -> NoExceptionsDecorator<T, Self> {
121        NoExceptionsDecorator::new(self)
122    }
123
124    /// Builds the same stack as C#
125    /// `ILinksExtensions.DecorateWithAutomaticUniquenessAndUsagesResolution`:
126    /// [`CascadeUsagesResolver`] innermost, then [`NonNullContentsLinkDeletionResolver`],
127    /// then [`CascadeUniquenessAndUsagesResolver`] outermost.
128    /// The cascade explicitly resets each nested usage before descending, so handlers
129    /// observe resets before the corresponding deletions, as with C#'s facade recursion.
130    #[inline]
131    fn with_automatic_uniqueness_and_usages_resolution(
132        self,
133    ) -> AutomaticUniquenessAndUsagesResolution<T, Self> {
134        CascadeUniquenessAndUsagesResolver::new(NonNullContentsLinkDeletionResolver::new(
135            CascadeUsagesResolver::new(self),
136        ))
137    }
138}
139
140impl<T: LinkReference, L: Doublets<T>> DecoratorsExt<T> for L {}