@@ -18,7 +18,7 @@ use std::{
18
18
cell:: RefCell ,
19
19
collections:: { HashMap , VecDeque } ,
20
20
fmt,
21
- hash:: { BuildHasher , Hash , Hasher } ,
21
+ hash:: { Hash , Hasher } ,
22
22
mem:: { replace, transmute} ,
23
23
path:: Path ,
24
24
str:: FromStr ,
@@ -711,8 +711,15 @@ thread_local! {
711
711
712
712
pub struct Syntax {
713
713
layers : HopSlotMap < LayerId , LanguageLayer > ,
714
- layers_lut : RawTable < LayerId > ,
715
- layers_lut_hasher : RandomState ,
714
+ /// This table allows inverse indexing of `layers`.
715
+ /// That is by hashing a `Layer` you can find
716
+ /// the `LayerId` of an existing equivalent `Layer` in `layers`.
717
+ ///
718
+ /// This hashtable is populated inside the `update` function
719
+ /// and used to determine if a new layer exists for an injection
720
+ /// or if an existing layer needs to be updated.
721
+ layers_tabel : RawTable < LayerId > ,
722
+ layers_hasher : RandomState ,
716
723
root : LayerId ,
717
724
loader : Arc < Loader > ,
718
725
}
@@ -756,8 +763,8 @@ impl Syntax {
756
763
root,
757
764
layers,
758
765
loader,
759
- layers_lut : RawTable :: new ( ) ,
760
- layers_lut_hasher : RandomState :: new ( ) ,
766
+ layers_tabel : RawTable :: new ( ) ,
767
+ layers_hasher : RandomState :: new ( ) ,
761
768
} ;
762
769
763
770
syntax
@@ -803,11 +810,10 @@ impl Syntax {
803
810
}
804
811
}
805
812
806
- // Ensure lut is large enough to hold all layers.
807
- // The lut should always be empty at this point because it is only
808
- // kept to avoid realloctions so rehashing is never requied (hence unreachable).
809
- assert ! ( self . layers_lut. is_empty( ) ) ;
810
- self . layers_lut
813
+ self . layers_tabel . clear_no_drop ( ) ;
814
+ // Ensure table is large enough to hold all layers.
815
+ // Because the table is cleared first, rehashing is never requied (hence unreachable).
816
+ self . layers_tabel
811
817
. reserve ( self . layers . len ( ) , |_| unreachable ! ( ) ) ;
812
818
813
819
for ( layer_id, layer) in self . layers . iter_mut ( ) {
@@ -881,17 +887,12 @@ impl Syntax {
881
887
}
882
888
}
883
889
884
- let hash = hash_injection_layer (
885
- & self . layers_lut_hasher ,
886
- layer. depth ,
887
- & layer. config ,
888
- & layer. ranges ,
889
- ) ;
890
+ let hash = self . layers_hasher . hash_one ( layer) ;
890
891
// Safety: insert_no_grow is unsafe because it assumes that the table
891
892
// has enough capacity to hold additional elements.
892
893
// This is always the case as we reserved enough capacity above.
893
894
unsafe {
894
- self . layers_lut . insert_no_grow ( hash, layer_id) ;
895
+ self . layers_tabel . insert_no_grow ( hash, layer_id) ;
895
896
}
896
897
}
897
898
}
@@ -1018,31 +1019,24 @@ impl Syntax {
1018
1019
let depth = layer. depth + 1 ;
1019
1020
// TODO: can't inline this since matches borrows self.layers
1020
1021
for ( config, ranges) in injections {
1021
- // Find an existing layer
1022
+ let new_layer = LanguageLayer {
1023
+ tree : None ,
1024
+ config,
1025
+ depth,
1026
+ ranges,
1027
+ flags : LayerUpdateFlags :: empty ( ) ,
1028
+ } ;
1022
1029
1023
- let hash =
1024
- hash_injection_layer ( & self . layers_lut_hasher , depth, & config, & ranges) ;
1030
+ // Find an identical existing layer
1025
1031
let layer = self
1026
- . layers_lut
1027
- . get ( hash, |& it| {
1028
- let layer = & self . layers [ it] ;
1029
- layer. depth == depth && // TODO: track parent id instead
1030
- layer. config . language == config. language &&
1031
- layer. ranges == ranges
1032
+ . layers_tabel
1033
+ . get ( self . layers_hasher . hash_one ( & new_layer) , |& it| {
1034
+ self . layers [ it] == new_layer
1032
1035
} )
1033
1036
. copied ( ) ;
1034
1037
1035
1038
// ...or insert a new one.
1036
- let layer_id = layer. unwrap_or_else ( || {
1037
- self . layers . insert ( LanguageLayer {
1038
- tree : None ,
1039
- config,
1040
- depth,
1041
- ranges,
1042
- // set the modified flag to ensure the layer is parsed
1043
- flags : LayerUpdateFlags :: empty ( ) ,
1044
- } )
1045
- } ) ;
1039
+ let layer_id = layer. unwrap_or_else ( || self . layers . insert ( new_layer) ) ;
1046
1040
1047
1041
queue. push_back ( layer_id) ;
1048
1042
}
@@ -1060,8 +1054,6 @@ impl Syntax {
1060
1054
. contains ( LayerUpdateFlags :: TOUCHED )
1061
1055
} ) ;
1062
1056
1063
- self . layers_lut . clear_no_drop ( ) ;
1064
-
1065
1057
Ok ( ( ) )
1066
1058
} )
1067
1059
}
@@ -1181,23 +1173,32 @@ pub struct LanguageLayer {
1181
1173
flags : LayerUpdateFlags ,
1182
1174
}
1183
1175
1184
- fn hash_injection_layer (
1185
- state : & RandomState ,
1186
- depth : u32 ,
1187
- config : & HighlightConfiguration ,
1188
- ranges : & [ Range ] ,
1189
- ) -> u64 {
1190
- let mut state = state. build_hasher ( ) ;
1191
- depth. hash ( & mut state) ;
1192
- // The transmute is necessary here because tree_sitter::Language does not derive Hash at the moment.
1193
- // However it does use #[repr] transparent so the transmute here is safe
1194
- // as `Language` (which `Grammar` is an alias for) is just a newtype wrapper around a (thin) pointer.
1195
- // This is also compatible with the PartialEq implementation of language
1196
- // as that is just a pointer comparison.
1197
- let language: * const ( ) = unsafe { transmute ( config. language ) } ;
1198
- language. hash ( & mut state) ;
1199
- ranges. hash ( & mut state) ;
1200
- state. finish ( )
1176
+ /// This PartialEq implementation only checks if that
1177
+ /// two layers are theoretically identical (meaning they highlight the same text range with the same language).
1178
+ /// It does not check whether the layers have the same internal treesitter
1179
+ /// state.
1180
+ impl PartialEq for LanguageLayer {
1181
+ fn eq ( & self , other : & Self ) -> bool {
1182
+ self . depth == other. depth
1183
+ && self . config . language == other. config . language
1184
+ && self . ranges == other. ranges
1185
+ }
1186
+ }
1187
+
1188
+ /// Hash implementation belongs to PartialEq implementation above.
1189
+ /// See its documentation for details.
1190
+ impl Hash for LanguageLayer {
1191
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
1192
+ self . depth . hash ( state) ;
1193
+ // The transmute is necessary here because tree_sitter::Language does not derive Hash at the moment.
1194
+ // However it does use #[repr] transparent so the transmute here is safe
1195
+ // as `Language` (which `Grammar` is an alias for) is just a newtype wrapper around a (thin) pointer.
1196
+ // This is also compatible with the PartialEq implementation of language
1197
+ // as that is just a pointer comparison.
1198
+ let language: * const ( ) = unsafe { transmute ( self . config . language ) } ;
1199
+ language. hash ( state) ;
1200
+ self . ranges . hash ( state) ;
1201
+ }
1201
1202
}
1202
1203
1203
1204
impl LanguageLayer {
0 commit comments