Skip to content

Commit 23ac553

Browse files
committed
perf: write_to_string
1 parent 4b7e115 commit 23ac553

File tree

8 files changed

+54
-2
lines changed

8 files changed

+54
-2
lines changed

src/cached_source.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ impl Source for CachedSource {
128128
}
129129
}
130130

131+
fn write_to_string(&self, string: &mut String) {
132+
self.inner.write_to_string(string);
133+
}
134+
131135
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
132136
self.inner.to_writer(writer)
133137
}

src/concat_source.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,11 @@ impl Source for ConcatSource {
167167
if children.len() == 1 {
168168
children[0].source()
169169
} else {
170-
SourceValue::String(Cow::Owned(self.rope().join("")))
170+
// Use to_writer to avoid multiple heap allocations that would occur
171+
// when concatenating nested ConcatSource instances directly
172+
let mut string = String::with_capacity(self.size());
173+
self.write_to_string(&mut string);
174+
SourceValue::String(Cow::Owned(string))
171175
}
172176
}
173177

@@ -214,6 +218,12 @@ impl Source for ConcatSource {
214218
result
215219
}
216220

221+
fn write_to_string(&self, string: &mut String) {
222+
for child in self.optimized_children() {
223+
child.write_to_string(string);
224+
}
225+
}
226+
217227
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
218228
for child in self.optimized_children() {
219229
child.to_writer(writer)?;

src/original_source.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ impl Source for OriginalSource {
7777
get_map(object_pool, chunks.as_ref(), options)
7878
}
7979

80+
fn write_to_string(&self, string: &mut String) {
81+
string.push_str(self.value.as_ref());
82+
}
83+
8084
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
8185
writer.write_all(self.value.as_bytes())
8286
}

src/raw_source.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ impl Source for RawStringSource {
8080
None
8181
}
8282

83+
fn write_to_string(&self, string: &mut String) {
84+
string.push_str(self.0.as_ref());
85+
}
86+
8387
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
8488
writer.write_all(self.0.as_bytes())
8589
}
@@ -226,6 +230,10 @@ impl Source for RawBufferSource {
226230
None
227231
}
228232

233+
fn write_to_string(&self, string: &mut String) {
234+
string.push_str(self.get_or_init_value_as_string());
235+
}
236+
229237
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
230238
writer.write_all(&self.value)
231239
}

src/replace_source.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ impl Source for ReplaceSource {
181181
< self.replacements.len())
182182
.then(|| self.replacements[replacement_idx].start as usize);
183183

184-
'chunk_loop: for chunk in self.inner.rope() {
184+
'chunk_loop: for chunk in inner_rope {
185185
let mut chunk_pos = 0;
186186
let end_pos = pos + chunk.len();
187187

@@ -323,6 +323,12 @@ impl Source for ReplaceSource {
323323
get_map(&ObjectPool::default(), chunks.as_ref(), options)
324324
}
325325

326+
fn write_to_string(&self, string: &mut String) {
327+
for chunk in self.rope() {
328+
string.push_str(chunk);
329+
}
330+
}
331+
326332
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
327333
for text in self.rope() {
328334
writer.write_all(text.as_bytes())?;

src/source.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ pub trait Source:
135135
self.dyn_hash(state);
136136
}
137137

138+
/// Appends the source content to the provided string buffer.
139+
///
140+
/// This method efficiently writes the source content directly into an existing
141+
/// string buffer, avoiding additional memory allocations when the buffer has
142+
/// sufficient capacity. This is particularly useful for concatenating multiple
143+
/// sources or building larger strings incrementally.
144+
fn write_to_string(&self, string: &mut String);
145+
138146
/// Writes the source into a writer, preferably a `std::io::BufWriter<std::io::Write>`.
139147
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()>;
140148
}
@@ -164,6 +172,10 @@ impl Source for BoxSource {
164172
self.as_ref().map(object_pool, options)
165173
}
166174

175+
fn write_to_string(&self, string: &mut String) {
176+
self.as_ref().write_to_string(string)
177+
}
178+
167179
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
168180
self.as_ref().to_writer(writer)
169181
}

src/source_map_source.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ impl Source for SourceMapSource {
118118
get_map(object_pool, chunks.as_ref(), options)
119119
}
120120

121+
fn write_to_string(&self, string: &mut String) {
122+
string.push_str(self.value.as_ref());
123+
}
124+
121125
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
122126
writer.write_all(self.value.as_bytes())
123127
}

tests/compat_source.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ impl Source for CompatSource {
3939
self.1.clone()
4040
}
4141

42+
fn write_to_string(&self, string: &mut String) {
43+
string.push_str(self.0.as_ref())
44+
}
45+
4246
fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
4347
writer.write_all(self.0.as_bytes())
4448
}

0 commit comments

Comments
 (0)