Skip to content

Commit

Permalink
Implement IAsyncDisposable for XmlWriter (#35233)
Browse files Browse the repository at this point in the history
* Update XmlWriter to implement IAsyncDisposable
  • Loading branch information
buyaa-n authored Apr 28, 2020
1 parent 57a931b commit 77fab0b
Show file tree
Hide file tree
Showing 16 changed files with 549 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,8 @@ public async Task SaveAsync(Stream stream, SaveOptions options, CancellationToke
}
}

using (XmlWriter w = XmlWriter.Create(stream, ws))
XmlWriter w = XmlWriter.Create(stream, ws);
await using (w.ConfigureAwait(false))
{
await WriteToAsync(w, cancellationToken).ConfigureAwait(false);
await w.FlushAsync().ConfigureAwait(false);
Expand Down Expand Up @@ -706,7 +707,8 @@ public async Task SaveAsync(TextWriter textWriter, SaveOptions options, Cancella

ws.Async = true;

using (XmlWriter w = XmlWriter.Create(textWriter, ws))
XmlWriter w = XmlWriter.Create(textWriter, ws);
await using (w.ConfigureAwait(false))
{
await WriteToAsync(w, cancellationToken).ConfigureAwait(false);
await w.FlushAsync().ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,8 @@ public async Task SaveAsync(Stream stream, SaveOptions options, CancellationToke

ws.Async = true;

using (XmlWriter w = XmlWriter.Create(stream, ws))
XmlWriter w = XmlWriter.Create(stream, ws);
await using (w.ConfigureAwait(false))
{
await SaveAsync(w, cancellationToken).ConfigureAwait(false);
}
Expand Down Expand Up @@ -1141,7 +1142,8 @@ public async Task SaveAsync(TextWriter textWriter, SaveOptions options, Cancella

ws.Async = true;

using (XmlWriter w = XmlWriter.Create(textWriter, ws))
XmlWriter w = XmlWriter.Create(textWriter, ws);
await using (w.ConfigureAwait(false))
{
await SaveAsync(w, cancellationToken).ConfigureAwait(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,5 +202,69 @@ public static IEnumerable<object[]> RoundtripOptions_MemberData
}
}

public static IEnumerable<object[]> IsAsync_SaveOptions_Data
{
get
{
foreach (bool isAsync in new[] { true, false })
foreach (SaveOptions saveOptions in Enum.GetValues(typeof(SaveOptions)))
yield return new object[] { isAsync, saveOptions };
}
}

[Theory]
[MemberData(nameof(IsAsync_SaveOptions_Data))]
public async Task SaveAsync_CallsAsyncOnly_SaveSync_CallsSyncOnly(bool isAsync, SaveOptions saveOptions)
{
XDocument document = XDocument.Parse("<root>Test document async save</root>");
var element = new XElement("Test");
using (ForceSyncAsyncStream stream = new ForceSyncAsyncStream(isAsync))
{
if (isAsync)
{
await document.SaveAsync(stream, saveOptions, CancellationToken.None);
await element.SaveAsync(stream, saveOptions, CancellationToken.None);
}
else
{
document.Save(stream);
element.Save(stream);
}
}
}
}

public class ForceSyncAsyncStream : MemoryStream
{
private bool _isAsync;

public ForceSyncAsyncStream(bool async)
{
_isAsync = async;
}

public override void Flush()
{
Assert.False(_isAsync, "Stream is in asynchronous mode when synchronous Flush is called");
base.Flush();
}

public override Task FlushAsync(CancellationToken cancellationToken)
{
Assert.True(_isAsync, "Stream is not in asynchronous mode when asynchronous Flush is called");
return Task.CompletedTask;
}

public override void Write(byte[] buffer, int offset, int count)
{
Assert.False(_isAsync, "Stream is in asynchronous mode when synchronous Write is called");
base.Write(buffer, offset, count);
}

public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
Assert.True(_isAsync, "Stream is not in asynchronous mode when asynchronous Write is called");
return Task.CompletedTask;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,13 @@ public override Task WriteNodeAsync(XPathNavigator navigator, bool defattr)
_lastTask = task;
return task;
}

protected override ValueTask DisposeAsyncCore()
{
CheckAsync();
return _coreWriter.DisposeAsync();
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -823,8 +823,11 @@ protected virtual void FlushBuffer()
}
else
{
// Write text to TextWriter
writer.Write(bufChars, 1, bufPos - 1);
if (bufPos - 1 > 0)
{
// Write text to TextWriter
writer.Write(bufChars, 1, bufPos - 1);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,62 @@ internal override Task WriteXmlDeclarationAsync(string xmldecl)
return Task.CompletedTask;
}

protected override async ValueTask DisposeAsyncCore()
{
try
{
await FlushBufferAsync().ConfigureAwait(false);
}
finally
{
// Future calls to Close or Flush shouldn't write to Stream or Writer
writeToNull = true;

if (stream != null)
{
try
{
await stream.FlushAsync().ConfigureAwait(false);
}
finally
{
try
{
if (closeOutput)
{
await stream.DisposeAsync().ConfigureAwait(false);
}
}
finally
{
stream = null;
}
}
}
else if (writer != null)
{
try
{
await writer.FlushAsync().ConfigureAwait(false);
}
finally
{
try
{
if (closeOutput)
{
await writer.DisposeAsync().ConfigureAwait(false);
}
}
finally
{
writer = null;
}
}
}
}
}

// Serialize the document type declaration.
public override async Task WriteDocTypeAsync(string name, string pubid, string sysid, string subset)
{
Expand Down Expand Up @@ -586,8 +642,11 @@ protected virtual async Task FlushBufferAsync()
}
else
{
// Write text to TextWriter
await writer.WriteAsync(bufChars, 1, bufPos - 1).ConfigureAwait(false);
if (bufPos - 1 > 0)
{
// Write text to TextWriter
await writer.WriteAsync(bufChars, 1, bufPos - 1).ConfigureAwait(false);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -820,8 +820,11 @@ namespace System.Xml
if (!writeToNull)
{
<# if (WriterType == RawTextWriterType.Utf8) { #>
Debug.Assert(stream != null);
stream.Write(<#= BufferName #>, 1, bufPos - 1);
if (bufPos - 1 > 0)
{
Debug.Assert(stream != null);
stream.Write(<#= BufferName #>, 1, bufPos - 1);
}
<# } else { #>
Debug.Assert(stream != null || writer != null);

Expand Down Expand Up @@ -849,8 +852,11 @@ namespace System.Xml
}
else
{
// Write text to TextWriter
writer.Write(<#= BufferName #>, 1, bufPos - 1);
if (bufPos - 1 > 0)
{
// Write text to TextWriter
writer.Write(<#= BufferName #>, 1, bufPos - 1);
}
}
<# } #>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,64 @@ namespace System.Xml
return Task.CompletedTask;
}

protected override async ValueTask DisposeAsyncCore()
{
try
{
await FlushBufferAsync().ConfigureAwait(false);
}
finally
{
// Future calls to Close or Flush shouldn't write to Stream or Writer
writeToNull = true;

if (stream != null)
{
try
{
await stream.FlushAsync().ConfigureAwait(false);
}
finally
{
try
{
if (closeOutput)
{
await stream.DisposeAsync().ConfigureAwait(false);
}
}
finally
{
stream = null;
}
}
}
<# if (WriterType == RawTextWriterType.Encoded) { #>
else if (writer != null)
{
try
{
await writer.FlushAsync().ConfigureAwait(false);
}
finally
{
try
{
if (closeOutput)
{
await writer.DisposeAsync().ConfigureAwait(false);
}
}
finally
{
writer = null;
}
}
}
<# } #>
}
}

// Serialize the document type declaration.
public override async Task WriteDocTypeAsync(string name, string pubid, string sysid, string subset)
{
Expand Down Expand Up @@ -563,8 +621,11 @@ namespace System.Xml
if (!writeToNull)
{
<# if (WriterType == RawTextWriterType.Utf8) { #>
Debug.Assert(stream != null);
await stream.WriteAsync(bufBytes, 1, bufPos - 1).ConfigureAwait(false);
if (bufPos - 1 > 0)
{
Debug.Assert(stream != null);
await stream.WriteAsync(bufBytes, 1, bufPos - 1).ConfigureAwait(false);
}
<# } else { #>
Debug.Assert(stream != null || writer != null);

Expand Down Expand Up @@ -592,8 +653,11 @@ namespace System.Xml
}
else
{
// Write text to TextWriter
await writer.WriteAsync(<#= BufferName #>, 1, bufPos - 1).ConfigureAwait(false);
if (bufPos - 1 > 0)
{
// Write text to TextWriter
await writer.WriteAsync(<#= BufferName #>, 1, bufPos - 1).ConfigureAwait(false);
}
}
<# } #>
}
Expand Down Expand Up @@ -689,7 +753,7 @@ namespace System.Xml
<#= BufferType #>* pDst = pDstBegin + bufPos;

int ch = 0;
for (;;)
while (true)
{
<#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc);
if (pDstEnd > pDstBegin + bufLen)
Expand Down Expand Up @@ -879,7 +943,7 @@ namespace System.Xml
<#= BufferType #>* pDst = pDstBegin + bufPos;

int ch = 0;
for (;;)
while (true)
{
<#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc);
if (pDstEnd > pDstBegin + bufLen)
Expand Down Expand Up @@ -1105,7 +1169,7 @@ namespace System.Xml
char* pSrc = pSrcBegin;

int ch = 0;
for (;;)
while (true)
{
<#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc);
if (pDstEnd > pDstBegin + bufLen)
Expand Down Expand Up @@ -1266,7 +1330,7 @@ namespace System.Xml
<#= BufferType #>* pDst = pDstBegin + bufPos;

int ch = 0;
for (;;)
while (true)
{
<#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc);
if (pDstEnd > pDstBegin + bufLen)
Expand Down Expand Up @@ -1454,7 +1518,7 @@ namespace System.Xml
<#= BufferType #>* pDst = pDstBegin + bufPos;

int ch = 0;
for (;;)
while (true)
{
<#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc);
if (pDstEnd > pDstBegin + bufLen)
Expand Down Expand Up @@ -1630,7 +1694,7 @@ namespace System.Xml
<#= BufferType #>* pDst = pDstBegin + bufPos;

int ch = 0;
for (;;)
while (true)
{
<#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc);
if (pDstEnd > pDstBegin + bufLen)
Expand Down
Loading

0 comments on commit 77fab0b

Please sign in to comment.