@@ -208,6 +208,13 @@ impl MultiTemplate {
208
208
/// let template = Template::parse("{split:,:..|sort|join: - }").unwrap();
209
209
/// ```
210
210
pub fn parse ( template : & str ) -> Result < Self , String > {
211
+ // Fast-path: if the input is a *single* template block (no outer-level
212
+ // literal text) we can skip the multi-template scanner and directly
213
+ // parse the operation list.
214
+ if let Some ( single) = Self :: try_single_block ( template) ? {
215
+ return Ok ( single) ;
216
+ }
217
+
211
218
let ( sections, _) = parser:: parse_multi_template ( template) ?;
212
219
Ok ( Self :: new ( template. to_string ( ) , sections, false ) )
213
220
}
@@ -252,6 +259,14 @@ impl MultiTemplate {
252
259
/// let template = Template::parse_with_debug("{upper}", Some(true)).unwrap();
253
260
/// ```
254
261
pub fn parse_with_debug ( template : & str , debug : Option < bool > ) -> Result < Self , String > {
262
+ // Re-use the single-block shortcut when applicable.
263
+ if let Some ( mut single) = Self :: try_single_block ( template) ? {
264
+ if let Some ( dbg_override) = debug {
265
+ single. debug = dbg_override;
266
+ }
267
+ return Ok ( single) ;
268
+ }
269
+
255
270
let ( sections, inner_dbg) = parser:: parse_multi_template ( template) ?;
256
271
Ok ( Self :: new (
257
272
template. to_string ( ) ,
@@ -588,6 +603,45 @@ impl MultiTemplate {
588
603
. collect :: < Vec < _ > > ( )
589
604
. join ( " | " )
590
605
}
606
+
607
+ /* -------- helper: detect plain single-block templates ------------- */
608
+
609
+ /// Detects and parses templates that consist of exactly one `{ ... }` block
610
+ /// with no surrounding literal text. Returns `Ok(Some(MultiTemplate))` when
611
+ /// the fast path can be applied, `Ok(None)` otherwise.
612
+ fn try_single_block ( template : & str ) -> Result < Option < Self > , String > {
613
+ // Must start with '{' and end with '}' to be a candidate.
614
+ if !( template. starts_with ( '{' ) && template. ends_with ( '}' ) ) {
615
+ return Ok ( None ) ;
616
+ }
617
+
618
+ // Verify that the outer-most braces close at the very end and that the
619
+ // brace nesting never returns to zero before the last char.
620
+ let mut depth = 0u32 ;
621
+ for ch in template[ 1 ..template. len ( ) - 1 ] . chars ( ) {
622
+ match ch {
623
+ '{' => depth += 1 ,
624
+ '}' => {
625
+ if depth == 0 {
626
+ // Closed the top-level early → literal content exists.
627
+ return Ok ( None ) ;
628
+ }
629
+ depth -= 1 ;
630
+ }
631
+ _ => { }
632
+ }
633
+ }
634
+
635
+ if depth != 0 {
636
+ // Unbalanced braces – fall back to full parser for proper error.
637
+ return Ok ( None ) ;
638
+ }
639
+
640
+ // Safe to treat as single template block.
641
+ let ( ops, dbg_flag) = parser:: parse_template ( template) ?;
642
+ let sections = vec ! [ TemplateSection :: Template ( ops) ] ;
643
+ Ok ( Some ( Self :: new ( template. to_string ( ) , sections, dbg_flag) ) )
644
+ }
591
645
}
592
646
593
647
/* ---------- trait impls -------------------------------------------------- */
0 commit comments