Files
GSS2Rework/GSS2.Core/Helpers/ControlValueHelper.cs
T
amkovkov 821144a691 fix: typos
TOO many typos
2026-03-11 12:46:21 +03:00

210 lines
7.7 KiB
C#

using System.Collections;
using LibCameraSharp;
namespace GSS2.Core.Helpers;
public static class ControlValueHelper
{
private static readonly Dictionary<Type, Func<object, ControlId, object?>> _parsers = new()
{
{ typeof(bool ), (obj, _) => Parse<bool >(obj, bool .TryParse) },
{ typeof(byte ), (obj, _) => Parse<byte >(obj, byte .TryParse) },
{ typeof(float ), (obj, _) => Parse<float >(obj, float .TryParse) },
{ typeof(long ), (obj, _) => Parse<long >(obj, long .TryParse) },
{ typeof(ushort ), (obj, _) => Parse<ushort>(obj, ushort.TryParse) },
{ typeof(uint ), (obj, _) => Parse<uint >(obj, uint .TryParse) },
{ typeof(int ), ParseInt },
// int - особый случай потому что он может использовать ControlId.Enumerators для преобразования строкового "enum" в значение
{ typeof(Rectangle), ParseRectangle },
{ typeof(Size ), ParseSize },
{ typeof(Point ), ParsePoint }
};
private delegate bool ParseValueDelegate<T>(string s, out T value);
private static object? Parse<T>(object obj, ParseValueDelegate<T> parser) where T : struct
{
if (obj is T value)
return value;
if (obj is string str && parser(str, out var parsed))
return parsed;
return null;
}
private static object? ParseInt(object obj, ControlId id)
{
if (obj is int value)
return value;
if (obj is string str)
{
if (int.TryParse(str, out value))
return value;
var match = id.Enumerators.FirstOrDefault(e => e.Value == str);
if (!match.Equals(default(KeyValuePair<int, string>)))
return match.Key;
}
return null;
}
private static object? ParseRectangle(object obj, ControlId id)
{
if (obj is Rectangle value)
return value;
if (obj is IEnumerable enumerable)
{
var list = enumerable.Cast<string>();
if (list.Count() != 4)
return null;
if (!int.TryParse(list.Skip(0).First(), out var x))
return null;
if (!int.TryParse(list.Skip(1).First(), out var y))
return null;
if (!uint.TryParse(list.Skip(2).First(), out var width))
return null;
if (!uint.TryParse(list.Skip(3).First(), out var height))
return null;
return new Rectangle(x, y, width, height);
}
return null;
}
private static object? ParseSize(object obj, ControlId id)
{
if (obj is Size value)
return value;
if (obj is IEnumerable enumerable)
{
var list = enumerable.Cast<string>();
if (list.Count() != 2)
return null;
if (!uint.TryParse(list.Skip(0).First(), out var width))
return null;
if (!uint.TryParse(list.Skip(1).First(), out var height))
return null;
return new Size(width, height);
}
return null;
}
private static object? ParsePoint(object obj, ControlId id)
{
if (obj is Point value)
return value;
if (obj is IEnumerable enumerable)
{
var list = enumerable.Cast<string>();
if (list.Count() != 4)
return null;
if (!int.TryParse(list.Skip(0).First(), out var x))
return null;
if (!int.TryParse(list.Skip(1).First(), out var y))
return null;
return new Point(x, y);
}
return null;
}
private static T ConvertValue<T>(object obj, ControlId id)
{
if (!_parsers.TryGetValue(typeof(T), out var parser))
throw new Exception();
var parsed = parser(obj, id);
if (parsed is null || parsed is not T typed)
throw new Exception();
return typed;
}
private static IEnumerable<T> ConvertArray<T>(object obj, ControlId id)
{
if (obj is not IEnumerable enumerable)
throw new Exception();
var list = enumerable.Cast<object>().ToList();
if ((ulong)list.Count() != id.Size)
throw new Exception();
var array = new T[list.Count()];
for (int i = 0; i < list.Count(); i++)
array[i] = ConvertValue<T>(list.Skip(i).First(), id);
return array.AsEnumerable();
}
private static ControlValue ConvertControlValue(object obj, ControlId id, ControlInfo info)
{
if (!ControlValue.ValueTypes.TryGetValue(id.Type, out var valueType))
throw new InvalidOperationException();
var convertValue = typeof(ControlValueHelper)
.GetMethod(nameof(ConvertValue), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)?
.MakeGenericMethod([valueType]);
if (convertValue is null)
throw new Exception();
var value = convertValue.Invoke(null, [obj, id]);
var controlValueType = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(a => a.GetTypes())
.FirstOrDefault(t =>
!t.IsAbstract &&
t.BaseType is { IsGenericType: true } baseType &&
baseType.GetGenericTypeDefinition() == typeof(ControlValue<>) &&
baseType.GetGenericArguments()[0] == valueType);
if (controlValueType is null)
throw new Exception();
var constructor = controlValueType.GetConstructor([valueType]);
if (constructor is null)
throw new Exception();
var controlValue = constructor.Invoke([value]);
if (controlValue is null || controlValue is not ControlValue typed)
throw new Exception();
return typed;
}
private static ControlValue ConvertControlArray(object obj, ControlId id, ControlInfo info)
{
if (!ControlValue.ArrayTypes.TryGetValue(id.Type, out var arrayType))
throw new Exception();
if (!ControlValue.ValueTypes.TryGetValue(id.Type, out var valueType))
throw new InvalidOperationException();
var convertArray = typeof(ControlValueHelper)
.GetMethod(nameof(ConvertArray), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)?
.MakeGenericMethod([valueType]);
if (convertArray is null)
throw new Exception();
var value = convertArray.Invoke(null, [obj, id]);
var controlValueType = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(a => a.GetTypes())
.FirstOrDefault(t =>
!t.IsAbstract &&
t.BaseType is { IsGenericType: true } baseType &&
baseType.GetGenericTypeDefinition() == typeof(ControlValue<>) &&
baseType.GetGenericArguments()[0] == arrayType);
if (controlValueType is null)
throw new Exception();
var constructor = controlValueType.GetConstructor([arrayType]);
if (constructor is null)
throw new Exception();
var controlValue = constructor.Invoke([value]);
if (controlValue is null || controlValue is not ControlValue typed)
throw new Exception();
return typed;
}
public static ControlValue Convert(object obj, ControlId id, ControlInfo info)
{
if (!id.IsArray)
return ConvertControlValue(obj, id, info);
return ConvertControlArray(obj, id, info);
}
}