Skip to content

Commit edddae1

Browse files
committed
perf: cached source map
1 parent e82545d commit edddae1

File tree

1 file changed

+32
-24
lines changed

1 file changed

+32
-24
lines changed

src/cached_source.rs

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ struct CachedSourceOwner {
5757

5858
#[derive(Debug)]
5959
struct CachedSourceDependent<'a> {
60-
cached_colomns_map: OnceLock<Option<SourceMap<'static>>>,
61-
cached_line_only_map: OnceLock<Option<SourceMap<'static>>>,
60+
cached_colomns_map: OnceLock<Option<Cow<'static, SourceMap<'static>>>>,
61+
cached_line_only_map: OnceLock<Option<Cow<'static, SourceMap<'static>>>>,
6262
phantom: std::marker::PhantomData<&'a ()>,
6363
}
6464

@@ -116,31 +116,39 @@ impl Source for CachedSource {
116116
}
117117

118118
fn map<'a>(&'a self, options: &MapOptions) -> Option<Cow<'a, SourceMap<'a>>> {
119+
fn get_or_init_cache<'b>(
120+
owner: &'b CachedSourceOwner,
121+
cache: &'b OnceLock<Option<Cow<'static, SourceMap<'static>>>>,
122+
options: &MapOptions,
123+
) -> Option<Cow<'b, SourceMap<'b>>> {
124+
cache
125+
.get_or_init(|| {
126+
let map = owner.inner.map(options);
127+
// SAFETY: This transmute is safe because:
128+
// 1. BoxSource is an immutable wrapper around Arc<dyn Source>, ensuring the underlying
129+
// data remains stable throughout the CachedSource's lifetime
130+
// 2. The SourceMap references string data that lives in the BoxSource, which is owned
131+
// by the CachedSourceOwner and guaranteed to outlive any cached references
132+
// 3. The self_cell structure ensures that the dependent (cache) cannot outlive the
133+
// owner (BoxSource), maintaining memory safety invariants
134+
// 4. We're extending the lifetime to 'static for caching purposes, but the actual
135+
// data lifetime is managed by the self-referential structure
136+
#[allow(unsafe_code)]
137+
unsafe { std::mem::transmute::<_, Option<Cow<'static, SourceMap<'static>>>>(map) }
138+
})
139+
.as_ref()
140+
.map(|map| {
141+
Cow::Borrowed(map.as_ref())
142+
})
143+
}
144+
119145
if options.columns {
120146
self.0.with_dependent(|owner, dependent| {
121-
dependent
122-
.cached_colomns_map
123-
.get_or_init(|| {
124-
owner
125-
.inner
126-
.map(options)
127-
.map(|m| m.as_ref().clone().into_owned())
128-
})
129-
.as_ref()
130-
.map(Cow::Borrowed)
147+
get_or_init_cache(owner, &dependent.cached_colomns_map, options)
131148
})
132149
} else {
133150
self.0.with_dependent(|owner, dependent| {
134-
dependent
135-
.cached_line_only_map
136-
.get_or_init(|| {
137-
owner
138-
.inner
139-
.map(options)
140-
.map(|m| m.as_ref().clone().into_owned())
141-
})
142-
.as_ref()
143-
.map(Cow::Borrowed)
151+
get_or_init_cache(owner, &dependent.cached_line_only_map, options)
144152
})
145153
}
146154
}
@@ -187,7 +195,7 @@ impl StreamChunks for CachedSource {
187195
on_name,
188196
);
189197
dependent.cached_colomns_map.get_or_init(|| {
190-
unsafe { std::mem::transmute::<Option<SourceMap>, Option<SourceMap<'static>>>(map) }
198+
unsafe { std::mem::transmute::<Option<SourceMap>, Option<SourceMap<'static>>>(map) }.map(Cow::Owned)
191199
});
192200
generated_info
193201
})
@@ -201,7 +209,7 @@ impl StreamChunks for CachedSource {
201209
on_name,
202210
);
203211
dependent.cached_line_only_map.get_or_init(|| {
204-
unsafe { std::mem::transmute::<Option<SourceMap>, Option<SourceMap<'static>>>(map) }
212+
unsafe { std::mem::transmute::<Option<SourceMap>, Option<SourceMap<'static>>>(map) }.map(Cow::Owned)
205213
});
206214
generated_info
207215
})

0 commit comments

Comments
 (0)