1
- use std:: borrow:: Cow ;
2
1
use std:: collections:: HashMap ;
3
2
4
3
use serde_json:: value:: Value as Json ;
@@ -15,22 +14,26 @@ use crate::RenderErrorReason;
15
14
16
15
pub ( crate ) const PARTIAL_BLOCK : & str = "@partial-block" ;
17
16
18
- fn find_partial < ' reg : ' rc , ' rc : ' a , ' a > (
19
- rc : & ' a RenderContext < ' reg , ' rc > ,
17
+ fn find_partial < ' reg : ' rc , ' rc > (
18
+ rc : & RenderContext < ' reg , ' rc > ,
20
19
r : & ' reg Registry < ' reg > ,
21
20
d : & Decorator < ' rc > ,
22
21
name : & str ,
23
- ) -> Result < Option < Cow < ' a , Template > > , RenderError > {
22
+ ) -> Result < Option < & ' rc Template > , RenderError > {
24
23
if let Some ( partial) = rc. get_partial ( name) {
25
- return Ok ( Some ( Cow :: Borrowed ( partial) ) ) ;
24
+ return Ok ( Some ( partial) ) ;
26
25
}
27
26
28
- if let Some ( tpl) = r. get_or_load_template_optional ( name) {
29
- return tpl. map ( Option :: Some ) ;
27
+ if let Some ( t) = rc. get_dev_mode_template ( name) {
28
+ return Ok ( Some ( t) ) ;
29
+ }
30
+
31
+ if let Some ( t) = r. get_template ( name) {
32
+ return Ok ( Some ( t) ) ;
30
33
}
31
34
32
35
if let Some ( tpl) = d. template ( ) {
33
- return Ok ( Some ( Cow :: Borrowed ( tpl) ) ) ;
36
+ return Ok ( Some ( tpl) ) ;
34
37
}
35
38
36
39
Ok ( None )
@@ -49,114 +52,103 @@ pub fn expand_partial<'reg: 'rc, 'rc>(
49
52
}
50
53
51
54
let tname = d. name ( ) ;
55
+
56
+ let current_template_before = rc. get_current_template_name ( ) ;
57
+ let indent_before = rc. get_indent_string ( ) . cloned ( ) ;
58
+
52
59
if rc. is_current_template ( tname) {
53
60
return Err ( RenderErrorReason :: CannotIncludeSelf . into ( ) ) ;
54
61
}
55
62
56
63
let partial = find_partial ( rc, r, d, tname) ?;
57
64
58
- if let Some ( t) = partial {
59
- // clone to avoid lifetime issue
60
- // FIXME refactor this to avoid
61
- let mut local_rc = rc. clone ( ) ;
62
-
63
- // if tname == PARTIAL_BLOCK
64
- let is_partial_block = tname == PARTIAL_BLOCK ;
65
-
66
- // add partial block depth there are consecutive partial
67
- // blocks in the stack.
68
- if is_partial_block {
69
- local_rc. inc_partial_block_depth ( ) ;
70
- } else {
71
- // depth cannot be lower than 0, which is guaranted in the
72
- // `dec_partial_block_depth` method
73
- local_rc. dec_partial_block_depth ( ) ;
74
- }
65
+ let Some ( partial) = partial else {
66
+ return Err ( RenderErrorReason :: PartialNotFound ( tname. to_owned ( ) ) . into ( ) ) ;
67
+ } ;
68
+
69
+ let is_partial_block = tname == PARTIAL_BLOCK ;
70
+
71
+ // add partial block depth there are consecutive partial
72
+ // blocks in the stack.
73
+ if is_partial_block {
74
+ rc. inc_partial_block_depth ( ) ;
75
+ } else {
76
+ // depth cannot be lower than 0, which is guaranted in the
77
+ // `dec_partial_block_depth` method
78
+ rc. dec_partial_block_depth ( ) ;
79
+ }
80
+
81
+ let mut block_created = false ;
82
+
83
+ // create context if param given
84
+ if let Some ( base_path) = d. param ( 0 ) . and_then ( |p| p. context_path ( ) ) {
85
+ // path given, update base_path
86
+ let mut block_inner = BlockContext :: new ( ) ;
87
+ * block_inner. base_path_mut ( ) = base_path. to_vec ( ) ;
75
88
76
- let mut block_created = false ;
89
+ block_created = true ;
90
+ rc. push_block ( block_inner) ;
91
+ }
77
92
78
- // create context if param given
79
- if let Some ( base_path) = d. param ( 0 ) . and_then ( |p| p. context_path ( ) ) {
80
- // path given, update base_path
81
- let mut block_inner = BlockContext :: new ( ) ;
82
- base_path. clone_into ( block_inner. base_path_mut ( ) ) ;
93
+ if !d. hash ( ) . is_empty ( ) {
94
+ // hash given, update base_value
95
+ let hash_ctx = d
96
+ . hash ( )
97
+ . iter ( )
98
+ . map ( |( k, v) | ( * k, v. value ( ) ) )
99
+ . collect :: < HashMap < & str , & Json > > ( ) ;
100
+
101
+ // create block if we didn't (no param provided for partial expression)
102
+ if !block_created {
103
+ let block_inner = if let Some ( block) = rc. block ( ) {
104
+ // reuse current block information, including base_path and
105
+ // base_value if any
106
+ block. clone ( )
107
+ } else {
108
+ BlockContext :: new ( )
109
+ } ;
83
110
84
- // because block is moved here, we need another bool variable to track
85
- // its status for later cleanup
86
111
block_created = true ;
87
- // clear blocks to prevent block params from parent
88
- // template to be leaked into partials
89
- // see `test_partial_context_issue_495` for the case.
90
- local_rc. clear_blocks ( ) ;
91
- local_rc. push_block ( block_inner) ;
112
+ rc. push_block ( block_inner) ;
92
113
}
93
114
94
- if !d. hash ( ) . is_empty ( ) {
95
- // hash given, update base_value
96
- let hash_ctx = d
97
- . hash ( )
98
- . iter ( )
99
- . map ( |( k, v) | ( * k, v. value ( ) ) )
100
- . collect :: < HashMap < & str , & Json > > ( ) ;
101
-
102
- // create block if we didn't (no param provided for partial expression)
103
- if !block_created {
104
- let block_inner = if let Some ( block) = local_rc. block ( ) {
105
- // reuse current block information, including base_path and
106
- // base_value if any
107
- block. clone ( )
108
- } else {
109
- BlockContext :: new ( )
110
- } ;
111
-
112
- local_rc. clear_blocks ( ) ;
113
- local_rc. push_block ( block_inner) ;
114
- }
115
-
116
- // evaluate context within current block, this includes block
117
- // context provided by partial expression parameter
118
- let merged_context = merge_json (
119
- local_rc. evaluate2 ( ctx, & Path :: current ( ) ) ?. as_json ( ) ,
120
- & hash_ctx,
121
- ) ;
122
-
123
- // update the base value, there must be a block for this so it's
124
- // also safe to unwrap.
125
- if let Some ( block) = local_rc. block_mut ( ) {
126
- block. set_base_value ( merged_context) ;
127
- }
128
- }
115
+ // evaluate context within current block, this includes block
116
+ // context provided by partial expression parameter
117
+ let merged_context = merge_json ( rc. evaluate2 ( ctx, & Path :: current ( ) ) ?. as_json ( ) , & hash_ctx) ;
129
118
130
- // @partial-block
131
- if let Some ( pb) = d. template ( ) {
132
- local_rc. push_partial_block ( pb) ;
119
+ // update the base value, there must be a block for this so it's
120
+ // also safe to unwrap.
121
+ if let Some ( block) = rc. block_mut ( ) {
122
+ block. set_base_value ( merged_context) ;
133
123
}
124
+ }
134
125
135
- // indent
136
- local_rc . set_indent_string ( d . indent ( ) . cloned ( ) ) ;
137
-
138
- let result = t . render ( r , ctx , & mut local_rc , out ) ;
126
+ // @partial-block
127
+ if let Some ( pb ) = d . template ( ) {
128
+ rc . push_partial_block ( pb ) ;
129
+ }
139
130
140
- // cleanup
131
+ // indent
132
+ rc. set_indent_string ( d. indent ( ) . cloned ( ) ) ;
141
133
142
- let trailing_newline = local_rc . get_trailine_newline ( ) ;
134
+ let result = partial . render ( r , ctx , rc , out ) ;
143
135
144
- if block_created {
145
- local_rc. pop_block ( ) ;
146
- }
136
+ // cleanup
137
+ let trailing_newline = rc. get_trailine_newline ( ) ;
147
138
148
- if d. template ( ) . is_some ( ) {
149
- local_rc . pop_partial_block ( ) ;
150
- }
139
+ if d. template ( ) . is_some ( ) {
140
+ rc . pop_partial_block ( ) ;
141
+ }
151
142
152
- drop ( local_rc) ;
143
+ if block_created {
144
+ rc. pop_block ( ) ;
145
+ }
153
146
154
- rc. set_trailing_newline ( trailing_newline) ;
147
+ rc. set_trailing_newline ( trailing_newline) ;
148
+ rc. set_current_template_name ( current_template_before) ;
149
+ rc. set_indent_string ( indent_before) ;
155
150
156
- result
157
- } else {
158
- Err ( RenderErrorReason :: PartialNotFound ( tname. to_owned ( ) ) . into ( ) )
159
- }
151
+ result
160
152
}
161
153
162
154
#[ cfg( test) ]
0 commit comments