diff --git a/Fluid.Tests/Domain/WithInterfaces/PetValue.cs b/Fluid.Tests/Domain/WithInterfaces/PetValue.cs
index 0df45163..ee0ae2ed 100644
--- a/Fluid.Tests/Domain/WithInterfaces/PetValue.cs
+++ b/Fluid.Tests/Domain/WithInterfaces/PetValue.cs
@@ -3,6 +3,7 @@
using System.Globalization;
using System.IO;
using System.Text.Encodings.Web;
+using System.Threading.Tasks;
namespace Fluid.Tests.Domain.WithInterfaces
{
@@ -42,11 +43,17 @@ public override string ToStringValue()
throw new NotImplementedException();
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
throw new NotImplementedException();
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ throw new NotImplementedException();
+ }
+
protected override FluidValue GetValue(string name, TemplateContext context)
{
if (name == "Name")
diff --git a/Fluid.Tests/MvcViewEngine/NoSyncStream.cs b/Fluid.Tests/MvcViewEngine/NoSyncStream.cs
new file mode 100644
index 00000000..a826714e
--- /dev/null
+++ b/Fluid.Tests/MvcViewEngine/NoSyncStream.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Fluid.Tests.MvcViewEngine
+{
+ ///
+ /// Stream implementation that prevents non-async usages.
+ ///
+ public sealed class NoSyncStream : Stream
+ {
+ public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => Task.CompletedTask;
+ public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) => ValueTask.CompletedTask;
+
+
+ public override void Flush() => throw new InvalidOperationException();
+ public override int Read(byte[] buffer, int offset, int count) => throw new InvalidOperationException();
+ public override long Seek(long offset, SeekOrigin origin) => throw new InvalidOperationException();
+ public override void SetLength(long value) => throw new InvalidOperationException();
+ public override void Write(byte[] buffer, int offset, int count) => throw new InvalidOperationException();
+
+ public override bool CanRead { get; } = false;
+ public override bool CanSeek { get; } = false;
+ public override bool CanWrite { get; } = true;
+ public override long Length { get; }
+ public override long Position { get; set; }
+ }
+}
diff --git a/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs b/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs
index d9b999bd..94494012 100644
--- a/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs
+++ b/Fluid.Tests/MvcViewEngine/ViewEngineTests.cs
@@ -1,6 +1,7 @@
using Fluid.Tests.Mocks;
using Fluid.ViewEngine;
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using Xunit;
@@ -278,5 +279,29 @@ public async Task LayoutShouldBeAbleToIncludeVarsFromViewStart()
Assert.Equal("[TITLE][SUBTITLE][ViewStart][View]", sw.ToString());
}
+
+ [Fact]
+ public async Task RenderViewOnlyAsyncStream_LargePropertyValue_Nested_SmallBuffer_BiggerThan128LengthString()
+ {
+ _mockFileProvider.Add("Views/Index.liquid", "{% layout '_Layout' %}{% section bigboy %}{{BigString}}{% endsection %} ");
+ _mockFileProvider.Add("Views/_Layout.liquid", "{% rendersection bigboy %}");
+
+ await using var sw = new StreamWriter(new NoSyncStream(), bufferSize: 10);
+ var template = new TemplateContext(new { BigString = new string(Enumerable.Range(0, 129).Select(x => 'b').ToArray()) });
+ await _renderer.RenderViewAsync(sw, "Index.liquid", template);
+ await sw.FlushAsync();
+ }
+
+ [Fact]
+ public async Task RenderViewOnlyAsyncStream_LargePropertyValue_Nested()
+ {
+ _mockFileProvider.Add("Views/Index.liquid", "{% layout '_Layout' %}{% section bigboy %}{{BigString}}{% endsection %} ");
+ _mockFileProvider.Add("Views/_Layout.liquid", "{% rendersection bigboy %}");
+
+ await using var sw = new StreamWriter(new NoSyncStream());
+ var template = new TemplateContext(new { BigString = new string(Enumerable.Range(0, 1500).Select(_ => 'b').ToArray()) });
+ await _renderer.RenderViewAsync(sw, "Index.liquid", template);
+ await sw.FlushAsync();
+ }
}
}
diff --git a/Fluid/Ast/CycleStatement.cs b/Fluid/Ast/CycleStatement.cs
index 3be3d7e9..1d34c755 100644
--- a/Fluid/Ast/CycleStatement.cs
+++ b/Fluid/Ast/CycleStatement.cs
@@ -32,7 +32,7 @@ public override async ValueTask WriteToAsync(TextWriter writer, Text
var value = await Values[(int)index].EvaluateAsync(context);
context.SetValue(groupValue, NumberValue.Create(index + 1));
- value.WriteTo(writer, encoder, context.CultureInfo);
+ await value.WriteToAsync(writer, encoder, context.CultureInfo);
return Completion.Normal;
}
diff --git a/Fluid/Ast/DecrementStatement.cs b/Fluid/Ast/DecrementStatement.cs
index 9479014c..03150933 100644
--- a/Fluid/Ast/DecrementStatement.cs
+++ b/Fluid/Ast/DecrementStatement.cs
@@ -12,7 +12,7 @@ public DecrementStatement(string identifier)
public string Identifier { get; }
- public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
+ public override async ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
{
context.IncrementSteps();
@@ -35,9 +35,9 @@ public override ValueTask WriteToAsync(TextWriter writer, TextEncode
context.SetValue(prefixedIdentifier, value);
- value.WriteTo(writer, encoder, context.CultureInfo);
+ await value.WriteToAsync(writer, encoder, context.CultureInfo);
- return Normal();
+ return Completion.Normal;
}
protected internal override Statement Accept(AstVisitor visitor) => visitor.VisitDecrementStatement(this);
diff --git a/Fluid/Ast/IncrementStatement.cs b/Fluid/Ast/IncrementStatement.cs
index 295e52b2..e8551302 100644
--- a/Fluid/Ast/IncrementStatement.cs
+++ b/Fluid/Ast/IncrementStatement.cs
@@ -36,9 +36,20 @@ public override ValueTask WriteToAsync(TextWriter writer, TextEncode
context.SetValue(prefixedIdentifier, value);
- value.WriteTo(writer, encoder, context.CultureInfo);
+ var task = value.WriteToAsync(writer, encoder, context.CultureInfo);
- return Normal();
+ if (task.IsCompletedSuccessfully)
+ {
+ return new ValueTask(Completion.Normal);
+ }
+
+ return Awaited(task);
+
+ static async ValueTask Awaited(ValueTask t)
+ {
+ await t;
+ return Completion.Normal;
+ }
}
protected internal override Statement Accept(AstVisitor visitor) => visitor.VisitIncrementStatement(this);
diff --git a/Fluid/Ast/OutputStatement.cs b/Fluid/Ast/OutputStatement.cs
index 98be5a96..86e402da 100644
--- a/Fluid/Ast/OutputStatement.cs
+++ b/Fluid/Ast/OutputStatement.cs
@@ -23,7 +23,7 @@ static async ValueTask Awaited(
TemplateContext ctx)
{
var value = await t;
- value.WriteTo(w, enc, ctx.CultureInfo);
+ await value.WriteToAsync(w, enc, ctx.CultureInfo);
return Completion.Normal;
}
@@ -32,8 +32,20 @@ static async ValueTask Awaited(
var task = Expression.EvaluateAsync(context);
if (task.IsCompletedSuccessfully)
{
- task.Result.WriteTo(writer, encoder, context.CultureInfo);
- return new ValueTask(Completion.Normal);
+ var valueTask = task.Result.WriteToAsync(writer, encoder, context.CultureInfo);
+
+ if (valueTask.IsCompletedSuccessfully)
+ {
+ return new ValueTask(Completion.Normal);
+ }
+
+ return AwaitedWriteTo(valueTask);
+
+ static async ValueTask AwaitedWriteTo(ValueTask t)
+ {
+ await t;
+ return Completion.Normal;
+ }
}
return Awaited(task, writer, encoder, context);
diff --git a/Fluid/Values/ArrayValue.cs b/Fluid/Values/ArrayValue.cs
index 3ef598bf..030f695d 100644
--- a/Fluid/Values/ArrayValue.cs
+++ b/Fluid/Values/ArrayValue.cs
@@ -99,6 +99,7 @@ public override decimal ToNumberValue()
public IReadOnlyList Values { get; }
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
AssertWriteToParameters(writer, encoder, cultureInfo);
@@ -109,6 +110,16 @@ public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo
}
}
+ public override async ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ AssertWriteToParameters(writer, encoder, cultureInfo);
+
+ foreach (var v in Values)
+ {
+ await writer.WriteAsync(v.ToStringValue());
+ }
+ }
+
public override string ToStringValue()
{
return String.Join("", Values.Select(x => x.ToStringValue()));
diff --git a/Fluid/Values/BlankValue.cs b/Fluid/Values/BlankValue.cs
index a0963cd9..3710e275 100644
--- a/Fluid/Values/BlankValue.cs
+++ b/Fluid/Values/BlankValue.cs
@@ -50,10 +50,16 @@ public override bool IsNil()
return true;
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ return default;
+ }
+
public override bool Equals(object obj)
{
// The is operator will return false if null
diff --git a/Fluid/Values/BooleanValue.cs b/Fluid/Values/BooleanValue.cs
index ad40cf47..4f2711d5 100644
--- a/Fluid/Values/BooleanValue.cs
+++ b/Fluid/Values/BooleanValue.cs
@@ -1,4 +1,5 @@
-using System.Globalization;
+using Fluid.Utils;
+using System.Globalization;
using System.Text.Encodings.Web;
namespace Fluid.Values
@@ -28,7 +29,7 @@ public static BooleanValue Create(bool value)
public override bool Equals(FluidValue other)
{
// blank == false -> true
- if (other.Type == FluidValues.Blank) return _value == false;
+ if (other.Type == FluidValues.Blank) return !_value;
return _value == other.ToBooleanValue();
}
@@ -48,12 +49,32 @@ public override string ToStringValue()
return _value ? "true" : "false";
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
AssertWriteToParameters(writer, encoder, cultureInfo);
writer.Write(encoder.Encode(ToStringValue()));
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ AssertWriteToParameters(writer, encoder, cultureInfo);
+ var task = writer.WriteAsync(encoder.Encode(ToStringValue()));
+
+ if (task.IsCompletedSuccessfully())
+ {
+ return default;
+ }
+
+ return Awaited(task);
+
+ static async ValueTask Awaited(Task t)
+ {
+ await t;
+ return;
+ }
+ }
+
public override object ToObjectValue()
{
return _value ? BoxedTrue : BoxedFalse;
diff --git a/Fluid/Values/DateTimeValue.cs b/Fluid/Values/DateTimeValue.cs
index 57420eaa..2e1ea48d 100644
--- a/Fluid/Values/DateTimeValue.cs
+++ b/Fluid/Values/DateTimeValue.cs
@@ -1,4 +1,5 @@
-using System.Globalization;
+using Fluid.Utils;
+using System.Globalization;
using System.Text.Encodings.Web;
namespace Fluid.Values
@@ -44,12 +45,32 @@ public override string ToStringValue()
return _value.ToString("u", CultureInfo.InvariantCulture);
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
AssertWriteToParameters(writer, encoder, cultureInfo);
writer.Write(_value.ToString("u", cultureInfo));
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ AssertWriteToParameters(writer, encoder, cultureInfo);
+ var task = writer.WriteAsync(_value.ToString("u", cultureInfo));
+
+ if (task.IsCompletedSuccessfully())
+ {
+ return default;
+ }
+
+ return Awaited(task);
+
+ static async ValueTask Awaited(Task t)
+ {
+ await t;
+ return;
+ }
+ }
+
public override object ToObjectValue()
{
return _value;
diff --git a/Fluid/Values/DictionaryValue.cs b/Fluid/Values/DictionaryValue.cs
index a8962fcf..a4659967 100644
--- a/Fluid/Values/DictionaryValue.cs
+++ b/Fluid/Values/DictionaryValue.cs
@@ -90,10 +90,16 @@ public override decimal ToNumberValue()
return 0;
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ return default;
+ }
+
public override string ToStringValue()
{
return "";
diff --git a/Fluid/Values/EmptyValue.cs b/Fluid/Values/EmptyValue.cs
index 233d31f6..7042a7b7 100644
--- a/Fluid/Values/EmptyValue.cs
+++ b/Fluid/Values/EmptyValue.cs
@@ -50,10 +50,16 @@ public override bool IsNil()
return true;
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ return default;
+ }
+
public override bool Equals(object obj)
{
// The is operator will return false if null
diff --git a/Fluid/Values/FactoryValue.cs b/Fluid/Values/FactoryValue.cs
index 9367b547..d198b4ac 100644
--- a/Fluid/Values/FactoryValue.cs
+++ b/Fluid/Values/FactoryValue.cs
@@ -79,10 +79,30 @@ public override string ToStringValue()
return _factory.Value.ToStringValue();
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
AssertWriteToParameters(writer, encoder, cultureInfo);
_factory.Value.WriteTo(writer, encoder, cultureInfo);
}
+
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ AssertWriteToParameters(writer, encoder, cultureInfo);
+ var task = _factory.Value.WriteToAsync(writer, encoder, cultureInfo);
+
+ if (task.IsCompletedSuccessfully)
+ {
+ return default;
+ }
+
+ return Awaited(task);
+
+ static async ValueTask Awaited(ValueTask t)
+ {
+ await t;
+ return;
+ }
+ }
}
}
diff --git a/Fluid/Values/FluidValue.cs b/Fluid/Values/FluidValue.cs
index c49e0e1c..5c463a8c 100644
--- a/Fluid/Values/FluidValue.cs
+++ b/Fluid/Values/FluidValue.cs
@@ -9,8 +9,17 @@ namespace Fluid.Values
public abstract class FluidValue : IEquatable
#pragma warning restore CA1067
{
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public abstract void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo);
+ public virtual ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+#pragma warning disable CS0618 // Type or member is obsolete
+ WriteTo(writer, encoder, cultureInfo);
+#pragma warning restore CS0618 // Type or member is obsolete
+ return default;
+ }
+
private static Dictionary _genericDictionaryTypeCache = new();
[Conditional("DEBUG")]
diff --git a/Fluid/Values/ForLoopValue.cs b/Fluid/Values/ForLoopValue.cs
index 097fcbf0..fb3b58c4 100644
--- a/Fluid/Values/ForLoopValue.cs
+++ b/Fluid/Values/ForLoopValue.cs
@@ -57,8 +57,14 @@ public override ValueTask GetValueAsync(string name, TemplateContext
};
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
}
+
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ return default;
+ }
}
}
diff --git a/Fluid/Values/FunctionValue.cs b/Fluid/Values/FunctionValue.cs
index 0e4a6933..d43dd207 100644
--- a/Fluid/Values/FunctionValue.cs
+++ b/Fluid/Values/FunctionValue.cs
@@ -55,10 +55,16 @@ public override bool IsNil()
return false;
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
// A function value should be invoked and its result used instead.
- // Calling write to is equivalent to renderding {{ alert }} instead of {{ alert() }}
+ // Calling write to is equivalent to rendering {{ alert }} instead of {{ alert() }}
+ }
+
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ return default;
}
public override bool Equals(object obj)
diff --git a/Fluid/Values/NilValue.cs b/Fluid/Values/NilValue.cs
index e5dc7145..79cc9d47 100644
--- a/Fluid/Values/NilValue.cs
+++ b/Fluid/Values/NilValue.cs
@@ -52,10 +52,16 @@ public override bool IsNil()
return true;
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ return default;
+ }
+
public override bool Equals(object obj)
{
// The is operator will return false if null
diff --git a/Fluid/Values/NumberValue.cs b/Fluid/Values/NumberValue.cs
index 98bc5325..31075579 100644
--- a/Fluid/Values/NumberValue.cs
+++ b/Fluid/Values/NumberValue.cs
@@ -1,4 +1,5 @@
-using System.Globalization;
+using Fluid.Utils;
+using System.Globalization;
using System.Text.Encodings.Web;
namespace Fluid.Values
@@ -57,12 +58,32 @@ public override string ToStringValue()
return _value.ToString(CultureInfo.InvariantCulture);
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
AssertWriteToParameters(writer, encoder, cultureInfo);
writer.Write(encoder.Encode(_value.ToString(cultureInfo)));
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ AssertWriteToParameters(writer, encoder, cultureInfo);
+ var task = writer.WriteAsync(encoder.Encode(_value.ToString(cultureInfo)));
+
+ if (task.IsCompletedSuccessfully())
+ {
+ return default;
+ }
+
+ return Awaited(task);
+
+ static async ValueTask Awaited(Task t)
+ {
+ await t;
+ return;
+ }
+ }
+
public override object ToObjectValue()
{
return _value;
@@ -135,7 +156,7 @@ public static int GetScale(decimal value)
return 0;
}
- int[] bits = decimal.GetBits(value);
+ var bits = decimal.GetBits(value);
return (int)((bits[3] >> 16) & 0x7F);
}
diff --git a/Fluid/Values/ObjectValueBase.cs b/Fluid/Values/ObjectValueBase.cs
index 793a3366..e7ebf524 100644
--- a/Fluid/Values/ObjectValueBase.cs
+++ b/Fluid/Values/ObjectValueBase.cs
@@ -1,4 +1,5 @@
-using System.Collections;
+using Fluid.Utils;
+using System.Collections;
using System.Globalization;
using System.Text.Encodings.Web;
@@ -104,7 +105,7 @@ private async ValueTask GetNestedValueAsync(string name, TemplateCon
{
var members = name.Split(MemberSeparators);
- object target = Value;
+ var target = Value;
foreach (var prop in members)
{
@@ -148,12 +149,32 @@ public override decimal ToNumberValue()
return Convert.ToDecimal(Value);
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
AssertWriteToParameters(writer, encoder, cultureInfo);
writer.Write(encoder.Encode(ToStringValue()));
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ AssertWriteToParameters(writer, encoder, cultureInfo);
+ var task = writer.WriteAsync(encoder.Encode(ToStringValue()));
+
+ if (task.IsCompletedSuccessfully())
+ {
+ return default;
+ }
+
+ return Awaited(task);
+
+ static async ValueTask Awaited(Task t)
+ {
+ await t;
+ return;
+ }
+ }
+
public override string ToStringValue()
{
return Convert.ToString(Value);
diff --git a/Fluid/Values/StringValue.cs b/Fluid/Values/StringValue.cs
index 1c01fd6b..a5d92cf5 100644
--- a/Fluid/Values/StringValue.cs
+++ b/Fluid/Values/StringValue.cs
@@ -1,4 +1,5 @@
-using Parlot;
+using Fluid.Utils;
+using Parlot;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text.Encodings.Web;
@@ -110,7 +111,7 @@ protected override FluidValue GetValue(string name, TemplateContext context)
{
"size" => NumberValue.Create(_value.Length),
"first" => _value.Length > 0 ? Create(_value[0]) : NilValue.Instance,
- "last" => _value.Length > 0 ? Create(_value[_value.Length - 1]) : NilValue.Instance,
+ "last" => _value.Length > 0 ? Create(_value[^1]) : NilValue.Instance,
_ => NilValue.Instance,
};
}
@@ -140,6 +141,7 @@ public override string ToStringValue()
return _value;
}
+ [Obsolete("WriteTo is obsolete, prefer the WriteToAsync method.")]
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
{
AssertWriteToParameters(writer, encoder, cultureInfo);
@@ -165,6 +167,46 @@ public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo
}
}
+ public override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
+ {
+ AssertWriteToParameters(writer, encoder, cultureInfo);
+ if (string.IsNullOrEmpty(_value))
+ {
+ return default;
+ }
+
+ Task task;
+
+ if (Encode)
+ {
+ // perf: Don't use this overload
+ // encoder.Encode(writer, _value);
+
+ // Use a transient string instead of calling
+ // encoder.Encode(TextWriter) since it would
+ // call writer.Write on each char if the string
+ // has even a single char to encode
+ task = writer.WriteAsync(encoder.Encode(_value));
+ }
+ else
+ {
+ task = writer.WriteAsync(_value);
+ }
+
+ if (task.IsCompletedSuccessfully())
+ {
+ return default;
+ }
+
+ return Awaited(task);
+
+ static async ValueTask Awaited(Task t)
+ {
+ await t;
+ return;
+ }
+ }
+
public override object ToObjectValue()
{
return _value;