11use async_trait:: async_trait;
22use rspack_error:: Result ;
3- use rustc_hash:: FxHashSet ;
3+
4+ pub struct HookMetadata {
5+ pub name : & ' static str ,
6+ }
7+
8+ pub struct HookCommon {
9+ metadata : HookMetadata ,
10+ tap_stages : Vec < i32 > ,
11+ interceptor_count : usize ,
12+ }
13+
14+ impl HookCommon {
15+ pub fn new ( name : & ' static str ) -> Self {
16+ Self {
17+ metadata : HookMetadata { name } ,
18+ tap_stages : Vec :: new ( ) ,
19+ interceptor_count : 0 ,
20+ }
21+ }
22+
23+ pub fn name ( & self ) -> & ' static str {
24+ self . metadata . name
25+ }
26+
27+ pub fn tap_stages ( & self ) -> & [ i32 ] {
28+ & self . tap_stages
29+ }
30+
31+ pub fn push_tap_stage ( & mut self , stage : i32 ) {
32+ self . tap_stages . push ( stage) ;
33+ }
34+
35+ pub fn insert_tap_stage ( & mut self , index : usize , stage : i32 ) {
36+ self . tap_stages . insert ( index, stage) ;
37+ }
38+
39+ pub fn tap_insert_position ( & self , stage : i32 ) -> usize {
40+ self . tap_stages . partition_point ( |& current| current <= stage)
41+ }
42+
43+ pub fn increment_interceptor_count ( & mut self ) {
44+ self . interceptor_count += 1 ;
45+ }
46+
47+ pub fn interceptor_count ( & self ) -> usize {
48+ self . interceptor_count
49+ }
50+
51+ pub fn used_stages ( & self ) -> Vec < i32 > {
52+ let mut used_stages = self . tap_stages . clone ( ) ;
53+ // tap_stages is kept sorted by stage, so duplicate stages are adjacent.
54+ used_stages. dedup ( ) ;
55+ used_stages
56+ }
57+
58+ pub fn is_empty ( & self ) -> bool {
59+ self . tap_stages . is_empty ( ) && self . interceptor_count == 0
60+ }
61+ }
62+
63+ pub fn sort_indices_by_stage ( stages : & [ i32 ] ) -> Vec < u16 > {
64+ debug_assert ! ( stages. len( ) <= HookTapIndex :: INDEX_LIMIT ) ;
65+ let mut indices: Vec < _ > = ( 0 ..stages. len ( ) ) . map ( |index| index as u16 ) . collect ( ) ;
66+ indices. sort_by_key ( |& index| {
67+ let index = index as usize ;
68+ ( stages[ index] , index)
69+ } ) ;
70+ debug_assert ! ( indices. windows( 2 ) . all( |indices| {
71+ let prev = indices[ 0 ] as usize ;
72+ let next = indices[ 1 ] as usize ;
73+ ( stages[ prev] , prev) <= ( stages[ next] , next)
74+ } ) ) ;
75+ indices
76+ }
77+
78+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
79+ pub struct HookTapIndex ( u16 ) ;
80+
81+ impl HookTapIndex {
82+ const INTERCEPT_FLAG : u16 = 1 << 15 ;
83+ const INDEX_MASK : u16 = !Self :: INTERCEPT_FLAG ;
84+ const INDEX_LIMIT : usize = Self :: INDEX_MASK as usize + 1 ;
85+
86+ pub fn tap ( index : u16 ) -> Self {
87+ debug_assert ! ( index <= Self :: INDEX_MASK ) ;
88+ Self ( index)
89+ }
90+
91+ pub fn intercept ( index : u16 ) -> Self {
92+ debug_assert ! ( index <= Self :: INDEX_MASK ) ;
93+ Self ( Self :: INTERCEPT_FLAG | index)
94+ }
95+
96+ pub fn is_tap ( self ) -> bool {
97+ self . 0 & Self :: INTERCEPT_FLAG == 0
98+ }
99+
100+ pub fn index ( self ) -> usize {
101+ ( self . 0 & Self :: INDEX_MASK ) as usize
102+ }
103+ }
104+
105+ pub struct MergedTapIndicesByStage < ' a > {
106+ base_stages : & ' a [ i32 ] ,
107+ additional_stages : & ' a [ i32 ] ,
108+ additional_order : Vec < u16 > ,
109+ base_index : u16 ,
110+ additional_cursor : u16 ,
111+ }
112+
113+ pub fn merged_tap_indices_by_stage < ' a > (
114+ base_stages : & ' a [ i32 ] ,
115+ additional_stages : & ' a [ i32 ] ,
116+ ) -> MergedTapIndicesByStage < ' a > {
117+ debug_assert ! ( base_stages. len( ) <= HookTapIndex :: INDEX_LIMIT ) ;
118+ debug_assert ! ( additional_stages. len( ) <= HookTapIndex :: INDEX_LIMIT ) ;
119+ debug_assert ! ( base_stages. windows( 2 ) . all( |stages| stages[ 0 ] <= stages[ 1 ] ) ) ;
120+ let additional_order = sort_indices_by_stage ( additional_stages) ;
121+ debug_assert_eq ! ( additional_order. len( ) , additional_stages. len( ) ) ;
122+ debug_assert ! (
123+ additional_order
124+ . iter( )
125+ . all( |& index| ( index as usize ) < additional_stages. len( ) )
126+ ) ;
127+ MergedTapIndicesByStage {
128+ base_stages,
129+ additional_stages,
130+ additional_order,
131+ base_index : 0 ,
132+ additional_cursor : 0 ,
133+ }
134+ }
135+
136+ impl Iterator for MergedTapIndicesByStage < ' _ > {
137+ type Item = HookTapIndex ;
138+
139+ fn next ( & mut self ) -> Option < Self :: Item > {
140+ let base_index = self . base_index as usize ;
141+ let additional_cursor = self . additional_cursor as usize ;
142+ debug_assert ! ( base_index <= self . base_stages. len( ) ) ;
143+ debug_assert ! ( additional_cursor <= self . additional_order. len( ) ) ;
144+ if base_index == self . base_stages . len ( ) && additional_cursor == self . additional_order . len ( ) {
145+ return None ;
146+ }
147+
148+ if additional_cursor == self . additional_order . len ( ) {
149+ let index = self . base_index ;
150+ debug_assert ! ( index <= HookTapIndex :: INDEX_MASK ) ;
151+ self . base_index += 1 ;
152+ return Some ( HookTapIndex :: tap ( index) ) ;
153+ }
154+
155+ if base_index == self . base_stages . len ( ) {
156+ let index = self . additional_order [ additional_cursor] ;
157+ debug_assert ! ( self . additional_cursor <= HookTapIndex :: INDEX_MASK ) ;
158+ self . additional_cursor += 1 ;
159+ return Some ( HookTapIndex :: intercept ( index) ) ;
160+ }
161+
162+ let additional_index = self . additional_order [ additional_cursor] ;
163+ if self . base_stages [ base_index] <= self . additional_stages [ additional_index as usize ] {
164+ let index = self . base_index ;
165+ debug_assert ! ( index <= HookTapIndex :: INDEX_MASK ) ;
166+ self . base_index += 1 ;
167+ Some ( HookTapIndex :: tap ( index) )
168+ } else {
169+ debug_assert ! ( self . additional_cursor <= HookTapIndex :: INDEX_MASK ) ;
170+ self . additional_cursor += 1 ;
171+ Some ( HookTapIndex :: intercept ( additional_index) )
172+ }
173+ }
174+ }
4175
5176#[ async_trait]
6177pub trait Interceptor < H : Hook > {
@@ -16,7 +187,7 @@ pub trait Interceptor<H: Hook> {
16187pub trait Hook {
17188 type Tap ;
18189
19- fn used_stages ( & self ) -> FxHashSet < i32 > ;
190+ fn used_stages ( & self ) -> Vec < i32 > ;
20191
21192 fn intercept ( & mut self , interceptor : impl Interceptor < Self > + Send + Sync + ' static )
22193 where
@@ -31,7 +202,6 @@ pub trait Hook {
31202pub mod __macro_helper {
32203 pub use async_trait:: async_trait;
33204 pub use rspack_error:: Result ;
34- pub use rustc_hash:: FxHashSet ;
35205 pub use tracing;
36206}
37207
0 commit comments