Remove IEnumerable from range and add more boxed reads.

This commit is contained in:
Eugene Wang
2025-11-25 07:31:36 -05:00
parent d2a1678164
commit 8d4e3a2708
5 changed files with 151 additions and 45 deletions

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<!--change these in each release-->
<VersionPrefix>4.0.0.0</VersionPrefix>
<VersionSuffix>alpha.19</VersionSuffix>
<VersionSuffix>alpha.21</VersionSuffix>
<!--keep it the same until major # changes-->
<AssemblyVersion>4.0.0.0</AssemblyVersion>

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace System.Runtime.CompilerServices
{
#if !NET5_0_OR_GREATER
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class IsExternalInit {}
#endif // !NET5_0_OR_GREATER
#if !NET7_0_OR_GREATER
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute {}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public CompilerFeatureRequiredAttribute(string featureName)
{
FeatureName = featureName;
}
public string FeatureName { get; }
public bool IsOptional { get; init; }
public const string RefStructs = nameof(RefStructs);
public const string RequiredMembers = nameof(RequiredMembers);
}
#endif // !NET7_0_OR_GREATER
}
namespace System.Diagnostics.CodeAnalysis
{
#if !NET7_0_OR_GREATER
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
internal sealed class SetsRequiredMembersAttribute : Attribute {}
#endif
}

View File

@@ -273,15 +273,20 @@ namespace NTwain.Data
/// A more dotnet-friendly representation of <see cref="TW_RANGE"/>.
/// </summary>
/// <typeparam name="TValue"></typeparam>
public partial record Range<TValue> : IEnumerable<TValue>
public partial record Range<TValue>
{
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; }
public required TValue MinValue { get; set; }
public required TValue MaxValue { get; set; }
public required TValue StepSize { get; set; }
public required TValue DefaultValue { get; set; }
public required TValue CurrentValue { get; set; }
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
/// <summary>
/// Tries to enumerate the range values.
/// This could be expensive depending on the range size.
/// </summary>
/// <returns></returns>
public IEnumerable<TValue> Enumerate()
{
if (MinValue is not IConvertible)
throw new NotSupportedException($"The value type {typeof(TValue).Name} is not supported for range enumeration.");
@@ -290,12 +295,10 @@ namespace NTwain.Data
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()
{
return ((IEnumerable<TValue>)this).GetEnumerator();
while (de.MoveNext())
{
yield return de.Current;
}
}
}
@@ -322,7 +325,7 @@ namespace NTwain.Data
TWON.ONEVALUE => ToEnumerable(OneValue),
TWON.ARRAY => ArrayValue ?? [],
TWON.ENUMERATION => EnumValue?.Items ?? [],
TWON.RANGE => RangeValue != null ? RangeValue.ToArray() : [],
TWON.RANGE => RangeValue != null ? RangeValue.Enumerate() : [],
_ => [],
};
}

View File

@@ -175,7 +175,7 @@ namespace NTwain.Data
}
}
public static Enumeration<object> ReadEnumerationBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
public static Enumeration<object> ReadEnumerationBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
{
Enumeration<object> retVal = new();
@@ -319,7 +319,7 @@ namespace NTwain.Data
return retVal;
}
public static IList<object> ReadArrayBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
public static IList<object> ReadArrayBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
{
if (cap.ConType != TWON.ARRAY || cap.hContainer == IntPtr.Zero) return Array.Empty<object>();
@@ -413,11 +413,9 @@ namespace NTwain.Data
}
}
public static Range<object> 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 Range<object>();
if (cap.ConType != TWON.RANGE || cap.hContainer == IntPtr.Zero) return retVal;
if (cap.ConType != TWON.RANGE || cap.hContainer == IntPtr.Zero) return null;
var lockedPtr = memMgr.Lock(cap.hContainer);
@@ -436,17 +434,24 @@ namespace NTwain.Data
itemType = (TWTY)Marshal.ReadInt16(lockedPtr);
lockedPtr += 2;
}
retVal.MinValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
var minValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.MaxValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
var maxValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.StepSize = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
var stepSize = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.CurrentValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
var currentValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.DefaultValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
var defaultValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
return retVal;
return new Range<object>
{
MinValue = minValue,
MaxValue = maxValue,
StepSize = stepSize,
CurrentValue = currentValue,
DefaultValue = defaultValue
};
}
finally
{
@@ -459,11 +464,9 @@ namespace NTwain.Data
}
}
public static Range<TValue> ReadRange<TValue>(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) where TValue : struct
public static Range<TValue>? ReadRange<TValue>(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) where TValue : struct
{
var retVal = new Range<TValue>();
if (cap.ConType != TWON.RANGE || cap.hContainer == IntPtr.Zero) return retVal;
if (cap.ConType != TWON.RANGE || cap.hContainer == IntPtr.Zero) return null;
var lockedPtr = memMgr.Lock(cap.hContainer);
@@ -482,17 +485,24 @@ namespace NTwain.Data
itemType = (TWTY)Marshal.ReadInt16(lockedPtr);
lockedPtr += 2;
}
retVal.MinValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
var minValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.MaxValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
var maxValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.StepSize = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
var stepSize = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.CurrentValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
var currentValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.DefaultValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
var defaultValue = ReadTWTYData<TValue>(lockedPtr, itemType, 0);
lockedPtr += 4;
return retVal;
return new Range<TValue>
{
MinValue = minValue,
MaxValue = maxValue,
StepSize = stepSize,
CurrentValue = currentValue,
DefaultValue = defaultValue
};
}
finally
{

View File

@@ -88,7 +88,8 @@ namespace NTwain
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRange<TValue>(this).CurrentValue);
var range = twcap.ReadRange<TValue>(this);
if (range != null) value.Add(range.CurrentValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
@@ -110,7 +111,7 @@ namespace NTwain
/// <returns></returns>
public STS GetCapCurrentBoxed(CAP cap, out List<object> value)
{
value = new List<object>();
value = [];
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
@@ -128,7 +129,8 @@ namespace NTwain
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRangeBoxed(this).CurrentValue);
var range = twcap.ReadRangeBoxed(this);
if (range != null) value.Add(range.CurrentValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArrayBoxed(this);
@@ -165,7 +167,7 @@ namespace NTwain
/// <returns></returns>
public STS GetCapDefault<TValue>(CAP cap, out List<TValue> value) where TValue : struct
{
value = new List<TValue>();
value = [];
var sts = GetCapDefault(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
@@ -182,7 +184,8 @@ namespace NTwain
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRange<TValue>(this).DefaultValue);
var range = twcap.ReadRange<TValue>(this);
if (range != null) value.Add(range.DefaultValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
@@ -204,7 +207,7 @@ namespace NTwain
/// <returns></returns>
public STS GetCapDefaultBoxed(CAP cap, out List<object> value)
{
value = new List<object>();
value = [];
var sts = GetCapDefault(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
@@ -222,7 +225,8 @@ namespace NTwain
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRangeBoxed(this).DefaultValue);
var range = twcap.ReadRangeBoxed(this);
if (range != null) value.Add(range.DefaultValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArrayBoxed(this);
@@ -651,7 +655,8 @@ namespace NTwain
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRange<TValue>(this).CurrentValue);
var range = twcap.ReadRange<TValue>(this);
if (range != null) value.Add(range.CurrentValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
@@ -664,6 +669,47 @@ namespace NTwain
return sts;
}
/// <summary>
/// Resets a CAP's current value to power-on default.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS ResetCapBoxed(CAP cap, out List<object> value)
{
value = [];
var sts = ResetCap(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
{
case TWON.ONEVALUE:
var read = twcap.ReadOneValueBoxed(this);
if (read != null) value.Add(read);
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumerationBoxed(this);
if (twenum.Items != null && twenum.CurrentIndex < twenum.Items.Length)
{
value.Add(twenum.Items[twenum.CurrentIndex]);
}
break;
case TWON.RANGE:
var range = twcap.ReadRangeBoxed(this);
if (range != null) value.Add(range.CurrentValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArrayBoxed(this);
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
break;
default:
twcap.Free(this); break;
}
}
return sts;
}
/// <summary>
/// Resets all CAP values and constraint to power-on defaults.
/// </summary>