Skip to content

Commit

Permalink
Add public UTF8 TryFormat overloads to relevant types (#84841)
Browse files Browse the repository at this point in the history
* Add public UTF8 TryFormat overloads to relevant types

* Fix IPNetwork.TryFormat parameter name
  • Loading branch information
stephentoub authored Apr 14, 2023
1 parent 3182dfb commit a4a5bdb
Show file tree
Hide file tree
Showing 39 changed files with 189 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ public IPAddress(System.ReadOnlySpan<byte> address, long scopeid) { }
public override string ToString() { throw null; }
string IFormattable.ToString(string? format, IFormatProvider? formatProvider) { throw null; }
public bool TryFormat(System.Span<char> destination, out int charsWritten) { throw null; }
public bool TryFormat(System.Span<byte> utf8Destination, out int bytesWritten) { throw null; }
bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) { throw null; }
bool System.IUtf8SpanFormattable.TryFormat(System.Span<byte> utf8Destination, out int bytesWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> ipSpan, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.IPAddress? address) { throw null; }
Expand Down Expand Up @@ -316,6 +317,7 @@ public IPEndPoint(System.Net.IPAddress address, int port) { }
static bool System.ISpanParsable<System.Net.IPNetwork>.TryParse(System.ReadOnlySpan<char> s, System.IFormatProvider? provider, out System.Net.IPNetwork result) { throw null; }
public override string ToString() { throw null; }
public bool TryFormat(System.Span<char> destination, out int charsWritten) { throw null; }
public bool TryFormat(System.Span<byte> utf8Destination, out int bytesWritten) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Net.IPNetwork result) { throw null; }
public static bool TryParse(string? s, out System.Net.IPNetwork result) { throw null; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,13 @@ string IFormattable.ToString(string? format, IFormatProvider? formatProvider) =>
public bool TryFormat(Span<char> destination, out int charsWritten) =>
TryFormatCore(destination, out charsWritten);

/// <summary>Tries to format the current IP address into the provided span.</summary>
/// <param name="utf8Destination">When this method returns, the IP address as a span of UTF8 bytes.</param>
/// <param name="bytesWritten">When this method returns, the number of bytes written into the <paramref name="utf8Destination"/>.</param>
/// <returns><see langword="true" /> if the formatting was successful; otherwise, <see langword="false" />.</returns>
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten) =>
TryFormatCore(utf8Destination, out bytesWritten);

/// <inheritdoc/>
bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
// format and provider are explicitly ignored
Expand Down
13 changes: 12 additions & 1 deletion src/libraries/System.Net.Primitives/src/System/Net/IPNetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ public override string ToString() =>
public bool TryFormat(Span<char> destination, out int charsWritten) =>
destination.TryWrite(CultureInfo.InvariantCulture, $"{BaseAddress}/{(uint)PrefixLength}", out charsWritten);

/// <summary>
/// Attempts to write the <see cref="IPNetwork"/>'s CIDR notation to the given <paramref name="utf8Destination"/> UTF8 span and returns a value indicating whether the operation succeeded.
/// </summary>
/// <param name="utf8Destination">The destination span of UTF8 bytes.</param>
/// <param name="bytesWritten">When this method returns, contains the number of bytes that were written to <paramref name="utf8Destination"/>.</param>
/// <returns><see langword="true"/> if the formatting was succesful; otherwise <see langword="false"/>.</returns>
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten) =>
Utf8.TryWrite(utf8Destination, CultureInfo.InvariantCulture, $"{BaseAddress}/{(uint)PrefixLength}", out bytesWritten);

/// <summary>
/// Determines whether two <see cref="IPNetwork"/> instances are equal.
/// </summary>
Expand Down Expand Up @@ -298,11 +307,13 @@ obj is IPNetwork other &&

/// <inheritdoc />
bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
// format and provider are ignored
TryFormat(destination, out charsWritten);

/// <inheritdoc />
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
Utf8.TryWrite(utf8Destination, CultureInfo.InvariantCulture, $"{BaseAddress}/{(uint)PrefixLength}", out bytesWritten);
// format and provider are ignored
TryFormat(utf8Destination, out bytesWritten);

/// <inheritdoc />
static IPNetwork IParsable<IPNetwork>.Parse([NotNull] string s, IFormatProvider? provider) => Parse(s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class IPAddressParsingFormatting_Span : IPAddressParsingFormatting
public override IPAddress Parse(string ipString) => IPAddress.Parse(ipString.AsSpan());
public override bool TryParse(string ipString, out IPAddress address) => IPAddress.TryParse(ipString.AsSpan(), out address);
public virtual bool TryFormat(IPAddress address, Span<char> destination, out int charsWritten) => address.TryFormat(destination, out charsWritten);
public virtual bool TryFormat(IPAddress address, Span<byte> utf8Destination, out int bytesWritten) => ((IUtf8SpanFormattable)address).TryFormat(utf8Destination, out bytesWritten, default, null);
public virtual bool TryFormat(IPAddress address, Span<byte> utf8Destination, out int bytesWritten) => address.TryFormat(utf8Destination, out bytesWritten);

[Theory]
[MemberData(nameof(ValidIpv4Addresses))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ public void TryFormatSpan_NotEnoughLength_ReturnsFalse(string input)
// UTF8
{
Span<byte> span = stackalloc byte[input.Length - 1];
Assert.False(((IUtf8SpanFormattable)network).TryFormat(span, out int bytesWritten, default, null));
Assert.False(network.TryFormat(span, out int bytesWritten));
Assert.Equal(0, bytesWritten);
}
}
Expand All @@ -290,7 +290,7 @@ public void TryFormatSpan_EnoughLength_Succeeds(string input)
// UTF8
{
Span<byte> span = stackalloc byte[input.Length + additionalLength];
Assert.True(((IUtf8SpanFormattable)network).TryFormat(span, out int bytesWritten, default, null));
Assert.True(network.TryFormat(span, out int bytesWritten));
Assert.Equal(input.Length, bytesWritten);
Assert.Equal(input, Encoding.UTF8.GetString(span.Slice(0, bytesWritten)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static partial class Utf8Formatter
//
private static bool TryFormatDateTimeL(DateTime value, Span<byte> destination, out int bytesWritten)
{
if (((IUtf8SpanFormattable)value).TryFormat(destination, out bytesWritten, "r", CultureInfo.InvariantCulture))
if (value.TryFormat(destination, out bytesWritten, "r", CultureInfo.InvariantCulture))
{
Debug.Assert(bytesWritten == 29);
Ascii.ToLowerInPlace(destination.Slice(0, bytesWritten), out bytesWritten);
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Byte.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatUInt32(m_value, format, provider, destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatUInt32(m_value, format, provider, utf8Destination, out bytesWritten);
}
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Private.CoreLib/src/System/Char.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, Re
return false;
}

/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
new Rune(this).TryEncodeToUtf8(utf8Destination, out bytesWritten);

Expand Down
5 changes: 3 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -784,10 +784,11 @@ public string ToString([StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] stri
/// <param name="format">A span containing the characters that represent a standard or custom format string that defines the acceptable format for destination.</param>
/// <param name="provider">An optional object that supplies culture-specific formatting information for destination.</param>
/// <returns>true if the formatting was successful; otherwise, false.</returns>
public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan<char> format = default(ReadOnlySpan<char>), IFormatProvider? provider = null) =>
public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
TryFormatCore(destination, out charsWritten, format, provider);

bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan<char> format, IFormatProvider? provider) =>
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
TryFormatCore(utf8Destination, out bytesWritten, format, provider);

private bool TryFormatCore<TChar>(Span<TChar> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.DateOnlyFormat)] ReadOnlySpan<char> format, IFormatProvider? provider = null)
Expand Down
3 changes: 2 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/DateTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1806,7 +1806,8 @@ public string ToString([StringSyntax(StringSyntaxAttribute.DateTimeFormat)] stri
public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
DateTimeFormat.TryFormat(this, destination, out charsWritten, format, provider);

bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan<char> format, IFormatProvider? provider) =>
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
DateTimeFormat.TryFormat(this, utf8Destination, out bytesWritten, format, provider);

public DateTime ToUniversalTime()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,8 @@ public string ToString([StringSyntax(StringSyntaxAttribute.DateTimeFormat)] stri
public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan<char> format = default, IFormatProvider? formatProvider = null) =>
DateTimeFormat.TryFormat(ClockDateTime, destination, out charsWritten, format, formatProvider, Offset);

bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan<char> format, IFormatProvider? formatProvider) =>
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.DateTimeFormat)] ReadOnlySpan<char> format = default, IFormatProvider? formatProvider = null) =>
DateTimeFormat.TryFormat(ClockDateTime, utf8Destination, out bytesWritten, format, formatProvider, Offset);

public DateTimeOffset ToUniversalTime() =>
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Decimal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatDecimal(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatDecimal(this, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten);
}
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Double.cs
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ internal static void FormatFraction<TChar>(ref ValueListBuilder<TChar> result, i
int charCount;
bool formatted = typeof(TChar) == typeof(char) ?
fraction.TryFormat(MemoryMarshal.Cast<TChar, char>(chars), out charCount, fractionFormat, CultureInfo.InvariantCulture) :
((IUtf8SpanFormattable)fraction).TryFormat(MemoryMarshal.Cast<TChar, byte>(chars), out charCount, fractionFormat, CultureInfo.InvariantCulture);
fraction.TryFormat(MemoryMarshal.Cast<TChar, byte>(chars), out charCount, fractionFormat, CultureInfo.InvariantCulture);
Debug.Assert(charCount != 0);
result.Append(chars.Slice(0, charCount));
}
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Half.cs
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatHalf(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatHalf(this, format, NumberFormatInfo.GetInstance(provider), utf8Destination, out bytesWritten);
}
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Int128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatInt128(this, format, provider, destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatInt128(this, format, provider, utf8Destination, out bytesWritten);
}
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Int16.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatInt32(m_value, 0x0000FFFF, format, provider, destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatInt32(m_value, 0x0000FFFF, format, provider, utf8Destination, out bytesWritten);
}
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Int32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatInt32(m_value, ~0, format, provider, destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatInt32(m_value, ~0, format, provider, utf8Destination, out bytesWritten);
}
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Int64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ public bool TryFormat(Span<char> destination, out int charsWritten, [StringSynta
return Number.TryFormatInt64(m_value, format, provider, destination, out charsWritten);
}

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
{
return Number.TryFormatInt64(m_value, format, provider, utf8Destination, out bytesWritten);
}
Expand Down
6 changes: 3 additions & 3 deletions src/libraries/System.Private.CoreLib/src/System/IntPtr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ public int CompareTo(nint value)
public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
((nint_t)_value).TryFormat(destination, out charsWritten, format, provider);

/// <inheritdoc/>
bool IUtf8SpanFormattable.TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider) =>
((IUtf8SpanFormattable)(nint_t)_value).TryFormat(utf8Destination, out bytesWritten, format, provider);
/// <inheritdoc cref="IUtf8SpanFormattable.TryFormat" />
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
((nint_t)_value).TryFormat(utf8Destination, out bytesWritten, format, provider);

public static nint Parse(string s) => (nint)nint_t.Parse(s);
public static nint Parse(string s, NumberStyles style) => (nint)nint_t.Parse(s, style);
Expand Down
Loading

0 comments on commit a4a5bdb

Please sign in to comment.