ferrunix_core/
dependency_builder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! Implementation of [`DepBuilder`] for tuples to be used with
//! [`Registry::with_deps`].

use std::any::TypeId;

use crate::types::Registerable;
use crate::Registry;

/// Required for sealing the trait. *Must not be public*.
pub(crate) mod private {
    /// This token is used to seal the [`DepBuilder`] trait from downstream
    /// crates.
    #[allow(missing_debug_implementations)]
    #[derive(Clone, Copy)]
    pub struct SealToken;
}

/// The [`DepBuilder`] trait is the key to specify a variable amount of
/// dependencies in the [`Registry::with_deps`] call from [`Registry`].
///
/// The trait is implemented by the `DepBuilderImpl!` macro for 0-ary, to 10-ary
/// tuples (e.g., `(T1,)`, `(T1, T2)`, etc.), which allows these tuples to be
/// passed as a single type parameter into [`Registry::with_deps`].
///
/// This trait is sealed, meaning it cannot be implemented or called by any
/// downstream crates.
pub trait DepBuilder<R> {
    /// When implemented, this should validate that all dependencies which are
    /// part of `Self` exist to construct the type `R`. If the dependencies
    /// cannot be fulfilled, `None` must be returned.
    ///
    /// If the dependencies can be fulfilled, they must be constructed as an
    /// N-ary tuple (same length and types as `Self`) and passed as the
    /// argument to `ctor`. `ctor` is a user provided constructor for the
    /// type `R`.
    ///
    /// An implementation for tuples is provided by `DepBuilderImpl!`.
    ///
    /// We advise against *manually* implementing `build`.
    fn build(
        registry: &Registry,
        ctor: fn(Self) -> R,
        _: private::SealToken,
    ) -> Option<R>
    where
        R: Sized;

    /// Constructs a [`Vec`] of [`std::any::TypeId`]s from the types in `Self`.
    /// The resulting vector must have the same length as `Self`.
    ///
    /// An implementation for tuples is provided by `DepBuilderImpl!`.
    ///
    /// We advise against *manually* implementing `as_typeids`.
    fn as_typeids(_: private::SealToken) -> Vec<TypeId>;
}

impl<R> DepBuilder<R> for ()
where
    R: Registerable,
{
    fn build(
        _registry: &Registry,
        ctor: fn(Self) -> R,
        _: private::SealToken,
    ) -> Option<R> {
        Some(ctor(()))
    }

    fn as_typeids(_: private::SealToken) -> Vec<TypeId> {
        Vec::new()
    }
}

/// Generates the implementation for [`DepBuilder`].
macro_rules! DepBuilderImpl {
    ($n:expr, { $($ts:ident),+ }) => {
        impl<R, $($ts,)*> $crate::dependency_builder::DepBuilder<R> for ($($ts,)*)
        where
            R: $crate::types::Registerable,
            $($ts: $crate::dependencies::Dep,)*
        {
            fn build(registry: &$crate::registry::Registry, ctor: fn(Self) -> R, _: private::SealToken) -> Option<R> {
                if !registry.validate::<R>() {
                    return None;
                }

                let deps = (
                    $(
                        <$ts>::new(registry),
                    )*
                );

                Some(ctor(deps))
            }

            fn as_typeids(_: private::SealToken) -> ::std::vec::Vec<::std::any::TypeId> {
                ::std::vec![ $(<$ts>::type_id(),)* ]
            }
        }
    };
}

DepBuilderImpl!(1, { T1 });
DepBuilderImpl!(2, { T1, T2 });
DepBuilderImpl!(3, { T1, T2, T3 });
DepBuilderImpl!(4, { T1, T2, T3, T4 });
DepBuilderImpl!(5, { T1, T2, T3, T4, T5 });
DepBuilderImpl!(6, { T1, T2, T3, T4, T5, T6 });
DepBuilderImpl!(7, { T1, T2, T3, T4, T5, T6, T8 });
DepBuilderImpl!(8, { T1, T2, T3, T4, T5, T6, T8, T9 });