@@ -26,6 +26,12 @@ use query::QueryNode;
2626/// without colliding with the impls for plain integers.
2727///
2828/// Use `id.0` (or `id.into()`) to obtain the raw arena index.
29+ ///
30+ /// Implements [`IntoIterator`] as a singleton (`iter::once(self)`)
31+ /// so that a bare `Id` can be used interchangeably with `Option<Id>`
32+ /// / `Vec<Id>` in places that expect an iterable of ids (e.g.
33+ /// [`crate::build::BuildCtx::translate`] and the field-splice
34+ /// interpolation via [`IntoFieldIds`]).
2935#[ repr( transparent) ]
3036#[ derive( Copy , Clone , Eq , PartialEq , Ord , PartialOrd , Debug , Hash , Serialize ) ]
3137pub struct Id ( pub usize ) ;
@@ -42,16 +48,25 @@ impl From<Id> for usize {
4248 }
4349}
4450
51+ impl IntoIterator for Id {
52+ type Item = Id ;
53+ type IntoIter = std:: iter:: Once < Id > ;
54+ fn into_iter ( self ) -> Self :: IntoIter {
55+ std:: iter:: once ( self )
56+ }
57+ }
58+
4559/// Field and Kind ids are provided by tree-sitter
4660type FieldId = u16 ;
4761type KindId = u16 ;
4862
4963/// Trait for values that can be appended to a field's id list inside a
5064/// `tree!`/`trees!`/`rule!` template (in `{expr}` placeholders).
5165///
52- /// `Id` pushes a single id; the blanket impl for
53- /// `IntoIterator<Item: Into<Id>>` handles `Vec<Id>`, `Option<Id>`,
54- /// arbitrary iterators yielding `Id`, etc.
66+ /// The blanket impl for `IntoIterator<Item: Into<Id>>` handles all
67+ /// current shapes: `Vec<Id>`, `Option<Id>`, arbitrary iterators
68+ /// yielding `Id`, and a bare `Id` itself (which is `IntoIterator`
69+ /// via a singleton).
5570///
5671/// This lets `{expr}` interpolate any of these shapes without a
5772/// dedicated splice syntax — the macro emits the same trait-dispatched
@@ -60,12 +75,6 @@ pub trait IntoFieldIds {
6075 fn extend_into ( self , out : & mut Vec < Id > ) ;
6176}
6277
63- impl IntoFieldIds for Id {
64- fn extend_into ( self , out : & mut Vec < Id > ) {
65- out. push ( self ) ;
66- }
67- }
68-
6978impl < I , T > IntoFieldIds for I
7079where
7180 I : IntoIterator < Item = T > ,
@@ -732,6 +741,16 @@ pub struct TranslatorHandle<'a, C> {
732741 inner : TranslatorImpl < ' a , C > ,
733742}
734743
744+ // Manual `Copy` / `Clone` so `TranslatorHandle<'_, C>: Copy` holds
745+ // regardless of whether `C: Copy`. `TranslatorImpl` contains only
746+ // shared references, which are `Copy` unconditionally.
747+ impl < C > Copy for TranslatorHandle < ' _ , C > { }
748+ impl < C > Clone for TranslatorHandle < ' _ , C > {
749+ fn clone ( & self ) -> Self {
750+ * self
751+ }
752+ }
753+
735754/// Internal phase-specific translation state. Kept private — callers
736755/// interact with [`TranslatorHandle`] only.
737756enum TranslatorImpl < ' a , C > {
@@ -752,6 +771,16 @@ enum TranslatorImpl<'a, C> {
752771 Repeating ,
753772}
754773
774+ // Manual `Copy` / `Clone` so `TranslatorImpl<'_, C>: Copy` holds
775+ // regardless of whether `C: Copy`. All variants hold only shared
776+ // references and small `Copy` scalars.
777+ impl < C > Copy for TranslatorImpl < ' _ , C > { }
778+ impl < C > Clone for TranslatorImpl < ' _ , C > {
779+ fn clone ( & self ) -> Self {
780+ * self
781+ }
782+ }
783+
755784impl < ' a , C : Clone > TranslatorHandle < ' a , C > {
756785 /// Recursively apply OneShot rules to `id` and return the resulting
757786 /// node ids. Errors in a Repeating phase (where translation is not
@@ -970,18 +999,21 @@ fn apply_repeating_rules_inner<C: Clone>(
970999 if Some ( rule_ptr) == skip_rule {
9711000 continue ;
9721001 }
973- // Snapshot the user context before invoking the rule so that any
974- // mutations the rule makes are visible during recursive translation
975- // of its result, but not leaked to the parent's siblings.
976- let snapshot = user_ctx. clone ( ) ;
1002+ // Give each rule attempt a private clone of the user context.
1003+ // Any mutations the rule makes are visible to its transform and
1004+ // to the recursive translation of its result, but never leak
1005+ // back to the parent — the clone is simply dropped when we
1006+ // return. This is also `?`-safe: an error return drops `local`
1007+ // without touching the caller's `user_ctx`.
1008+ let mut local = user_ctx. clone ( ) ;
9771009 // Repeating rules don't need a real translator: their captures
9781010 // aren't auto-translated (Repeating preserves the input schema),
9791011 // and `ctx.translate(id)` errors if invoked from a Repeating
9801012 // transform.
9811013 let translator = TranslatorHandle {
9821014 inner : TranslatorImpl :: Repeating ,
9831015 } ;
984- let try_result = rule. try_rule ( ast, id, fresh, user_ctx , translator) ?;
1016+ let try_result = rule. try_rule ( ast, id, fresh, & mut local , translator) ?;
9851017 if let Some ( result_node) = try_result {
9861018 // For non-repeated rules, suppress further application of *this*
9871019 // rule on the result root, so a rule whose output matches its own
@@ -993,19 +1025,17 @@ fn apply_repeating_rules_inner<C: Clone>(
9931025 results. extend ( apply_repeating_rules_inner (
9941026 index,
9951027 ast,
996- user_ctx ,
1028+ & mut local ,
9971029 node,
9981030 fresh,
9991031 rewrite_depth + 1 ,
10001032 next_skip,
10011033 ) ?) ;
10021034 }
1003- * user_ctx = snapshot;
10041035 return Ok ( results) ;
10051036 }
1006- // Rule didn't match; restore any speculative changes (none expected
1007- // since try_rule only mutates on match, but be defensive).
1008- * user_ctx = snapshot;
1037+ // Rule didn't match; `local` is dropped as we loop to the next
1038+ // rule.
10091039 }
10101040
10111041 // Take the parent's fields by ownership: the recursion will rewrite
@@ -1087,11 +1117,13 @@ fn apply_one_shot_rules_inner<C: Clone>(
10871117
10881118 for rule in index. rules_for_kind ( node_kind) {
10891119 if let Some ( captures) = rule. try_match ( ast, id) ? {
1090- // Snapshot the user context before invoking the rule so that any
1091- // mutations the rule (or its transitively-translated captures)
1092- // make are visible during this rule's transform, but not leaked
1093- // to the parent's siblings.
1094- let snapshot = user_ctx. clone ( ) ;
1120+ // Give the rule a private clone of the user context. Any
1121+ // mutations the rule (or its transitively-translated
1122+ // captures) make are visible during this rule's transform,
1123+ // but never leak back — the clone is dropped when we
1124+ // return. `?`-safe: an error return drops `local` without
1125+ // touching the caller's `user_ctx`.
1126+ let mut local = user_ctx. clone ( ) ;
10951127 // Build the translator handle the transform will use to
10961128 // recursively translate captures (or, for macro-generated
10971129 // rules, the auto-translate prefix uses it to translate every
@@ -1104,8 +1136,7 @@ fn apply_one_shot_rules_inner<C: Clone>(
11041136 matched_root : id,
11051137 } ,
11061138 } ;
1107- let result = rule. run_transform ( ast, captures, id, fresh, user_ctx, translator) ?;
1108- * user_ctx = snapshot;
1139+ let result = rule. run_transform ( ast, captures, id, fresh, & mut local, translator) ?;
11091140 return Ok ( result) ;
11101141 }
11111142 }
0 commit comments