Skip to content

Conversation

Joy-less
Copy link

Supercedes #111815.

This time the methods are fully implemented and ready to go, and the ref assemblies are added to match the implementations.

@Copilot Copilot AI review requested due to automatic review settings June 30, 2025 17:58
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jun 30, 2025
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Jun 30, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a set of new API overloads to support System.Text.Rune across various string and text manipulation APIs, addressing methods such as Equals, Contains, IndexOf/LastIndexOf, Replace, Trim, Append, Insert, and Write. The changes span multiple libraries including System.Runtime and System.Private.CoreLib to fully integrate rune-based operations.

  • Added overloads for string comparison methods accepting System.Text.Rune.
  • Introduced new methods on StringBuilder, TextWriter, and TextInfo to handle rune conversion and manipulation.
  • Updated internal string splitting and trimming routines to support rune separators and trim characters.

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/libraries/System.Runtime/ref/System.Runtime.cs Added new overloads for string API methods accepting System.Text.Rune and StringComparison.
src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs Added Append/Insert/Replace methods with System.Text.Rune and Rune retrieval overloads.
src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs Updated Equals implementations and added new overloads for comparing Runes with StringComparison.
src/libraries/System.Private.CoreLib/src/System/String.Searching.cs Provided new overloads of Contains, IndexOf, and LastIndexOf for System.Text.Rune with careful iteration over surrogates.
src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs Added Replace, Split, and Trim overloads using System.Text.Rune for enhanced string manipulation.
src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs Extended StartsWith and EndsWith to support System.Text.Rune comparisons.
src/libraries/System.Private.CoreLib/src/System/IO/TextWriter.cs Integrated Write and WriteLine overloads that accept System.Text.Rune.
src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs Implemented ToLower and ToUpper for System.Text.Rune conversions.
src/libraries/System.Private.CoreLib/src/System/Char.cs Added an overload for Equals accepting a StringComparison using modern array initialization.
Comments suppressed due to low confidence (1)

src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs:2850

  • In GetRuneAt(int index), consider throwing a more specific exception type (such as ArgumentOutOfRangeException) rather than a generic Exception for improved clarity and consistency with API design.
            throw new Exception($"Unable to get rune at {index}.");

Joy-less and others added 2 commits June 30, 2025 19:04
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

@MihaZupan MihaZupan removed the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Aug 1, 2025
@jeffhandley
Copy link
Member

@stephentoub - Since this has been open as long as it has, I wanted to check with you that we should still pursue adding the Rune overloads. Any concerns or hesitations?

@Joy-less
Copy link
Author

Joy-less commented Sep 5, 2025

@jeffhandley I have made some changes to my PR:

  • Fixed TextInfo.ToLower(Rune) and TextInfo.ToUpper(Rune) for runes which use two chars. Very niche but affects some characters like 𐐨 (\uD801\uDC28) -> 𐐀 (\uD801\uDC00).
  • Used the ordinal char.Equals(char) implementation for char.Equals(char, StringComparison) when StringComparison is StringComparison.Ordinal.

I think #111170 is a relevant pull request to this one.

Also, the original creator of the API proposals for both this pull request and the above pull request has this on their profile:

On other projects, not checking GitHub notifications - ping via Teams if urgent.

@tarekgh
Copy link
Member

tarekgh commented Sep 5, 2025

@Joy-less I'll get into this PR in the next few days. Thanks!

@tarekgh
Copy link
Member

tarekgh commented Sep 23, 2025

@Joy-less do you compile and run the tests locally before submitting changes? curious to know 😄.

@Joy-less
Copy link
Author

As far as I know all of the tests have been implemented now, granted they are kind of all over the place so I may have missed some. Feel free to go through them now.

#117168 (comment)

I actually added these to an existing test, do you want them separate?
6b6fae9

@Joy-less
Copy link
Author

@Joy-less do you compile and run the tests locally before submitting changes? curious to know 😄.

No haha, I'm not sure how especially with the lack of .NET 10.0 on my system and issues installing it.

@tarekgh
Copy link
Member

tarekgh commented Sep 24, 2025

No haha, I'm not sure how especially with the lack of .NET 10.0 on my system and issues installing it.

You don't need to install that. You can do:

  • assuming you cloned on a folder like C:\runtime
  • cd C:\runtime
  • Build from the root doing .\build.cmd -s libs+clr -c Release
  • then go to the test folder like: pushd .\src\libraries\System.Runtime\tests\System.Runtime.Tests\
  • Run the test C:\runtime\.dotnet\dotnet build /t:test /p:Configuration=Release
  • You can run any other tests same way

I'll try to clone your branch tomorrow and run it myself, would be faster push fixes 😄

@tarekgh
Copy link
Member

tarekgh commented Sep 24, 2025

I actually added these to an existing test, do you want them separate?

This works with a single character; we need to test surrogate pairs too. This is why I suggested doing something like the one using the string separator.

@tarekgh
Copy link
Member

tarekgh commented Sep 25, 2025

@Joy-less I pushed some changes to fix some behavior and ensure the runtime tests are passing now with no problem. Please take a look and let me know if there is anything else you want to add before I take a last look tomorrow and try to merge. Thanks!


return SplitInternal(separatorChars, count, options);
// Ensure matching the string separator overload.
return count <= 1 || Length == 0 ? CreateSplitArrayOfThisAsSoleValue(options, count) : Split(runeSeparator, count, options);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be easier to read with brackets:
(count <= 1 || Length == 0)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change it if you want, 😄

public string[] Split(Rune separator, int count, StringSplitOptions options = StringSplitOptions.None)
{
if (Length == 0)
ReadOnlySpan<char> runeSeparator = separator.AsSpan(stackalloc char[Rune.MaxUtf16CharsPerRune]);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe should be separatorChars instead of runeSeparator to be consistent with the other implementations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chars can indicate multiple separators, I wanted to be clear this is a single separator.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about separatorSpan? runeSeparator implies that it's separator typed as a Rune which is actually the opposite of the case.

@Joy-less
Copy link
Author

@Joy-less I pushed some changes to fix some behavior and ensure the runtime tests are passing now with no problem. Please take a look and let me know if there is anything else you want to add before I take a last look tomorrow and try to merge. Thanks!

I think that's everything done now. Let me know if there's something else I missed or need to look at. Thanks for your diligence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Runtime community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants