Skip to content

Commit 0055d1d

Browse files
committed
add TextWriter WriteAsync and Write for StringBuilder
1 parent 44de6a4 commit 0055d1d

File tree

4 files changed

+142
-3
lines changed

4 files changed

+142
-3
lines changed

contributing.md

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,12 @@ Example:
189189
// <auto-generated />
190190
#pragma warning disable
191191

192-
#if FeatureMemory && (NETFRAMEWORK || NETSTANDARD2_0 || NETCOREAPP2_0)
192+
#if FeatureMemory
193193

194194
namespace Polyfills;
195+
195196
using System;
197+
using System.Text;
196198
using System.Buffers;
197199
using System.IO;
198200
using System.Runtime.InteropServices;
@@ -202,6 +204,56 @@ using System.Threading.Tasks;
202204

203205
static partial class Polyfill
204206
{
207+
#if !NETCOREAPP3_0_OR_GREATER
208+
/// <summary>
209+
/// Equivalent to Write(stringBuilder.ToString()) however it uses the
210+
/// StringBuilder.GetChunks() method to avoid creating the intermediate string
211+
/// </summary>
212+
/// <param name="value">The string (as a StringBuilder) to write to the stream</param>
213+
[Link("https://learn.microsoft.com/en-us/dotnet/api/system.io.textwriter.write#system-io-textwriter-write(system-text-stringbuilder)")]
214+
public static void Write(this TextWriter target, StringBuilder? value)
215+
{
216+
if (value != null)
217+
{
218+
foreach (ReadOnlyMemory<char> chunk in value.GetChunks())
219+
{
220+
target.Write(chunk.Span);
221+
}
222+
}
223+
}
224+
225+
/// <summary>
226+
/// Equivalent to WriteAsync(stringBuilder.ToString()) however it uses the
227+
/// StringBuilder.GetChunks() method to avoid creating the intermediate string
228+
/// </summary>
229+
/// <param name="value">The string (as a StringBuilder) to write to the stream</param>
230+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
231+
[Link("https://learn.microsoft.com/en-us/dotnet/api/system.io.textwriter.writeasync#system-io-textwriter-writeasync(system-readonlymemory((system-char))-system-threading-cancellationtoken)")]
232+
public static Task WriteAsync(this TextWriter target, StringBuilder? value, CancellationToken cancellationToken = default)
233+
{
234+
if (cancellationToken.IsCancellationRequested)
235+
{
236+
return Task.FromCanceled(cancellationToken);
237+
}
238+
239+
if (value == null)
240+
{
241+
return Task.CompletedTask;
242+
}
243+
244+
return WriteAsyncCore(value, cancellationToken);
245+
246+
async Task WriteAsyncCore(StringBuilder builder, CancellationToken cancel)
247+
{
248+
foreach (ReadOnlyMemory<char> chunk in builder.GetChunks())
249+
{
250+
await target.WriteAsync(chunk, cancel).ConfigureAwait(false);
251+
}
252+
}
253+
}
254+
#endif
255+
256+
#if NETFRAMEWORK || NETSTANDARD2_0 || NETCOREAPP2_0
205257
#if FeatureValueTask
206258

207259
/// <summary>
@@ -303,10 +355,11 @@ static partial class Polyfill
303355
pool.Return(array);
304356
}
305357
}
358+
#endif
306359
}
307360
#endif
308361
```
309-
<sup><a href='/src/Polyfill/Polyfill_TextWriter.cs#L1-L119' title='Snippet source file'>snippet source</a> | <a href='#snippet-Polyfill_TextWriter.cs' title='Start of snippet'>anchor</a></sup>
362+
<sup><a href='/src/Polyfill/Polyfill_TextWriter.cs#L1-L172' title='Snippet source file'>snippet source</a> | <a href='#snippet-Polyfill_TextWriter.cs' title='Start of snippet'>anchor</a></sup>
310363
<!-- endSnippet -->
311364

312365

src/Consume/Consume.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,17 @@ void NonGenericTaskCompletionSource()
482482
}
483483

484484
#if FeatureMemory
485+
async Task TextWriter()
486+
{
487+
TextWriter target = new StringWriter();
488+
target.Write(new StringBuilder());
489+
target.WriteAsync(new StringBuilder());
490+
target.WriteLine("a".AsSpan());
491+
await target.WriteLineAsync("a".AsMemory());
492+
target.Write("a".AsSpan());
493+
await target.WriteAsync("a".AsMemory());
494+
}
495+
485496
void RandomNextBytesSpan()
486497
{
487498
var random = new Random();

src/Polyfill/Polyfill_TextWriter.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// <auto-generated />
22
#pragma warning disable
33

4-
#if FeatureMemory && (NETFRAMEWORK || NETSTANDARD2_0 || NETCOREAPP2_0)
4+
#if FeatureMemory
55

66
namespace Polyfills;
7+
78
using System;
9+
using System.Text;
810
using System.Buffers;
911
using System.IO;
1012
using System.Runtime.InteropServices;
@@ -14,6 +16,56 @@ namespace Polyfills;
1416

1517
static partial class Polyfill
1618
{
19+
#if !NETCOREAPP3_0_OR_GREATER
20+
/// <summary>
21+
/// Equivalent to Write(stringBuilder.ToString()) however it uses the
22+
/// StringBuilder.GetChunks() method to avoid creating the intermediate string
23+
/// </summary>
24+
/// <param name="value">The string (as a StringBuilder) to write to the stream</param>
25+
[Link("https://learn.microsoft.com/en-us/dotnet/api/system.io.textwriter.write#system-io-textwriter-write(system-text-stringbuilder)")]
26+
public static void Write(this TextWriter target, StringBuilder? value)
27+
{
28+
if (value != null)
29+
{
30+
foreach (ReadOnlyMemory<char> chunk in value.GetChunks())
31+
{
32+
target.Write(chunk.Span);
33+
}
34+
}
35+
}
36+
37+
/// <summary>
38+
/// Equivalent to WriteAsync(stringBuilder.ToString()) however it uses the
39+
/// StringBuilder.GetChunks() method to avoid creating the intermediate string
40+
/// </summary>
41+
/// <param name="value">The string (as a StringBuilder) to write to the stream</param>
42+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
43+
[Link("https://learn.microsoft.com/en-us/dotnet/api/system.io.textwriter.writeasync#system-io-textwriter-writeasync(system-readonlymemory((system-char))-system-threading-cancellationtoken)")]
44+
public static Task WriteAsync(this TextWriter target, StringBuilder? value, CancellationToken cancellationToken = default)
45+
{
46+
if (cancellationToken.IsCancellationRequested)
47+
{
48+
return Task.FromCanceled(cancellationToken);
49+
}
50+
51+
if (value == null)
52+
{
53+
return Task.CompletedTask;
54+
}
55+
56+
return WriteAsyncCore(value, cancellationToken);
57+
58+
async Task WriteAsyncCore(StringBuilder builder, CancellationToken cancel)
59+
{
60+
foreach (ReadOnlyMemory<char> chunk in builder.GetChunks())
61+
{
62+
await target.WriteAsync(chunk, cancel).ConfigureAwait(false);
63+
}
64+
}
65+
}
66+
#endif
67+
68+
#if NETFRAMEWORK || NETSTANDARD2_0 || NETCOREAPP2_0
1769
#if FeatureValueTask
1870

1971
/// <summary>
@@ -115,5 +167,6 @@ public static void WriteLine(
115167
pool.Return(array);
116168
}
117169
}
170+
#endif
118171
}
119172
#endif

src/Tests/PolyfillTests_TextWriter.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@ public async Task TextWriterWriteSpan()
1111
Assert.AreEqual("value", s);
1212
}
1313

14+
[Test]
15+
public async Task TextWriterWriteStringBuilder()
16+
{
17+
using var stream = new MemoryStream();
18+
using var writer = new StreamWriter(stream);
19+
writer.Write(new StringBuilder("value"));
20+
await writer.FlushAsync();
21+
var s = Encoding.UTF8.GetString(stream.ToArray());
22+
Assert.AreEqual("value", s);
23+
}
24+
25+
[Test]
26+
public async Task TextWriterWriteStringBuilderAsync()
27+
{
28+
using var stream = new MemoryStream();
29+
using var writer = new StreamWriter(stream);
30+
await writer.WriteAsync(new StringBuilder("value"));
31+
await writer.FlushAsync();
32+
var s = Encoding.UTF8.GetString(stream.ToArray());
33+
Assert.AreEqual("value", s);
34+
}
35+
1436
[Test]
1537
public async Task TextWriterWriteLineSpan()
1638
{

0 commit comments

Comments
 (0)