diff --git a/Directory.Packages.props b/Directory.Packages.props index 07317381..c06ecbb0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -31,6 +31,7 @@ + diff --git a/SpreadCheetah.Test/Helpers/NoDefaultConstructorForStructsCondition.cs b/SpreadCheetah.Test/Helpers/NoDefaultConstructorForStructsCondition.cs new file mode 100644 index 00000000..92130ad8 --- /dev/null +++ b/SpreadCheetah.Test/Helpers/NoDefaultConstructorForStructsCondition.cs @@ -0,0 +1,42 @@ +using ArchUnitNET.Domain; +using ArchUnitNET.Domain.Extensions; +using ArchUnitNET.Fluent.Conditions; + +namespace SpreadCheetah.Test.Helpers; + +internal sealed class NoDefaultConstructorForStructsCondition : ICondition +{ + public string Description => "not have a default constructor"; + + public IEnumerable Check(IEnumerable objects, Architecture architecture) + { + foreach (var obj in objects) + { + yield return Check(obj); + } + } + + private static ConditionResult Check(IType type) + { + var pass = true; + + if (type is Struct structType) + { + foreach (var constructor in structType.GetConstructors()) + { + if (constructor.IsStatic is true) + continue; + + if (!constructor.Parameters.Any()) + { + pass = false; + break; + } + } + } + + return new ConditionResult(type, pass: pass, failDescription: pass ? null : "has a default constructor"); + } + + public bool CheckEmpty() => true; +} diff --git a/SpreadCheetah.Test/SpreadCheetah.Test.csproj b/SpreadCheetah.Test/SpreadCheetah.Test.csproj index 8ba70d67..199a84cf 100644 --- a/SpreadCheetah.Test/SpreadCheetah.Test.csproj +++ b/SpreadCheetah.Test/SpreadCheetah.Test.csproj @@ -24,6 +24,7 @@ + @@ -50,7 +51,6 @@ - diff --git a/SpreadCheetah.Test/Tests/ArchitectureTests.cs b/SpreadCheetah.Test/Tests/ArchitectureTests.cs new file mode 100644 index 00000000..ae0d3ca8 --- /dev/null +++ b/SpreadCheetah.Test/Tests/ArchitectureTests.cs @@ -0,0 +1,27 @@ +#if !NET5_0_OR_GREATER +using ArchUnitNET.Domain; +using ArchUnitNET.Loader; +using ArchUnitNET.xUnit; +using SpreadCheetah.Test.Helpers; +using static ArchUnitNET.Fluent.ArchRuleDefinition; + +namespace SpreadCheetah.Test.Tests; + +public class ArchitectureTests +{ + private static readonly Architecture Architecture = new ArchLoader().LoadAssemblies(typeof(Spreadsheet).Assembly).Build(); + + /// + /// Structs with a default constructor leads to a compilation error on UWP: https://github.com/sveinungf/spreadcheetah/issues/58 + /// + [Fact] + public void Architecture_NoDefaultConstructorForStructs() + { + // Arrange + var rule = Types().Should().FollowCustomCondition(new NoDefaultConstructorForStructsCondition()); + + // Act & Assert + rule.Check(Architecture); + } +} +#endif \ No newline at end of file diff --git a/SpreadCheetah/CellValues/CellValue.cs b/SpreadCheetah/CellValues/CellValue.cs index 718462ff..6b63e5b5 100644 --- a/SpreadCheetah/CellValues/CellValue.cs +++ b/SpreadCheetah/CellValues/CellValue.cs @@ -8,12 +8,12 @@ internal readonly struct CellValue [FieldOffset(0)] public readonly StringOrPrimitiveCellValue StringOrPrimitive; [FieldOffset(0)] public readonly ReadOnlyMemory Memory; +#if NET5_0_OR_GREATER public CellValue() { -#if NET5_0_OR_GREATER System.Runtime.CompilerServices.Unsafe.SkipInit(out this); -#endif } +#endif public CellValue(StringOrPrimitiveCellValue value) : this() => StringOrPrimitive = value; public CellValue(ReadOnlyMemory value) : this() => Memory = value; diff --git a/SpreadCheetah/CellValues/PrimitiveCellValue.cs b/SpreadCheetah/CellValues/PrimitiveCellValue.cs index 72fab1ac..41c604f2 100644 --- a/SpreadCheetah/CellValues/PrimitiveCellValue.cs +++ b/SpreadCheetah/CellValues/PrimitiveCellValue.cs @@ -9,12 +9,12 @@ internal readonly struct PrimitiveCellValue [FieldOffset(0)] public readonly float FloatValue; [FieldOffset(0)] public readonly double DoubleValue; +#if NET5_0_OR_GREATER public PrimitiveCellValue() { -#if NET5_0_OR_GREATER System.Runtime.CompilerServices.Unsafe.SkipInit(out this); -#endif } +#endif public PrimitiveCellValue(int value) : this() => IntValue = value; public PrimitiveCellValue(float value) : this() => FloatValue = value; diff --git a/SpreadCheetah/CellValues/StringOrPrimitiveCellValue.cs b/SpreadCheetah/CellValues/StringOrPrimitiveCellValue.cs index 1938414f..ed306552 100644 --- a/SpreadCheetah/CellValues/StringOrPrimitiveCellValue.cs +++ b/SpreadCheetah/CellValues/StringOrPrimitiveCellValue.cs @@ -5,12 +5,12 @@ internal readonly struct StringOrPrimitiveCellValue public readonly string? StringValue; public readonly PrimitiveCellValue PrimitiveValue; +#if NET5_0_OR_GREATER public StringOrPrimitiveCellValue() { -#if NET5_0_OR_GREATER System.Runtime.CompilerServices.Unsafe.SkipInit(out this); -#endif } +#endif public StringOrPrimitiveCellValue(string? value) : this() => StringValue = value; public StringOrPrimitiveCellValue(PrimitiveCellValue value) : this() => PrimitiveValue = value; diff --git a/SpreadCheetah/Helpers/PooledArray.cs b/SpreadCheetah/Helpers/PooledArray.cs index bb5348cd..022d3883 100644 --- a/SpreadCheetah/Helpers/PooledArray.cs +++ b/SpreadCheetah/Helpers/PooledArray.cs @@ -9,12 +9,6 @@ namespace SpreadCheetah.Helpers; public ReadOnlyMemory Memory => _array.AsMemory(0, _count); - public PooledArray() - { - _array = []; - _count = 0; - } - private PooledArray(T[] array, int count) { _array = array; @@ -24,7 +18,7 @@ private PooledArray(T[] array, int count) public static PooledArray Create(ICollection collection) { if (collection.Count == 0) - return new PooledArray(); + return new PooledArray([], 0); var array = ArrayPool.Shared.Rent(collection.Count);