Skip to content

Commit 013dfe8

Browse files
feat: refactor AppendFormattedValue in GeneratedQueryStringBuilder
1 parent 485c632 commit 013dfe8

2 files changed

Lines changed: 14 additions & 52 deletions

File tree

src/Refit/GeneratedQueryStringBuilder.cs

Lines changed: 13 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -255,34 +255,6 @@ public string Build()
255255
return _text.ToString();
256256
}
257257

258-
#if NET6_0_OR_GREATER
259-
/// <summary>Formats a span-formattable value into <paramref name="buffer"/>, growing a rented buffer until the value fits.</summary>
260-
/// <typeparam name="T">The span-formattable value type.</typeparam>
261-
/// <param name="value">The value to render.</param>
262-
/// <param name="buffer">The target buffer, replaced with a larger rented buffer when the value overflows it.</param>
263-
/// <param name="rented">The rented buffer to grow and return to the pool, or null while the stack buffer is in use.</param>
264-
/// <param name="format">The compile-time format, or null for the default rendering.</param>
265-
/// <returns>The number of characters written into <paramref name="buffer"/>.</returns>
266-
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] // The grow back-edge only fires for a value larger than the stack buffer; the compiler's loop second-jump stays unreachable in practice.
267-
private static int FormatWithGrowth<T>(T value, ref Span<char> buffer, ref char[]? rented, string? format)
268-
where T : ISpanFormattable
269-
{
270-
int written;
271-
while (!value.TryFormat(buffer, out written, format.AsSpan(), System.Globalization.CultureInfo.InvariantCulture))
272-
{
273-
if (rented is not null)
274-
{
275-
System.Buffers.ArrayPool<char>.Shared.Return(rented);
276-
}
277-
278-
rented = System.Buffers.ArrayPool<char>.Shared.Rent(buffer.Length * BufferGrowthFactor);
279-
buffer = rented;
280-
}
281-
282-
return written;
283-
}
284-
#endif
285-
286258
/// <summary>Appends the <c>?</c> or <c>&amp;</c> separator, materializing the text buffer on first use.</summary>
287259
private void AppendSeparator()
288260
{
@@ -337,33 +309,23 @@ private void AppendFormattedPair<T>(string name, T value, string? format, bool k
337309
private readonly void AppendFormattedValue<T>(ref ValueStringBuilder target, T value, string? format, bool escape)
338310
where T : ISpanFormattable
339311
{
340-
Span<char> buffer = stackalloc char[FormatBufferLength];
341-
char[]? rented = null;
342-
try
312+
var buffer = new ValueStringBuilder(stackalloc char[FormatBufferLength]);
313+
while (!value.TryFormat(buffer.RawChars, out _, format.AsSpan(), System.Globalization.CultureInfo.InvariantCulture))
343314
{
344-
var written = FormatWithGrowth(value, ref buffer, ref rented, format);
345-
346-
var formatted = (ReadOnlySpan<char>)buffer[..written];
347-
if (escape)
348-
{
349-
// Percent-encode straight into the builder with no intermediate escaped string, on every target
350-
// framework (the span overload of Uri.EscapeDataString only exists on net9+).
351-
StringHelpers.AppendUriDataEscaped(ref target, formatted);
352-
return;
353-
}
354-
355-
// Copy into a reserved slice so the stack buffer is never captured by the builder (ref-safety), matching a
356-
// verbatim span append with no intermediate string.
357-
formatted.CopyTo(target.AppendSpan(written));
315+
buffer.EnsureCapacity(buffer.Capacity * BufferGrowthFactor);
358316
}
359-
finally
317+
318+
if (escape)
360319
{
361-
if (rented is not null)
362-
{
363-
System.Buffers.ArrayPool<char>.Shared.Return(rented);
364-
}
320+
// Percent-encode straight into the builder with no intermediate escaped string, on every target
321+
// framework (the span overload of Uri.EscapeDataString only exists on net9+).
322+
StringHelpers.AppendUriDataEscaped(ref target, buffer.AsSpan());
323+
return;
365324
}
366-
}
367325

326+
// Copy into a reserved slice so the stack buffer is never captured by the builder (ref-safety), matching a
327+
// verbatim span append with no intermediate string.
328+
target.Append(buffer.AsSpan());
329+
}
368330
#endif
369331
}

src/Refit/ValueStringBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ public void Append(char c, int count)
277277

278278
/// <summary>Appends the characters of a span to the builder.</summary>
279279
/// <param name="value">The characters to append.</param>
280-
public void Append(ReadOnlySpan<char> value)
280+
public void Append(scoped ReadOnlySpan<char> value)
281281
{
282282
var pos = _pos;
283283
if (pos > _chars.Length - value.Length)

0 commit comments

Comments
 (0)