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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use crate::;
/// Trait used as input for wiring layers, aiming to provide all the resources the layer needs for wiring.
///
/// For most cases, the most conevenient way to implement this trait is to use the `#[derive(FromContext)]`.
/// Otherwise, the trait has several blanket implementations (including the implementation for `()` and `Option`).
///
/// # Example
///
/// ```
/// use wire_framework::FromContext;
/// # #[derive(Clone)]
/// # struct MandatoryResource;
/// # impl wire_framework::resource::Resource for MandatoryResource { fn name() -> String { "a".into() } }
/// # #[derive(Clone)]
/// # struct OptionalResource;
/// # impl wire_framework::resource::Resource for OptionalResource { fn name() -> String { "b".into() } }
/// # #[derive(Default, Clone)]
/// # struct ResourceWithDefault;
/// # impl wire_framework::resource::Resource for ResourceWithDefault { fn name() -> String { "c".into() } }
/// #[derive(FromContext)]
/// struct MyWiringLayerInput {
/// // The following field _must_ be present in the context.
/// mandatory_resource: MandatoryResource,
/// // The following field is optional.
/// // If will be `None` if there is no such resource in the context.
/// optional_resource: Option<OptionalResource>,
/// // The following field is guaranteed to fetch the value from the context.
/// // In case the value is missing, a default value will be added to the context.
/// #[context(default)]
/// resource_with_default: ResourceWithDefault,
/// }
/// ```
/// Trait used as output for wiring layers, aiming to provide all the resources and tasks the layer creates.
///
/// For most cases, the most conevenient way to implement this trait is to use the `#[derive(IntoContext)]`.
/// Otherwise, the trait has several blanket implementations (including the implementation for `()` and `Option`).
/// Note, however, that due to the lack of specialization, the blanket implementation for `Option<T: Task>` is not
/// provided. When used in the macro, tasks must be annotated with the `#[context(task)]` attribute.
///
/// Note: returning a resource that already exists in the context will result in a wiring error. If you need to provide
/// a "substitute" resource, request `Option` of it in the `FromContext` implementation to check whether it's already
/// provided.
///
///
/// # Example
///
/// ```
/// use wire_framework::IntoContext;
/// # struct MyTask;
/// # #[async_trait::async_trait]
/// # impl wire_framework::task::Task for MyTask {
/// # fn id(&self) -> wire_framework::TaskId { "a".into() }
/// # async fn run(self: Box<Self>, _: wire_framework::StopReceiver) -> eyre::Result<()> { Ok(()) }
/// # }
/// # struct MaybeTask;
/// # #[async_trait::async_trait]
/// # impl wire_framework::task::Task for MaybeTask {
/// # fn id(&self) -> wire_framework::TaskId { "b".into() }
/// # async fn run(self: Box<Self>, _: wire_framework::StopReceiver) -> eyre::Result<()> { Ok(()) }
/// # }
/// # struct MyResource;
/// # impl wire_framework::resource::Resource for MyResource { fn name() -> String { "a".into() } }
/// # struct MaybeResource;
/// # impl wire_framework::resource::Resource for MaybeResource { fn name() -> String { "b".into() } }
/// #[derive(IntoContext)]
/// struct MyWiringLayerOutput {
/// // This resource will be inserted unconditionally.
/// // Will err if such resource is already present in the context.
/// recource: MyResource,
/// // Will only provide the resource if it's `Some`.
/// maybe_resource: Option<MaybeResource>,
/// // Will provide task unconditionally.
/// #[context(task)]
/// task: MyTask,
/// // Will provide task only if it's `Some`.
/// #[context(task)]
/// maybe_task: Option<MaybeTask>,
/// }
/// ```
// Unfortunately, without specialization we cannot provide a blanket implementation for `T: Task`
// as well. `Resource` is chosen because it also has a blanket implementation of `FromContext`.