1
0
Fork 0

Migrate existing code

This commit is contained in:
Jöran Malek 2025-01-29 23:53:57 +01:00
parent 384ff4a6f3
commit 9b49f880a2
30 changed files with 1789 additions and 5 deletions

113
System/IO/Paths.cs Normal file
View file

@ -0,0 +1,113 @@
#if !(LINUX || MACOS || WINDOWS)
#define TARGET_ANY
#endif
#if TARGET_ANY || LINUX
#define TARGET_LINUX
#endif
#if TARGET_ANY || MACOS
#define TARGET_MACOS
#endif
#if TARGET_ANY || WINDOWS
#define TARGET_WINDOWS
#endif
using System.Buffers;
using CommunityToolkit.HighPerformance.Buffers;
namespace System.IO;
public static class PathEx
{
public static string ExpandPath(string path)
{
#if TARGET_ANY
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
#endif
#if TARGET_LINUX || TARGET_MACOS
return ExpandPathUnixImpl(path);
#endif
#if TARGET_ANY
}
else if (OperatingSystem.IsWindows())
{
#endif
#if TARGET_WINDOWS
return ExpandPathWindowsImpl(path);
#endif
#if TARGET_ANY
}
else
{
throw new PlatformNotSupportedException();
}
#endif
}
#if TARGET_LINUX || TARGET_MACOS
private static string ExpandPathUnixImpl(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
return path;
}
var reader = new SequenceReader<char>(new(path.AsMemory()));
if (!reader.TryReadTo(out ReadOnlySpan<char> read, '$'))
{
return path;
}
using ArrayPoolBufferWriter<char> result = new();
while (true)
{
result.Write(read);
int skip = 0;
if (reader.UnreadSpan[0] == '{' && reader.UnreadSpan.IndexOf('}') is not -1 and int s)
{
read = reader.UnreadSpan[1..s];
skip = s + 1;
}
else
{
var propertyReader = new SequenceReader<char>(reader.UnreadSequence);
while (!propertyReader.End && propertyReader.UnreadSpan[0] is char c && (c == '_' || char.IsAsciiLetterOrDigit(c)))
{
propertyReader.Advance(1);
}
read = reader.UnreadSpan[..(int)propertyReader.Consumed];
skip = read.Length;
}
if (skip != 0 && Environment.GetEnvironmentVariable(read.ToString()) is { } env)
{
result.Write(env);
reader.Advance(skip);
}
else
{
result.Write(['$']);
}
if (!reader.TryReadTo(out read, '$'))
{
break;
}
}
result.Write(reader.UnreadSpan);
return result.WrittenSpan.ToString();
}
#endif
#if TARGET_WINDOWS
private static string ExpandPathWindowsImpl(string path)
{
return Environment.ExpandEnvironmentVariables(path);
}
#endif
}

View file

@ -0,0 +1,67 @@
namespace System.Threading.Tasks;
public static class AsyncWaitHandle
{
public static Task WaitOneAsync(this WaitHandle waitHandle, CancellationToken cancellationToken = default)
{
WaitOneAsyncState state = new(waitHandle, cancellationToken);
return state.WaitOneAsync();
}
private class WaitOneAsyncState : IDisposable
{
private readonly CancellationTokenRegistration _cancellationTokenRegistration;
private readonly RegisteredWaitHandle _registeredWaitHandle;
private readonly TaskCompletionSource _tcs;
private bool _disposed;
public WaitOneAsyncState(WaitHandle waitHandle, CancellationToken cancellationToken)
{
_tcs = new();
_cancellationTokenRegistration = cancellationToken.Register((state, token) => ((WaitOneAsyncState)state!).Canceled(token), this);
_registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitHandle, (state, timeout) => ((WaitOneAsyncState)state!).Signaled(timeout), this, Timeout.Infinite, true);
}
public void Dispose()
{
if (_disposed)
{
return;
}
_registeredWaitHandle.Unregister(default);
_cancellationTokenRegistration.Dispose();
_disposed = true;
}
public Task WaitOneAsync()
{
const TaskContinuationOptions options = TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.ExecuteSynchronously;
return _tcs.Task.ContinueWith((upstream, state) => ((WaitOneAsyncState)state!).Continuation(upstream), this, options).Unwrap();
}
private void Canceled(CancellationToken token)
{
_tcs.SetCanceled(token);
}
private Task Continuation(Task task)
{
Dispose();
return task;
}
private void Signaled(bool timeout)
{
if (timeout)
{
Canceled(CancellationToken.None);
}
else
{
_tcs.SetResult();
}
}
}
}