Minor respath improvements (#5876)

* Minor respath improvements

* Add helpers

* tweak helper

* Throw on more than 1 char

* comments

* No emoji separators
This commit is contained in:
Leon Friedrich
2025-05-12 13:04:40 +10:00
committed by GitHub
parent 2b1d755d9f
commit 4d47cfa1a6
2 changed files with 43 additions and 16 deletions

View File

@@ -66,7 +66,7 @@ public readonly struct ResPath : IEquatable<ResPath>
public ResPath(string canonPath)
{
// Paths should never have non-standardised directory separators passed in, the caller should have already sanitised it.
DebugTools.Assert(!canonPath.Contains('\\'));
DebugTools.Assert(IsValidPath(canonPath));
CanonPath = canonPath;
}
@@ -77,6 +77,21 @@ public readonly struct ResPath : IEquatable<ResPath>
{
}
/// <summary>
/// Check whether the given string paths contains any non-standard directory separators.
/// </summary>
public static bool IsValidPath(string path) => !path.Contains('\\');
/// <summary>
/// Check whether a string is a valid path (<see cref="IsValidPath"/>) and corresponds to a simple file name.
/// </summary>
public static bool IsValidFilename([NotNullWhen(true)] string? filename)
=> !string.IsNullOrEmpty(filename)
&& IsValidPath(filename)
&& !filename.Contains('/')
&& filename != "."
&& filename != "..";
/// <summary>
/// Returns true if the path is equal to "."
/// </summary>
@@ -106,7 +121,7 @@ public readonly struct ResPath : IEquatable<ResPath>
}
var ind = CanonPath.Length > 1 && CanonPath[^1] == '/'
? CanonPath[..^1].LastIndexOf('/')
? CanonPath.LastIndexOf('/', CanonPath.Length - 2)
: CanonPath.LastIndexOf('/');
return ind switch
{
@@ -206,7 +221,7 @@ public readonly struct ResPath : IEquatable<ResPath>
// it's a filename
// Uses +1 to skip `/` found in or starts from beginning of string
// if we found nothing (ind == -1)
var ind = CanonPath[..^1].LastIndexOf('/') + 1;
var ind = CanonPath.LastIndexOf('/', CanonPath.Length - 2) + 1;
return CanonPath[^1] == '/'
? CanonPath[ind .. ^1] // Omit last `/`
: CanonPath[ind..];
@@ -242,7 +257,6 @@ public readonly struct ResPath : IEquatable<ResPath>
return CanonPath.GetHashCode();
}
public static bool operator ==(ResPath left, ResPath right)
{
return left.Equals(right);
@@ -283,7 +297,7 @@ public readonly struct ResPath : IEquatable<ResPath>
}
// Avoid double separators
if (left.CanonPath.EndsWith("/"))
if (left.CanonPath.EndsWith('/'))
{
return new ResPath(left.CanonPath + right.CanonPath);
}
@@ -475,7 +489,7 @@ public readonly struct ResPath : IEquatable<ResPath>
/// </summary>
public string ToRelativeSystemPath()
{
return ToRelativePath().ChangeSeparator(SystemSeparatorStr);
return ToRelativePath().ChangeSeparator(SystemSeparator);
}
/// <summary>
@@ -495,14 +509,19 @@ public readonly struct ResPath : IEquatable<ResPath>
/// </summary>
public string ChangeSeparator(string newSeparator)
{
if (newSeparator is "." or "\0")
{
throw new ArgumentException("New separator can't be `.` or `NULL`");
}
if (newSeparator.Length != 1)
throw new InvalidOperationException("new separator must be a single character.");
return ChangeSeparator(newSeparator[0]);
}
return newSeparator == "/"
? CanonPath
: CanonPath.Replace("/", newSeparator);
/// <inheritdoc cref="ChangeSeparator(string)"/>
public string ChangeSeparator(char newSeparator)
{
if (newSeparator is '.' or '\0')
throw new ArgumentException("New separator can't be `.` or `NULL`");
// String.Replace() already checks if newSeparator == '/'
return CanonPath.Replace('/', newSeparator);
}
}