@@ -13,7 +13,7 @@ use crate::{
1313 stream_chunks_of_source_map, StreamChunks ,
1414 } ,
1515 rope:: Rope ,
16- MapOptions , Source , SourceMap ,
16+ BoxSource , MapOptions , Source , SourceExt , SourceMap ,
1717} ;
1818
1919/// It tries to reused cached results from other methods to avoid calculations,
@@ -49,36 +49,60 @@ use crate::{
4949/// "Hello World\nconsole.log('test');\nconsole.log('test2');\nHello2\n"
5050/// );
5151/// ```
52- pub struct CachedSource < T > {
53- inner : Arc < T > ,
54- cached_hash : Arc < OnceLock < u64 > > ,
55- cached_maps :
56- Arc < DashMap < MapOptions , Option < SourceMap > , BuildHasherDefault < FxHasher > > > ,
52+
53+ #[ derive( Debug ) ]
54+ struct CachedSourceOwner {
55+ inner : BoxSource ,
56+ cached_hash : OnceLock < u64 > ,
57+ }
58+
59+ #[ derive( Debug ) ]
60+ struct CachedSourceDependent < ' a > {
61+ cached_colomns_map : OnceLock < Option < SourceMap < ' static > > > ,
62+ cached_line_only_map : OnceLock < Option < SourceMap < ' static > > > ,
63+ phantom : std:: marker:: PhantomData < & ' a ( ) > ,
5764}
5865
59- impl < T > CachedSource < T > {
66+ self_cell:: self_cell!(
67+ struct CachedSourceCell {
68+ owner: CachedSourceOwner ,
69+
70+ #[ covariant]
71+ dependent: CachedSourceDependent ,
72+ }
73+
74+ impl { Debug }
75+ ) ;
76+
77+ pub struct CachedSource ( CachedSourceCell ) ;
78+
79+ impl CachedSource {
6080 /// Create a [CachedSource] with the original [Source].
61- pub fn new ( inner : T ) -> Self {
62- Self {
63- inner : Arc :: new ( inner) ,
64- cached_hash : Default :: default ( ) ,
65- cached_maps : Default :: default ( ) ,
66- }
81+ pub fn new < T : SourceExt > ( inner : T ) -> Self {
82+ let owner = CachedSourceOwner {
83+ inner : inner. boxed ( ) ,
84+ cached_hash : OnceLock :: new ( ) ,
85+ } ;
86+ Self ( CachedSourceCell :: new ( owner, |_| CachedSourceDependent {
87+ cached_colomns_map : Default :: default ( ) ,
88+ cached_line_only_map : Default :: default ( ) ,
89+ phantom : std:: marker:: PhantomData ,
90+ } ) )
6791 }
6892
6993 /// Get the original [Source].
70- pub fn original ( & self ) -> & T {
71- & self . inner
94+ pub fn original ( & self ) -> & BoxSource {
95+ & self . 0 . borrow_owner ( ) . inner
7296 }
7397}
7498
75- impl < T : Source + Hash + PartialEq + Eq + ' static > Source for CachedSource < T > {
99+ impl Source for CachedSource {
76100 fn source ( & self ) -> Cow < str > {
77- self . inner . source ( )
101+ self . 0 . borrow_owner ( ) . inner . source ( )
78102 }
79103
80104 fn rope ( & self ) -> Rope < ' _ > {
81- self . inner . rope ( )
105+ self . 0 . borrow_owner ( ) . inner . rope ( )
82106 }
83107
84108 fn buffer ( & self ) -> Cow < [ u8 ] > {
@@ -88,101 +112,114 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for CachedSource<T> {
88112 }
89113
90114 fn size ( & self ) -> usize {
91- self . inner . size ( )
115+ self . 0 . borrow_owner ( ) . inner . size ( )
92116 }
93117
94118 fn map ( & self , options : & MapOptions ) -> Option < SourceMap > {
95- if let Some ( map) = self . cached_maps . get ( options) {
96- map. clone ( )
119+ if options. columns {
120+ self . 0 . with_dependent ( |owner, dependent| {
121+ dependent. cached_colomns_map . get_or_init ( || {
122+ let map = owner. inner . map ( options) ;
123+ unsafe { std:: mem:: transmute :: < Option < SourceMap > , Option < SourceMap < ' static > > > ( map) }
124+ } ) . clone ( )
125+ } )
97126 } else {
98- let map = self . inner . map ( options) ;
99- self . cached_maps . insert ( options. clone ( ) , map. clone ( ) ) ;
100- map
127+ self . 0 . with_dependent ( |owner, dependent| {
128+ dependent. cached_line_only_map . get_or_init ( || {
129+ let map = owner. inner . map ( options) ;
130+ unsafe { std:: mem:: transmute :: < Option < SourceMap > , Option < SourceMap < ' static > > > ( map) }
131+ } ) . clone ( )
132+ } )
101133 }
102134 }
103135
104136 fn to_writer ( & self , writer : & mut dyn std:: io:: Write ) -> std:: io:: Result < ( ) > {
105- self . inner . to_writer ( writer)
137+ self . 0 . borrow_owner ( ) . inner . to_writer ( writer)
106138 }
107139}
108140
109- impl < T : Source + Hash + PartialEq + Eq + ' static > StreamChunks
110- for CachedSource < T >
111- {
141+ impl StreamChunks for CachedSource {
112142 fn stream_chunks < ' a > (
113143 & ' a self ,
114144 options : & MapOptions ,
115145 on_chunk : crate :: helpers:: OnChunk < ' _ , ' a > ,
116146 on_source : crate :: helpers:: OnSource < ' _ , ' a > ,
117147 on_name : crate :: helpers:: OnName < ' _ , ' a > ,
118148 ) -> crate :: helpers:: GeneratedInfo {
119- let cached_map = self . cached_maps . entry ( options. clone ( ) ) ;
120- match cached_map {
121- Entry :: Occupied ( entry) => {
122- let source = self . rope ( ) ;
123- if let Some ( map) = entry. get ( ) {
124- #[ allow( unsafe_code) ]
125- // SAFETY: We guarantee that once a `SourceMap` is stored in the cache, it will never be removed.
126- // Therefore, even if we force its lifetime to be longer, the reference remains valid.
127- // This is based on the following assumptions:
128- // 1. `SourceMap` will be valid for the entire duration of the application.
129- // 2. The cached `SourceMap` will not be manually removed or replaced, ensuring the reference's safety.
130- let map =
131- unsafe { std:: mem:: transmute :: < & SourceMap , & ' a SourceMap > ( map) } ;
132- stream_chunks_of_source_map (
133- source, map, on_chunk, on_source, on_name, options,
134- )
135- } else {
136- stream_chunks_of_raw_source (
137- source, options, on_chunk, on_source, on_name,
138- )
139- }
149+ let cached = if options. columns {
150+ self . 0 . borrow_dependent ( ) . cached_colomns_map . get ( )
151+ } else {
152+ self . 0 . borrow_dependent ( ) . cached_line_only_map . get ( )
153+ } ;
154+ match cached {
155+ Some ( Some ( map) ) => {
156+ let source = self . 0 . borrow_owner ( ) . inner . rope ( ) ;
157+ stream_chunks_of_source_map (
158+ source, map, on_chunk, on_source, on_name, options,
159+ )
140160 }
141- Entry :: Vacant ( entry) => {
142- let ( generated_info, map) = stream_and_get_source_and_map (
143- & self . inner as & T ,
161+ Some ( None ) => {
162+ let source = self . 0 . borrow_owner ( ) . inner . rope ( ) ;
163+ stream_chunks_of_raw_source (
164+ source, options, on_chunk, on_source, on_name,
165+ )
166+ }
167+ None => {
168+ if options. columns {
169+ self . 0 . with_dependent ( |owner, dependent| {
170+ let ( generated_info, map) = stream_and_get_source_and_map (
171+ & owner. inner ,
144172 options,
145173 on_chunk,
146174 on_source,
147175 on_name,
148176 ) ;
149- entry. insert ( map) ;
177+ dependent. cached_colomns_map . get_or_init ( || {
178+ unsafe { std:: mem:: transmute :: < Option < SourceMap > , Option < SourceMap < ' static > > > ( map) }
179+ } ) ;
150180 generated_info
181+ } )
182+ } else {
183+ self . 0 . with_dependent ( |owner, dependent| {
184+ let ( generated_info, map) = stream_and_get_source_and_map (
185+ & owner. inner ,
186+ options,
187+ on_chunk,
188+ on_source,
189+ on_name,
190+ ) ;
191+ dependent. cached_line_only_map . get_or_init ( || {
192+ unsafe { std:: mem:: transmute :: < Option < SourceMap > , Option < SourceMap < ' static > > > ( map) }
193+ } ) ;
194+ generated_info
195+ } )
196+ }
151197 }
152198 }
153199 }
154200}
155201
156- impl < T > Clone for CachedSource < T > {
157- fn clone ( & self ) -> Self {
158- Self {
159- inner : self . inner . clone ( ) ,
160- cached_hash : self . cached_hash . clone ( ) ,
161- cached_maps : self . cached_maps . clone ( ) ,
162- }
163- }
164- }
165-
166- impl < T : Source + Hash + PartialEq + Eq + ' static > Hash for CachedSource < T > {
202+ impl Hash for CachedSource {
167203 fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
168- ( self . cached_hash . get_or_init ( || {
204+ let owner = self . 0 . borrow_owner ( ) ;
205+ ( owner. cached_hash . get_or_init ( || {
169206 let mut hasher = FxHasher :: default ( ) ;
170- self . inner . hash ( & mut hasher) ;
207+ owner . inner . hash ( & mut hasher) ;
171208 hasher. finish ( )
172209 } ) )
173210 . hash ( state) ;
174211 }
175212}
176213
177- impl < T : PartialEq > PartialEq for CachedSource < T > {
214+ impl PartialEq for CachedSource {
178215 fn eq ( & self , other : & Self ) -> bool {
179- self . inner == other. inner
216+ & self . 0 . borrow_owner ( ) . inner == & other. 0 . borrow_owner ( ) . inner
180217 }
181218}
182219
183- impl < T : Eq > Eq for CachedSource < T > { }
220+ impl Eq for CachedSource { }
184221
185- impl < T : std:: fmt:: Debug > std :: fmt :: Debug for CachedSource < T > {
222+ impl std:: fmt:: Debug for CachedSource {
186223 fn fmt (
187224 & self ,
188225 f : & mut std:: fmt:: Formatter < ' _ > ,
@@ -194,7 +231,7 @@ impl<T: std::fmt::Debug> std::fmt::Debug for CachedSource<T> {
194231 writeln ! (
195232 f,
196233 "{indent_str}{:indent$?}" ,
197- self . inner,
234+ self . 0 . borrow_owner ( ) . inner,
198235 indent = indent + 2
199236 ) ?;
200237 write ! ( f, "{indent_str}).boxed()" )
@@ -218,7 +255,7 @@ mod tests {
218255 value : "\n console.log(1);\n " . to_string ( ) ,
219256 name : "index.js" . to_string ( ) ,
220257 source_map : SourceMap :: new (
221- ";AACA" ,
258+ ";AACA" . into ( ) ,
222259 vec ! [ "index.js" . into( ) ] ,
223260 vec ! [ "// DELETE IT\n console.log(1)" . into( ) ] ,
224261 vec ! [ ] ,
@@ -230,25 +267,6 @@ mod tests {
230267 assert_eq ! ( map. mappings( ) , ";;AACA" ) ;
231268 }
232269
233- #[ test]
234- fn should_allow_to_store_and_share_cached_data ( ) {
235- let original = OriginalSource :: new ( "Hello World" , "test.txt" ) ;
236- let source = CachedSource :: new ( original) ;
237- let clone = source. clone ( ) ;
238-
239- // fill up cache
240- let map_options = MapOptions :: default ( ) ;
241- source. source ( ) ;
242- source. buffer ( ) ;
243- source. size ( ) ;
244- source. map ( & map_options) ;
245-
246- assert_eq ! (
247- * clone. cached_maps. get( & map_options) . unwrap( ) . value( ) ,
248- source. map( & map_options)
249- ) ;
250- }
251-
252270 #[ test]
253271 fn should_return_the_correct_size_for_binary_files ( ) {
254272 let source = OriginalSource :: new (
0 commit comments