Cleanup boxed types.

This commit is contained in:
Eugene Wang
2025-11-25 06:31:31 -05:00
parent ce96d0c361
commit e6a21dde7c
4 changed files with 99 additions and 123 deletions

View File

@@ -1,72 +0,0 @@
using NTwain.Data;
using System;
using System.Collections;
using System.Collections.Generic;
namespace NTwain.Caps;
public record ValueContainer<TValue>
{
public TWON ContainerType { get; set; }
public TValue? OneValue { get; set; }
public IList<TValue>? ArrayValue { get; set; }
public EnumValue<TValue>? EnumValue { get; set; }
public RangeValue<TValue>? RangeValue { get; set; }
public IEnumerable<TValue> GetValues()
{
return ContainerType switch
{
TWON.ONEVALUE => ToEnumerable(OneValue),
TWON.ARRAY => ArrayValue ?? [],
TWON.ENUMERATION => EnumValue?.Items ?? [],
TWON.RANGE => RangeValue != null ? GenerateRangeValues(RangeValue) : [],
_ => [],
};
}
private IEnumerable<TValue> ToEnumerable(TValue? value)
{
if (value == null) yield break;
yield return value;
}
private IEnumerable<TValue> GenerateRangeValues(RangeValue<TValue> range)
{
var dynamicType = typeof(DynamicEnumerator<>);
var genericType = dynamicType.MakeGenericType(typeof(TValue));
var de = Activator.CreateInstance(genericType, range.Min, range.Max, range.Step) as IEnumerator;
if (de == null) yield break;
while (de.MoveNext())
{
yield return (TValue)de.Current;
}
}
}
public record EnumValue<TValue>
{
public TValue[] Items { get; set; } = [];
public int CurrentIndex { get; set; }
public int DefaultIndex { get; set; }
}
public record RangeValue<TValue>
{
public TValue Min { get; set; }
public TValue Max { get; set; }
public TValue Step { get; set; }
public TValue DefaultValue;
public TValue CurrentValue;
}

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
@@ -258,33 +260,37 @@ namespace NTwain.Data
/// A more dotnet-friendly representation of <see cref="TW_ENUMERATION"/>.
/// </summary>
/// <typeparam name="TValue"></typeparam>
public class Enumeration<TValue>
public record Enumeration<TValue>
{
public int CurrentIndex;
public int CurrentIndex { get; set; }
public int DefaultIndex;
public int DefaultIndex { get; set; }
public TValue[]? Items;
public TValue[] Items { get; set; } = [];
}
/// <summary>
/// A more dotnet-friendly representation of <see cref="TW_RANGE"/>.
/// </summary>
/// <typeparam name="TValue"></typeparam>
public partial class Range<TValue> : IEnumerable<TValue> where TValue : struct
public partial record Range<TValue> : IEnumerable<TValue>
{
public TValue MinValue;
public TValue MaxValue;
public TValue StepSize;
public TValue DefaultValue;
public TValue CurrentValue;
public TValue MinValue { get; set; }
public TValue MaxValue { get; set; }
public TValue StepSize { get; set; }
public TValue DefaultValue { get; set; }
public TValue CurrentValue { get; set; }
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
{
if (MinValue is not IConvertible)
throw new NotSupportedException($"The value type {typeof(TValue).Name} is not supported for range enumeration.");
return new DynamicEnumerator<TValue>(MinValue, MaxValue, StepSize);
var dynamicType = typeof(DynamicEnumerator<>);
var genericType = dynamicType.MakeGenericType(typeof(TValue));
var de = (IEnumerator<TValue>)Activator.CreateInstance(genericType, MinValue, MaxValue, StepSize)!;
return de;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
@@ -292,16 +298,40 @@ namespace NTwain.Data
return ((IEnumerable<TValue>)this).GetEnumerator();
}
}
/// <summary>
/// A more dotnet-friendly representation of <see cref="TW_RANGE"/> with boxed values.
/// A more dotnet-friendly container of CAP value.
/// </summary>
public partial class RangeBoxed
/// <typeparam name="TValue"></typeparam>
public record ValueContainer<TValue>
{
public object MinValue;
public object MaxValue;
public object StepSize;
public object DefaultValue;
public object CurrentValue;
public TWON ContainerType { get; set; }
public TValue? OneValue { get; set; }
public IList<TValue>? ArrayValue { get; set; }
public Enumeration<TValue>? EnumValue { get; set; }
public Range<TValue>? RangeValue { get; set; }
public IEnumerable<TValue> GetValues()
{
return ContainerType switch
{
TWON.ONEVALUE => ToEnumerable(OneValue),
TWON.ARRAY => ArrayValue ?? [],
TWON.ENUMERATION => EnumValue?.Items ?? [],
TWON.RANGE => RangeValue != null ? RangeValue.ToArray() : [],
_ => [],
};
}
private IEnumerable<TValue> ToEnumerable(TValue? value)
{
if (value == null) yield break;
yield return value;
}
}
partial struct TW_FIX32 : IEquatable<TW_FIX32>, IConvertible

View File

@@ -413,9 +413,9 @@ namespace NTwain.Data
}
}
public static RangeBoxed ReadRangeBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
public static Range<object> ReadRangeBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
{
var retVal = new RangeBoxed();
var retVal = new Range<object>();
if (cap.ConType != TWON.RANGE || cap.hContainer == IntPtr.Zero) return retVal;

View File

@@ -108,7 +108,7 @@ namespace NTwain
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapCurrentBoxed(CAP cap, out List<object> value)
public STS GetCapCurrentBoxed(CAP cap, out List<object> value)
{
value = new List<object>();
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
@@ -202,7 +202,7 @@ namespace NTwain
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapDefaultBoxed(CAP cap, out List<object> value)
public STS GetCapDefaultBoxed(CAP cap, out List<object> value)
{
value = new List<object>();
var sts = GetCapDefault(cap, out TW_CAPABILITY twcap);
@@ -273,24 +273,12 @@ namespace NTwain
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null)
{
value.EnumValue = new EnumValue<TValue>
{
CurrentIndex = twenum.CurrentIndex,
DefaultIndex = twenum.DefaultIndex,
Items = twenum.Items
};
value.EnumValue = twenum;
}
break;
case TWON.RANGE:
var range = twcap.ReadRange<TValue>(this);
value.RangeValue = new RangeValue<TValue>
{
Min = range.MinValue,
Max = range.MaxValue,
Step = range.StepSize,
DefaultValue = range.DefaultValue,
CurrentValue = range.CurrentValue
};
value.RangeValue = range;
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
@@ -314,7 +302,7 @@ namespace NTwain
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapValuesBoxed(CAP cap, out ValueContainer<object> value)
public STS GetCapValuesBoxed(CAP cap, out ValueContainer<object> value)
{
value = new ValueContainer<object> { ContainerType = TWON.DONTCARE };
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
@@ -330,24 +318,12 @@ namespace NTwain
var twenum = twcap.ReadEnumerationBoxed(this);
if (twenum.Items != null)
{
value.EnumValue = new EnumValue<object>
{
CurrentIndex = twenum.CurrentIndex,
DefaultIndex = twenum.DefaultIndex,
Items = twenum.Items
};
value.EnumValue = twenum;
}
break;
case TWON.RANGE:
var range = twcap.ReadRangeBoxed(this);
value.RangeValue = new RangeValue<object>
{
Min = range.MinValue,
Max = range.MaxValue,
Step = range.StepSize,
DefaultValue = range.DefaultValue,
CurrentValue = range.CurrentValue
};
value.RangeValue = range;
break;
case TWON.ARRAY:
var twarr = twcap.ReadArrayBoxed(this);
@@ -459,6 +435,48 @@ namespace NTwain
return SetCap(ref twcap);
}
/// <summary>
/// A cap value setter for all kinds of container types.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS SetCap<TValue>(CAP cap, ValueContainer<TValue> value) where TValue : struct
{
switch (value.ContainerType)
{
case TWON.ONEVALUE:
{
var twcap = ValueWriter.CreateOneValueCap(cap, this, value.OneValue);
return SetCap(ref twcap);
}
case TWON.ENUMERATION:
{
if (value.EnumValue == null)
throw new ArgumentException("EnumValue cannot be null when ContainerType is ENUMERATION.", nameof(value));
var twcap = ValueWriter.CreateEnumCap(cap, this, value.EnumValue);
return SetCap(ref twcap);
}
case TWON.RANGE:
{
if (value.RangeValue == null)
throw new ArgumentException("RangeValue cannot be null when ContainerType is RANGE.", nameof(value));
var twcap = ValueWriter.CreateRangeCap(cap, this, value.RangeValue);
return SetCap(ref twcap);
}
case TWON.ARRAY:
{
if (value.ArrayValue == null)
throw new ArgumentException("ArrayValue cannot be null when ContainerType is ARRAY.", nameof(value));
var twcap = ValueWriter.CreateArrayCap(cap, this, value.ArrayValue);
return SetCap(ref twcap);
}
default:
throw new ArgumentException("Unsupported ContainerType for setting CAP.", nameof(value));
}
}
/// <summary>
/// Sets a CAP's constraint values.
/// An easy way to create a value is to use the