Browse Source
* remove uncompilable code guarded by platform defines * Remove OperatingSystemEx * remove NativeLibraryEx * remove unused classes * fix unused usingspull/20892/head
committed by
GitHub
97 changed files with 67 additions and 1022 deletions
@ -1,32 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
|
|||
namespace System; |
|||
|
|||
#if !NET6_0_OR_GREATER
|
|||
internal static class CollectionCompatibilityExtensions |
|||
{ |
|||
public static bool Remove<TKey, TValue>( |
|||
this Dictionary<TKey, TValue> o, |
|||
TKey key, |
|||
[MaybeNullWhen(false)] out TValue value) |
|||
where TKey : notnull |
|||
{ |
|||
if (o.TryGetValue(key, out value)) |
|||
return o.Remove(key); |
|||
return false; |
|||
} |
|||
|
|||
public static bool TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> o, TKey key, TValue value) |
|||
where TKey : notnull |
|||
{ |
|||
if (!o.ContainsKey(key)) |
|||
{ |
|||
o.Add(key, value); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
#endif
|
|||
@ -1,122 +0,0 @@ |
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Reflection; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.Compatibility; |
|||
using Avalonia.Platform.Interop; |
|||
|
|||
namespace Avalonia.Compatibility |
|||
{ |
|||
internal class NativeLibraryEx |
|||
{ |
|||
#if NET6_0_OR_GREATER
|
|||
public static IntPtr Load(string dll, Assembly assembly) => NativeLibrary.Load(dll, assembly, null); |
|||
public static IntPtr Load(string dll) => NativeLibrary.Load(dll); |
|||
public static bool TryGetExport(IntPtr handle, string name, out IntPtr address) => |
|||
NativeLibrary.TryGetExport(handle, name, out address); |
|||
#else
|
|||
public static IntPtr Load(string dll, Assembly assembly) => Load(dll); |
|||
public static IntPtr Load(string dll) |
|||
{ |
|||
var handle = DlOpen!(dll); |
|||
if (handle != IntPtr.Zero) |
|||
return handle; |
|||
throw new InvalidOperationException("Unable to load " + dll, DlError!()); |
|||
} |
|||
|
|||
public static bool TryGetExport(IntPtr handle, string name, out IntPtr address) |
|||
{ |
|||
try |
|||
{ |
|||
address = DlSym!(handle, name); |
|||
return address != default; |
|||
} |
|||
catch (Exception) |
|||
{ |
|||
address = default; |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
static NativeLibraryEx() |
|||
{ |
|||
if (OperatingSystemEx.IsWindows()) |
|||
{ |
|||
Win32Imports.Init(); |
|||
} |
|||
else if (OperatingSystemEx.IsLinux() || OperatingSystemEx.IsMacOS()) |
|||
{ |
|||
var buffer = Marshal.AllocHGlobal(0x1000); |
|||
uname(buffer); |
|||
var unixName = Marshal.PtrToStringAnsi(buffer); |
|||
Marshal.FreeHGlobal(buffer); |
|||
if (unixName == "Darwin") |
|||
OsXImports.Init(); |
|||
else |
|||
LinuxImports.Init(); |
|||
} |
|||
} |
|||
|
|||
private static Func<string, IntPtr>? DlOpen; |
|||
private static Func<IntPtr, string, IntPtr>? DlSym; |
|||
private static Func<Exception?>? DlError; |
|||
|
|||
[DllImport("libc")] |
|||
static extern int uname(IntPtr buf); |
|||
|
|||
static class Win32Imports |
|||
{ |
|||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] |
|||
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); |
|||
|
|||
[DllImport("kernel32", EntryPoint = "LoadLibraryW", SetLastError = true, CharSet = CharSet.Unicode)] |
|||
private static extern IntPtr LoadLibrary(string lpszLib); |
|||
|
|||
public static void Init() |
|||
{ |
|||
DlOpen = LoadLibrary; |
|||
DlSym = GetProcAddress; |
|||
DlError = () => new Win32Exception(Marshal.GetLastWin32Error()); |
|||
} |
|||
} |
|||
|
|||
static class LinuxImports |
|||
{ |
|||
[DllImport("libdl.so.2")] |
|||
private static extern IntPtr dlopen(string path, int flags); |
|||
|
|||
[DllImport("libdl.so.2")] |
|||
private static extern IntPtr dlsym(IntPtr handle, string symbol); |
|||
|
|||
[DllImport("libdl.so.2")] |
|||
private static extern IntPtr dlerror(); |
|||
|
|||
public static void Init() |
|||
{ |
|||
DlOpen = s => dlopen(s, 1); |
|||
DlSym = dlsym; |
|||
DlError = () => new InvalidOperationException(Marshal.PtrToStringAnsi(dlerror())); |
|||
} |
|||
} |
|||
|
|||
static class OsXImports |
|||
{ |
|||
[DllImport("/usr/lib/libSystem.dylib")] |
|||
private static extern IntPtr dlopen(string path, int flags); |
|||
|
|||
[DllImport("/usr/lib/libSystem.dylib")] |
|||
private static extern IntPtr dlsym(IntPtr handle, string symbol); |
|||
|
|||
[DllImport("/usr/lib/libSystem.dylib")] |
|||
private static extern IntPtr dlerror(); |
|||
|
|||
public static void Init() |
|||
{ |
|||
DlOpen = s => dlopen(s, 1); |
|||
DlSym = dlsym; |
|||
DlError = () => new InvalidOperationException(Marshal.PtrToStringAnsi(dlerror())); |
|||
} |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Compatibility |
|||
{ |
|||
internal sealed class OperatingSystemEx |
|||
{ |
|||
#if NET6_0_OR_GREATER
|
|||
public static bool IsWindows() => OperatingSystem.IsWindows(); |
|||
public static bool IsMacOS() => OperatingSystem.IsMacOS(); |
|||
public static bool IsMacCatalyst() => OperatingSystem.IsMacCatalyst(); |
|||
public static bool IsLinux() => OperatingSystem.IsLinux(); |
|||
public static bool IsFreeBSD() => OperatingSystem.IsFreeBSD(); |
|||
public static bool IsAndroid() => OperatingSystem.IsAndroid(); |
|||
public static bool IsIOS() => OperatingSystem.IsIOS(); |
|||
public static bool IsTvOS() => OperatingSystem.IsTvOS(); |
|||
public static bool IsBrowser() => OperatingSystem.IsBrowser(); |
|||
public static bool IsOSPlatform(string platform) => OperatingSystem.IsOSPlatform(platform); |
|||
#else
|
|||
public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); |
|||
public static bool IsMacOS() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); |
|||
public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux); |
|||
public static bool IsFreeBSD() => false; |
|||
public static bool IsAndroid() => false; |
|||
public static bool IsIOS() => false; |
|||
public static bool IsMacCatalyst() => false; |
|||
public static bool IsTvOS() => false; |
|||
public static bool IsBrowser() => false; |
|||
public static bool IsOSPlatform(string platform) => RuntimeInformation.IsOSPlatform(OSPlatform.Create(platform)); |
|||
#endif
|
|||
} |
|||
} |
|||
@ -1,43 +0,0 @@ |
|||
#pragma warning disable MA0048 // File name must match type name
|
|||
// https://github.com/dotnet/runtime/blob/v8.0.4/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/StringSyntaxAttribute.cs
|
|||
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
|||
// See the LICENSE file in the project root for more information.
|
|||
|
|||
// ReSharper disable once CheckNamespace
|
|||
namespace System.Diagnostics.CodeAnalysis |
|||
{ |
|||
#if !NET7_0_OR_GREATER
|
|||
/// <summary>Specifies the syntax used in a string.</summary>
|
|||
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] |
|||
internal sealed class StringSyntaxAttribute : Attribute |
|||
{ |
|||
/// <summary>Initializes the <see cref="StringSyntaxAttribute"/> with the identifier of the syntax used.</summary>
|
|||
/// <param name="syntax">The syntax identifier.</param>
|
|||
public StringSyntaxAttribute(string syntax) |
|||
{ |
|||
Syntax = syntax; |
|||
Arguments = Array.Empty<object?>(); |
|||
} |
|||
|
|||
/// <summary>Initializes the <see cref="StringSyntaxAttribute"/> with the identifier of the syntax used.</summary>
|
|||
/// <param name="syntax">The syntax identifier.</param>
|
|||
/// <param name="arguments">Optional arguments associated with the specific syntax employed.</param>
|
|||
public StringSyntaxAttribute(string syntax, params object?[] arguments) |
|||
{ |
|||
Syntax = syntax; |
|||
Arguments = arguments; |
|||
} |
|||
|
|||
/// <summary>Gets the identifier of the syntax used.</summary>
|
|||
public string Syntax { get; } |
|||
|
|||
/// <summary>Optional arguments associated with the specific syntax employed.</summary>
|
|||
public object?[] Arguments { get; } |
|||
|
|||
/// <summary>The syntax identifier for strings containing XML.</summary>
|
|||
public const string Xml = nameof(Xml); |
|||
} |
|||
#endif
|
|||
} |
|||
@ -1,156 +0,0 @@ |
|||
#if NET6_0_OR_GREATER
|
|||
// In .NET Core, the security context and call context are not supported, however,
|
|||
// the impersonation context and culture would typically flow with the execution context.
|
|||
// See: https://learn.microsoft.com/en-us/dotnet/api/system.threading.executioncontext
|
|||
//
|
|||
// So we can safely use ExecutionContext without worrying about culture flowing issues.
|
|||
#else
|
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using System.Globalization; |
|||
using System.Threading; |
|||
|
|||
namespace Avalonia.Threading; |
|||
|
|||
/// <summary>
|
|||
/// An ExecutionContext that preserves culture information across async operations.
|
|||
/// This is a modernized version that removes legacy compatibility switches and
|
|||
/// includes nullable reference type annotations.
|
|||
/// </summary>
|
|||
internal sealed class CulturePreservingExecutionContext |
|||
{ |
|||
private readonly ExecutionContext _context; |
|||
private CultureAndContext? _cultureAndContext; |
|||
|
|||
private CulturePreservingExecutionContext(ExecutionContext context) |
|||
{ |
|||
_context = context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Captures the current ExecutionContext and culture information.
|
|||
/// </summary>
|
|||
/// <returns>A new CulturePreservingExecutionContext instance, or null if no context needs to be captured.</returns>
|
|||
public static CulturePreservingExecutionContext? Capture() |
|||
{ |
|||
// ExecutionContext.SuppressFlow had been called.
|
|||
// We expect ExecutionContext.Capture() to return null, so match that behavior and return null.
|
|||
if (ExecutionContext.IsFlowSuppressed()) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var context = ExecutionContext.Capture(); |
|||
if (context == null) |
|||
return null; |
|||
|
|||
return new CulturePreservingExecutionContext(context); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Runs the specified callback in the captured execution context while preserving culture information.
|
|||
/// This method is used for .NET Framework and earlier .NET versions.
|
|||
/// </summary>
|
|||
/// <param name="executionContext">The execution context to run in.</param>
|
|||
/// <param name="callback">The callback to execute.</param>
|
|||
/// <param name="state">The state to pass to the callback.</param>
|
|||
public static void Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, object? state) |
|||
{ |
|||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
|||
if (callback == null) |
|||
return; |
|||
|
|||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
|||
if (executionContext == null) |
|||
ThrowNullContext(); |
|||
|
|||
// Save culture information - we will need this to restore just before
|
|||
// the callback is actually invoked from CallbackWrapper.
|
|||
executionContext._cultureAndContext = CultureAndContext.Initialize(callback, state); |
|||
|
|||
try |
|||
{ |
|||
ExecutionContext.Run( |
|||
executionContext._context, |
|||
s_callbackWrapperDelegate, |
|||
executionContext._cultureAndContext); |
|||
} |
|||
finally |
|||
{ |
|||
// Restore culture information - it might have been modified during callback execution.
|
|||
executionContext._cultureAndContext.RestoreCultureInfos(); |
|||
} |
|||
} |
|||
|
|||
[DoesNotReturn] |
|||
private static void ThrowNullContext() |
|||
{ |
|||
throw new InvalidOperationException("ExecutionContext cannot be null."); |
|||
} |
|||
|
|||
private static readonly ContextCallback s_callbackWrapperDelegate = CallbackWrapper; |
|||
|
|||
/// <summary>
|
|||
/// Executes the callback and saves culture values immediately afterwards.
|
|||
/// </summary>
|
|||
/// <param name="obj">Contains the actual callback and state.</param>
|
|||
private static void CallbackWrapper(object? obj) |
|||
{ |
|||
var cultureAndContext = (CultureAndContext)obj!; |
|||
|
|||
// Restore culture information saved during Run()
|
|||
cultureAndContext.RestoreCultureInfos(); |
|||
|
|||
try |
|||
{ |
|||
// Execute the actual callback
|
|||
cultureAndContext.Callback(cultureAndContext.State); |
|||
} |
|||
finally |
|||
{ |
|||
// Save any culture changes that might have occurred during callback execution
|
|||
cultureAndContext.CaptureCultureInfos(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Helper class to manage culture information across execution contexts.
|
|||
/// </summary>
|
|||
private sealed class CultureAndContext |
|||
{ |
|||
public ContextCallback Callback { get; } |
|||
public object? State { get; } |
|||
|
|||
private CultureInfo? _culture; |
|||
private CultureInfo? _uiCulture; |
|||
|
|||
private CultureAndContext(ContextCallback callback, object? state) |
|||
{ |
|||
Callback = callback; |
|||
State = state; |
|||
CaptureCultureInfos(); |
|||
} |
|||
|
|||
public static CultureAndContext Initialize(ContextCallback callback, object? state) |
|||
{ |
|||
return new CultureAndContext(callback, state); |
|||
} |
|||
|
|||
public void CaptureCultureInfos() |
|||
{ |
|||
_culture = Thread.CurrentThread.CurrentCulture; |
|||
_uiCulture = Thread.CurrentThread.CurrentUICulture; |
|||
} |
|||
|
|||
public void RestoreCultureInfos() |
|||
{ |
|||
if (_culture != null) |
|||
Thread.CurrentThread.CurrentCulture = _culture; |
|||
|
|||
if (_uiCulture != null) |
|||
Thread.CurrentThread.CurrentUICulture = _uiCulture; |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|||
@ -1,34 +0,0 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Utilities |
|||
{ |
|||
internal class EnumHelper |
|||
{ |
|||
#if NET6_0_OR_GREATER
|
|||
public static T Parse<T>(ReadOnlySpan<char> key, bool ignoreCase) where T : struct |
|||
{ |
|||
return Enum.Parse<T>(key, ignoreCase); |
|||
} |
|||
|
|||
public static bool TryParse<T>(ReadOnlySpan<char> key, bool ignoreCase, out T result) where T : struct |
|||
{ |
|||
return Enum.TryParse(key, ignoreCase, out result); |
|||
} |
|||
#else
|
|||
public static T Parse<T>(string key, bool ignoreCase) where T : struct |
|||
{ |
|||
return (T)Enum.Parse(typeof(T), key, ignoreCase); |
|||
} |
|||
|
|||
public static bool TryParse<T>(string key, bool ignoreCase, out T result) where T : struct |
|||
{ |
|||
return Enum.TryParse(key, ignoreCase, out result); |
|||
} |
|||
|
|||
public static bool TryParse<T>(ReadOnlySpan<char> key, bool ignoreCase, out T result) where T : struct |
|||
{ |
|||
return Enum.TryParse(key.ToString(), ignoreCase, out result); |
|||
} |
|||
#endif
|
|||
} |
|||
} |
|||
@ -1,43 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
|
|||
internal static class Polyfills |
|||
{ |
|||
#if !NET6_0_OR_GREATER
|
|||
|
|||
public static bool TryDequeue<T>(this Queue<T> queue, [MaybeNullWhen(false)]out T item) |
|||
{ |
|||
if (queue.Count == 0) |
|||
{ |
|||
item = default; |
|||
return false; |
|||
} |
|||
|
|||
item = queue.Dequeue(); |
|||
return true; |
|||
} |
|||
|
|||
#endif
|
|||
} |
|||
|
|||
#if !NET7_0_OR_GREATER
|
|||
|
|||
namespace System.Diagnostics.CodeAnalysis |
|||
{ |
|||
[System.AttributeUsage( |
|||
System.AttributeTargets.Method | System.AttributeTargets.Parameter | System.AttributeTargets.Property, |
|||
AllowMultiple = false, Inherited = false)] |
|||
internal sealed class UnscopedRefAttribute : Attribute |
|||
{ |
|||
} |
|||
|
|||
struct S |
|||
{ |
|||
int _field; |
|||
|
|||
// Okay: `field` has the ref-safe-to-escape of `this` which is *calling method* because
|
|||
// it is a `ref`
|
|||
[UnscopedRef] ref int Prop1 => ref _field; |
|||
} |
|||
} |
|||
#endif
|
|||
Loading…
Reference in new issue