@@ -4,7 +4,7 @@ use std::{
44 sync:: { Arc , OnceLock } ,
55} ;
66
7- use dashmap:: DashMap ;
7+ use dashmap:: { mapref :: entry :: Entry , DashMap } ;
88use rustc_hash:: FxHasher ;
99
1010use crate :: {
@@ -50,8 +50,9 @@ use crate::{
5050/// ```
5151pub struct CachedSource < T > {
5252 inner : Arc < T > ,
53- cached_buffer : OnceLock < Arc < Vec < u8 > > > ,
54- cached_source : OnceLock < Arc < str > > ,
53+ cached_buffer : Arc < OnceLock < Vec < u8 > > > ,
54+ cached_source : Arc < OnceLock < Arc < str > > > ,
55+ cached_size : Arc < OnceLock < usize > > ,
5556 cached_maps :
5657 Arc < DashMap < MapOptions , Option < SourceMap > , BuildHasherDefault < FxHasher > > > ,
5758}
@@ -63,6 +64,7 @@ impl<T> CachedSource<T> {
6364 inner : Arc :: new ( inner) ,
6465 cached_buffer : Default :: default ( ) ,
6566 cached_source : Default :: default ( ) ,
67+ cached_size : Default :: default ( ) ,
6668 cached_maps : Default :: default ( ) ,
6769 }
6870 }
@@ -82,14 +84,25 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for CachedSource<T> {
8284 }
8385
8486 fn buffer ( & self ) -> Cow < [ u8 ] > {
85- let cached = self
86- . cached_buffer
87- . get_or_init ( || self . inner . buffer ( ) . to_vec ( ) . into ( ) ) ;
87+ let cached = self . cached_buffer . get_or_init ( || {
88+ let source = self . cached_source . get ( ) ;
89+ match source {
90+ Some ( source) => source. as_bytes ( ) . to_vec ( ) ,
91+ None => self . inner . buffer ( ) . to_vec ( ) ,
92+ }
93+ } ) ;
8894 Cow :: Borrowed ( cached)
8995 }
9096
9197 fn size ( & self ) -> usize {
92- self . inner . size ( )
98+ let cached = self . cached_size . get_or_init ( || {
99+ let source = self . cached_source . get ( ) ;
100+ match source {
101+ Some ( source) => source. len ( ) ,
102+ None => self . inner . size ( ) ,
103+ }
104+ } ) ;
105+ * cached
93106 }
94107
95108 fn map ( & self , options : & MapOptions ) -> Option < SourceMap > {
@@ -117,27 +130,32 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> StreamChunks
117130 on_source : crate :: helpers:: OnSource ,
118131 on_name : crate :: helpers:: OnName ,
119132 ) -> crate :: helpers:: GeneratedInfo {
120- if self . cached_maps . contains_key ( options) {
121- let source = self . source ( ) ;
122- if let Some ( map) = & self . map ( options) {
123- return stream_chunks_of_source_map (
124- & source, map, on_chunk, on_source, on_name, options,
125- ) ;
126- } else {
127- return stream_chunks_of_raw_source (
128- & source, options, on_chunk, on_source, on_name,
133+ let cached_map = self . cached_maps . entry ( options. clone ( ) ) ;
134+ match cached_map {
135+ Entry :: Occupied ( entry) => {
136+ let source = self . source ( ) ;
137+ if let Some ( map) = entry. get ( ) {
138+ stream_chunks_of_source_map (
139+ & source, map, on_chunk, on_source, on_name, options,
140+ )
141+ } else {
142+ stream_chunks_of_raw_source (
143+ & source, options, on_chunk, on_source, on_name,
144+ )
145+ }
146+ }
147+ Entry :: Vacant ( entry) => {
148+ let ( generated_info, map) = stream_and_get_source_and_map (
149+ self . original ( ) ,
150+ options,
151+ on_chunk,
152+ on_source,
153+ on_name,
129154 ) ;
155+ entry. insert ( map) ;
156+ generated_info
130157 }
131158 }
132- let ( generated_info, map) = stream_and_get_source_and_map (
133- self . original ( ) ,
134- options,
135- on_chunk,
136- on_source,
137- on_name,
138- ) ;
139- self . cached_maps . insert ( options. clone ( ) , map) ;
140- generated_info
141159 }
142160}
143161
@@ -147,6 +165,7 @@ impl<T: Source> Clone for CachedSource<T> {
147165 inner : self . inner . clone ( ) ,
148166 cached_buffer : self . cached_buffer . clone ( ) ,
149167 cached_source : self . cached_source . clone ( ) ,
168+ cached_size : self . cached_size . clone ( ) ,
150169 cached_maps : self . cached_maps . clone ( ) ,
151170 }
152171 }
@@ -182,8 +201,11 @@ impl<T: std::fmt::Debug> std::fmt::Debug for CachedSource<T> {
182201
183202#[ cfg( test) ]
184203mod tests {
204+ use std:: borrow:: Borrow ;
205+
185206 use crate :: {
186- ConcatSource , RawSource , SourceExt , SourceMapSource , WithoutOriginalOptions ,
207+ ConcatSource , OriginalSource , RawSource , SourceExt , SourceMapSource ,
208+ WithoutOriginalOptions ,
187209 } ;
188210
189211 use super :: * ;
@@ -208,4 +230,127 @@ mod tests {
208230 let map = source. map ( & Default :: default ( ) ) . unwrap ( ) ;
209231 assert_eq ! ( map. mappings( ) , ";;AACA" ) ;
210232 }
233+
234+ #[ test]
235+ fn should_allow_to_store_and_share_cached_data ( ) {
236+ let original = OriginalSource :: new ( "Hello World" , "test.txt" ) ;
237+ let source = CachedSource :: new ( original) ;
238+ let clone = source. clone ( ) ;
239+
240+ // fill up cache
241+ let map_options = MapOptions :: default ( ) ;
242+ source. source ( ) ;
243+ source. buffer ( ) ;
244+ source. size ( ) ;
245+ source. map ( & map_options) ;
246+
247+ assert_eq ! ( clone. cached_source. get( ) . unwrap( ) . borrow( ) , source. source( ) ) ;
248+ assert_eq ! (
249+ * clone. cached_buffer. get( ) . unwrap( ) ,
250+ source. buffer( ) . to_vec( )
251+ ) ;
252+ assert_eq ! ( * clone. cached_size. get( ) . unwrap( ) , source. size( ) ) ;
253+ assert_eq ! (
254+ * clone. cached_maps. get( & map_options) . unwrap( ) . value( ) ,
255+ source. map( & map_options)
256+ ) ;
257+ }
258+
259+ #[ test]
260+ fn should_return_the_correct_size_for_binary_files ( ) {
261+ let source = OriginalSource :: new (
262+ String :: from_utf8 ( vec ! [ 0 ; 256 ] ) . unwrap ( ) ,
263+ "file.wasm" ,
264+ ) ;
265+ let cached_source = CachedSource :: new ( source) ;
266+
267+ assert_eq ! ( cached_source. size( ) , 256 ) ;
268+ assert_eq ! ( cached_source. size( ) , 256 ) ;
269+ }
270+
271+ #[ test]
272+ fn should_return_the_correct_size_for_cached_binary_files ( ) {
273+ let source = OriginalSource :: new (
274+ String :: from_utf8 ( vec ! [ 0 ; 256 ] ) . unwrap ( ) ,
275+ "file.wasm" ,
276+ ) ;
277+ let cached_source = CachedSource :: new ( source) ;
278+
279+ cached_source. source ( ) ;
280+ assert_eq ! ( cached_source. size( ) , 256 ) ;
281+ assert_eq ! ( cached_source. size( ) , 256 ) ;
282+ }
283+
284+ #[ test]
285+ fn should_return_the_correct_size_for_text_files ( ) {
286+ let source = OriginalSource :: new ( "TestTestTest" , "file.js" ) ;
287+ let cached_source = CachedSource :: new ( source) ;
288+
289+ assert_eq ! ( cached_source. size( ) , 12 ) ;
290+ assert_eq ! ( cached_source. size( ) , 12 ) ;
291+ }
292+
293+ #[ test]
294+ fn should_return_the_correct_size_for_cached_text_files ( ) {
295+ let source = OriginalSource :: new ( "TestTestTest" , "file.js" ) ;
296+ let cached_source = CachedSource :: new ( source) ;
297+
298+ cached_source. source ( ) ;
299+ assert_eq ! ( cached_source. size( ) , 12 ) ;
300+ assert_eq ! ( cached_source. size( ) , 12 ) ;
301+ }
302+
303+ #[ test]
304+ fn should_produce_correct_output_for_cached_raw_source ( ) {
305+ let map_options = MapOptions {
306+ columns : true ,
307+ final_source : true ,
308+ } ;
309+
310+ let source = RawSource :: from ( "Test\n Test\n Test\n " ) ;
311+ let mut on_chunk_count = 0 ;
312+ let mut on_source_count = 0 ;
313+ let mut on_name_count = 0 ;
314+ let generated_info = source. stream_chunks (
315+ & map_options,
316+ & mut |_chunk, _mapping| {
317+ on_chunk_count += 1 ;
318+ } ,
319+ & mut |_source_index, _source, _source_content| {
320+ on_source_count += 1 ;
321+ } ,
322+ & mut |_name_index, _name| {
323+ on_name_count += 1 ;
324+ } ,
325+ ) ;
326+
327+ let cached_source = CachedSource :: new ( source) ;
328+ cached_source. stream_chunks (
329+ & map_options,
330+ & mut |_chunk, _mapping| { } ,
331+ & mut |_source_index, _source, _source_content| { } ,
332+ & mut |_name_index, _name| { } ,
333+ ) ;
334+
335+ let mut cached_on_chunk_count = 0 ;
336+ let mut cached_on_source_count = 0 ;
337+ let mut cached_on_name_count = 0 ;
338+ let cached_generated_info = cached_source. stream_chunks (
339+ & map_options,
340+ & mut |_chunk, _mapping| {
341+ cached_on_chunk_count += 1 ;
342+ } ,
343+ & mut |_source_index, _source, _source_content| {
344+ cached_on_source_count += 1 ;
345+ } ,
346+ & mut |_name_index, _name| {
347+ cached_on_name_count += 1 ;
348+ } ,
349+ ) ;
350+
351+ assert_eq ! ( on_chunk_count, cached_on_chunk_count) ;
352+ assert_eq ! ( on_source_count, cached_on_source_count) ;
353+ assert_eq ! ( on_name_count, cached_on_name_count) ;
354+ assert_eq ! ( generated_info, cached_generated_info) ;
355+ }
211356}
0 commit comments