@@ -9,24 +9,88 @@ pub use provider::Provider;
9
9
use template:: Part ;
10
10
pub use template:: Template ;
11
11
12
+ /// A [`ProviderResolver`] that can be shared.
13
+ pub type SharedPreparedResolver =
14
+ std:: sync:: Arc < std:: sync:: OnceLock < std:: sync:: Arc < PreparedResolver > > > ;
15
+
16
+ /// A [`Resolver`] which is extended by [`Provider`]s.
17
+ #[ derive( Debug , Default ) ]
18
+ pub struct ProviderResolver {
19
+ internal : Resolver ,
20
+ providers : Vec < Box < dyn Provider > > ,
21
+ }
22
+
23
+ impl ProviderResolver {
24
+ /// Creates a Resolver for the given Tree.
25
+ pub fn new ( variables : impl IntoIterator < Item = ( String , Variable ) > ) -> Result < Self > {
26
+ Ok ( Self {
27
+ internal : Resolver :: new ( variables) ?,
28
+ providers : Default :: default ( ) ,
29
+ } )
30
+ }
31
+
32
+ /// Adds component variable values to the Resolver.
33
+ pub fn add_component_variables (
34
+ & mut self ,
35
+ component_id : impl Into < String > ,
36
+ variables : impl IntoIterator < Item = ( String , String ) > ,
37
+ ) -> Result < ( ) > {
38
+ self . internal
39
+ . add_component_variables ( component_id, variables)
40
+ }
41
+
42
+ /// Adds a variable Provider to the Resolver.
43
+ pub fn add_provider ( & mut self , provider : Box < dyn Provider > ) {
44
+ self . providers . push ( provider) ;
45
+ }
46
+
47
+ /// Resolves a variable value for the given path.
48
+ pub async fn resolve ( & self , component_id : & str , key : Key < ' _ > ) -> Result < String > {
49
+ let template = self . internal . get_template ( component_id, key) ?;
50
+ self . resolve_template ( template) . await
51
+ }
52
+
53
+ /// Resolves the given template.
54
+ pub async fn resolve_template ( & self , template : & Template ) -> Result < String > {
55
+ let mut resolved_parts: Vec < Cow < str > > = Vec :: with_capacity ( template. parts ( ) . len ( ) ) ;
56
+ for part in template. parts ( ) {
57
+ resolved_parts. push ( match part {
58
+ Part :: Lit ( lit) => lit. as_ref ( ) . into ( ) ,
59
+ Part :: Expr ( var) => self . resolve_variable ( var) . await ?. into ( ) ,
60
+ } ) ;
61
+ }
62
+ Ok ( resolved_parts. concat ( ) )
63
+ }
64
+
65
+ /// Fully resolve all variables into a [`PreparedResolver`].
66
+ pub async fn prepare ( & self ) -> Result < PreparedResolver > {
67
+ let mut variables = HashMap :: new ( ) ;
68
+ for name in self . internal . variables . keys ( ) {
69
+ let value = self . resolve_variable ( name) . await ?;
70
+ variables. insert ( name. clone ( ) , value) ;
71
+ }
72
+ Ok ( PreparedResolver { variables } )
73
+ }
74
+
75
+ async fn resolve_variable ( & self , key : & str ) -> Result < String > {
76
+ for provider in & self . providers {
77
+ if let Some ( value) = provider. get ( & Key ( key) ) . await . map_err ( Error :: Provider ) ? {
78
+ return Ok ( value) ;
79
+ }
80
+ }
81
+ self . internal . resolve_variable ( key)
82
+ }
83
+ }
84
+
12
85
/// A variable resolver.
13
86
#[ derive( Debug , Default ) ]
14
87
pub struct Resolver {
15
88
// variable key -> variable
16
89
variables : HashMap < String , Variable > ,
17
90
// component ID -> variable key -> variable value template
18
91
component_configs : HashMap < String , HashMap < String , Template > > ,
19
- providers : Vec < Box < dyn Provider > > ,
20
- }
21
-
22
- #[ derive( Default ) ]
23
- pub struct PreparedResolver {
24
- variables : HashMap < String , String > ,
25
92
}
26
93
27
- pub type SharedPreparedResolver =
28
- std:: sync:: Arc < std:: sync:: OnceLock < std:: sync:: Arc < PreparedResolver > > > ;
29
-
30
94
impl Resolver {
31
95
/// Creates a Resolver for the given Tree.
32
96
pub fn new ( variables : impl IntoIterator < Item = ( String , Variable ) > ) -> Result < Self > {
@@ -36,7 +100,6 @@ impl Resolver {
36
100
Ok ( Self {
37
101
variables,
38
102
component_configs : Default :: default ( ) ,
39
- providers : Default :: default ( ) ,
40
103
} )
41
104
}
42
105
@@ -62,58 +125,43 @@ impl Resolver {
62
125
Ok ( ( ) )
63
126
}
64
127
65
- /// Adds a variable Provider to the Resolver.
66
- pub fn add_provider ( & mut self , provider : Box < dyn Provider > ) {
67
- self . providers . push ( provider) ;
68
- }
69
-
70
128
/// Resolves a variable value for the given path.
71
- pub async fn resolve ( & self , component_id : & str , key : Key < ' _ > ) -> Result < String > {
72
- let configs = self . component_configs . get ( component_id) . ok_or_else ( || {
73
- Error :: Undefined ( format ! ( "no variable for component {component_id:?}" ) )
74
- } ) ?;
75
-
76
- let key = key. as_ref ( ) ;
77
- let template = configs
78
- . get ( key)
79
- . ok_or_else ( || Error :: Undefined ( format ! ( "no variable for {component_id:?}.{key:?}" ) ) ) ?;
80
-
81
- self . resolve_template ( template) . await
129
+ pub fn resolve ( & self , component_id : & str , key : Key < ' _ > ) -> Result < String > {
130
+ let template = self . get_template ( component_id, key) ?;
131
+ self . resolve_template ( template)
82
132
}
83
133
84
- pub async fn resolve_template ( & self , template : & Template ) -> Result < String > {
134
+ /// Resolves the given template.
135
+ fn resolve_template ( & self , template : & Template ) -> Result < String > {
85
136
let mut resolved_parts: Vec < Cow < str > > = Vec :: with_capacity ( template. parts ( ) . len ( ) ) ;
86
137
for part in template. parts ( ) {
87
138
resolved_parts. push ( match part {
88
139
Part :: Lit ( lit) => lit. as_ref ( ) . into ( ) ,
89
- Part :: Expr ( var) => self . resolve_variable ( var) . await ?. into ( ) ,
140
+ Part :: Expr ( var) => self . resolve_variable ( var) ?. into ( ) ,
90
141
} ) ;
91
142
}
92
143
Ok ( resolved_parts. concat ( ) )
93
144
}
94
145
95
- pub async fn prepare ( & self ) -> Result < PreparedResolver > {
96
- let mut variables = HashMap :: new ( ) ;
97
- for name in self . variables . keys ( ) {
98
- let value = self . resolve_variable ( name) . await ?;
99
- variables. insert ( name. clone ( ) , value) ;
100
- }
101
- Ok ( PreparedResolver { variables } )
146
+ /// Gets a template for the given path.
147
+ fn get_template ( & self , component_id : & str , key : Key < ' _ > ) -> Result < & Template > {
148
+ let configs = self . component_configs . get ( component_id) . ok_or_else ( || {
149
+ Error :: Undefined ( format ! ( "no variable for component {component_id:?}" ) )
150
+ } ) ?;
151
+ let key = key. as_ref ( ) ;
152
+ let template = configs
153
+ . get ( key)
154
+ . ok_or_else ( || Error :: Undefined ( format ! ( "no variable for {component_id:?}.{key:?}" ) ) ) ?;
155
+ Ok ( template)
102
156
}
103
157
104
- async fn resolve_variable ( & self , key : & str ) -> Result < String > {
158
+ fn resolve_variable ( & self , key : & str ) -> Result < String > {
105
159
let var = self
106
160
. variables
107
161
. get ( key)
108
162
// This should have been caught by validate_template
109
163
. ok_or_else ( || Error :: InvalidName ( key. to_string ( ) ) ) ?;
110
164
111
- for provider in & self . providers {
112
- if let Some ( value) = provider. get ( & Key ( key) ) . await . map_err ( Error :: Provider ) ? {
113
- return Ok ( value) ;
114
- }
115
- }
116
-
117
165
var. default . clone ( ) . ok_or_else ( || {
118
166
Error :: Provider ( anyhow:: anyhow!(
119
167
"no provider resolved required variable {key:?}"
@@ -134,14 +182,14 @@ impl Resolver {
134
182
}
135
183
}
136
184
137
- impl PreparedResolver {
138
- fn resolve_variable ( & self , key : & str ) -> Result < String > {
139
- self . variables
140
- . get ( key)
141
- . cloned ( )
142
- . ok_or ( Error :: InvalidName ( key. to_string ( ) ) )
143
- }
185
+ /// A resolver who has resolved all variables.
186
+ #[ derive( Default ) ]
187
+ pub struct PreparedResolver {
188
+ variables : HashMap < String , String > ,
189
+ }
144
190
191
+ impl PreparedResolver {
192
+ /// Resolves a the given template.
145
193
pub fn resolve_template ( & self , template : & Template ) -> Result < String > {
146
194
let mut resolved_parts: Vec < Cow < str > > = Vec :: with_capacity ( template. parts ( ) . len ( ) ) ;
147
195
for part in template. parts ( ) {
@@ -152,6 +200,13 @@ impl PreparedResolver {
152
200
}
153
201
Ok ( resolved_parts. concat ( ) )
154
202
}
203
+
204
+ fn resolve_variable ( & self , key : & str ) -> Result < String > {
205
+ self . variables
206
+ . get ( key)
207
+ . cloned ( )
208
+ . ok_or ( Error :: InvalidName ( key. to_string ( ) ) )
209
+ }
155
210
}
156
211
157
212
/// A variable key
@@ -245,7 +300,7 @@ mod tests {
245
300
}
246
301
247
302
async fn test_resolve ( template : & str ) -> Result < String > {
248
- let mut resolver = Resolver :: new ( [
303
+ let mut resolver = ProviderResolver :: new ( [
249
304
(
250
305
"required" . into ( ) ,
251
306
Variable {
0 commit comments