forked from amkovkov/GranuSightSoftware2
210 lines
7.7 KiB
C#
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);
|
|
}
|
|
} |