diff --git a/.github/workflows/dotnet-core.yml b/.github/workflows/dotnet-core.yml
index ef84bcf..41a1d8b 100644
--- a/.github/workflows/dotnet-core.yml
+++ b/.github/workflows/dotnet-core.yml
@@ -33,7 +33,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore
run: dotnet restore
- name: Build
@@ -73,7 +73,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Create Release NuGet package
run: |
arrTag=(${GITHUB_REF//\// })
diff --git a/Directory.Build.props b/Directory.Build.props
index 3ac1d84..9721898 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -35,65 +35,12 @@
https://github.com/synercoder/Primitives/
https://api.nuget.org/v3/index.json;
- https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json;
true
- 10.0
+ 12.0
-
-
-
-
-
- $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS
- $(DefineConstants);SUPPORTS_CODECOVERAGE
-
-
-
-
- $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS
- $(DefineConstants);SUPPORTS_CODECOVERAGE
-
-
-
-
- $(DefineConstants);SUPPORTS_MATHF
- $(DefineConstants);SUPPORTS_HASHCODE
- $(DefineConstants);SUPPORTS_SPAN_STREAM
- $(DefineConstants);SUPPORTS_ENCODING_STRING
- $(DefineConstants);SUPPORTS_CODECOVERAGE
- $(DefineConstants);SUPPORTS_CREATESPAN
-
-
-
-
-
- $(DefineConstants);SUPPORTS_MATHF
- $(DefineConstants);SUPPORTS_HASHCODE
- $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS
- $(DefineConstants);SUPPORTS_SPAN_STREAM
- $(DefineConstants);SUPPORTS_ENCODING_STRING
- $(DefineConstants);SUPPORTS_RUNTIME_INTRINSICS
- $(DefineConstants);SUPPORTS_CODECOVERAGE
- $(DefineConstants);SUPPORTS_HOTPATH
- $(DefineConstants);SUPPORTS_CREATESPAN
- $(DefineConstants);SUPPORTS_BITOPERATIONS
-
-
-
-
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index ccbf612..0c9b1de 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -2,7 +2,7 @@
- net48;netcoreapp3.1;netstandard1.6;netstandard2.0;netstandard2.1;net5.0;net6.0
+ net8.0$(MSBuildAllProjects);$(MSBuildThisFileDirectory)..\Directory.Build.propssrc
diff --git a/src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs
new file mode 100644
index 0000000..7208fcb
--- /dev/null
+++ b/src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Synercoding.Primitives.JsonConverters;
+
+public class PointJsonConverter : JsonConverter
+{
+ public static PointJsonConverter Instance { get; } = new();
+
+ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ var textValue = reader.GetString() ?? throw new JsonException();
+
+ if (Point.TryParse(textValue, out var value))
+ return value;
+
+ throw new JsonException();
+ }
+
+ if (reader.TokenType != JsonTokenType.StartObject)
+ throw new JsonException();
+
+ var complexPoint = default(Point);
+ while (reader.Read())
+ {
+ if (reader.TokenType == JsonTokenType.EndObject)
+ return complexPoint;
+
+ if (reader.TokenType == JsonTokenType.PropertyName)
+ {
+ string propertyName = reader.GetString() ?? throw new JsonException();
+ reader.Read();
+ switch (propertyName)
+ {
+ case nameof(Point.X):
+ Value width = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexPoint = complexPoint with { X = width };
+ break;
+ case nameof(Point.Y):
+ Value height = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexPoint = complexPoint with { Y = height };
+ break;
+ }
+ }
+ }
+
+ throw new JsonException();
+ }
+
+ public override void Write(Utf8JsonWriter writer, Point value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
+}
\ No newline at end of file
diff --git a/src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs
new file mode 100644
index 0000000..e860b27
--- /dev/null
+++ b/src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Synercoding.Primitives.JsonConverters;
+
+public class RectangleJsonConverter : JsonConverter
+{
+ public static RectangleJsonConverter Instance { get; } = new();
+
+ public override Rectangle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ var textValue = reader.GetString() ?? throw new JsonException();
+
+ if (Rectangle.TryParse(textValue, out var value))
+ return value;
+
+ throw new JsonException();
+ }
+
+ if (reader.TokenType != JsonTokenType.StartObject)
+ throw new JsonException();
+
+ var complexRectangle = default(Rectangle);
+ while (reader.Read())
+ {
+ if (reader.TokenType == JsonTokenType.EndObject)
+ return complexRectangle;
+
+ if (reader.TokenType == JsonTokenType.PropertyName)
+ {
+ string propertyName = reader.GetString() ?? throw new JsonException();
+ reader.Read();
+ switch (propertyName)
+ {
+ case nameof(Rectangle.LLX):
+ Value llx = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexRectangle = complexRectangle with { LLX = llx };
+ break;
+ case nameof(Rectangle.LLY):
+ Value lly = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexRectangle = complexRectangle with { LLY = lly };
+ break;
+ case nameof(Rectangle.URX):
+ Value urx = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexRectangle = complexRectangle with { URX = urx };
+ break;
+ case nameof(Rectangle.URY):
+ Value ury = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexRectangle = complexRectangle with { URY = ury };
+ break;
+ }
+ }
+ }
+
+ throw new JsonException();
+ }
+
+ public override void Write(Utf8JsonWriter writer, Rectangle value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
+}
diff --git a/src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs
new file mode 100644
index 0000000..2d0ae51
--- /dev/null
+++ b/src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Synercoding.Primitives.JsonConverters;
+
+public class SizeJsonConverter : JsonConverter
+{
+ public static SizeJsonConverter Instance { get; } = new();
+
+ public override Size Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ var textValue = reader.GetString() ?? throw new JsonException();
+
+ if (Size.TryParse(textValue, out var value))
+ return value;
+
+ throw new JsonException();
+ }
+
+ if (reader.TokenType != JsonTokenType.StartObject)
+ throw new JsonException();
+
+ var complexSize = default(Size);
+ while (reader.Read())
+ {
+ if (reader.TokenType == JsonTokenType.EndObject)
+ return complexSize;
+
+ if (reader.TokenType == JsonTokenType.PropertyName)
+ {
+ string propertyName = reader.GetString() ?? throw new JsonException();
+ reader.Read();
+ switch (propertyName)
+ {
+ case nameof(Size.Width):
+ Value width = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexSize = complexSize with { Width = width };
+ break;
+ case nameof(Size.Height):
+ Value height = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexSize = complexSize with { Height = height };
+ break;
+ }
+ }
+ }
+
+ throw new JsonException();
+ }
+
+ public override void Write(Utf8JsonWriter writer, Size value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
+}
diff --git a/src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs
new file mode 100644
index 0000000..3f82f4d
--- /dev/null
+++ b/src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Synercoding.Primitives.JsonConverters;
+
+public class SpacingJsonConverter : JsonConverter
+{
+ public static SpacingJsonConverter Instance { get; } = new();
+
+ public override Spacing Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ var textValue = reader.GetString() ?? throw new JsonException();
+
+ if (Spacing.TryParse(textValue, out var value))
+ return value;
+
+ throw new JsonException();
+ }
+
+ if (reader.TokenType != JsonTokenType.StartObject)
+ throw new JsonException();
+
+ var complexSpacing = default(Spacing);
+ while (reader.Read())
+ {
+ if (reader.TokenType == JsonTokenType.EndObject)
+ return complexSpacing;
+
+ if (reader.TokenType == JsonTokenType.PropertyName)
+ {
+ string propertyName = reader.GetString() ?? throw new JsonException();
+ reader.Read();
+ switch (propertyName)
+ {
+ case nameof(Spacing.Left):
+ Value left = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexSpacing = complexSpacing with { Left = left };
+ break;
+ case nameof(Spacing.Right):
+ Value right = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexSpacing = complexSpacing with { Right = right };
+ break;
+ case nameof(Spacing.Top):
+ Value top = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexSpacing = complexSpacing with { Top = top };
+ break;
+ case nameof(Spacing.Bottom):
+ Value bottom = ValueJsonConverter.Instance.Read(ref reader, typeof(Value), options);
+ complexSpacing = complexSpacing with { Bottom = bottom };
+ break;
+ }
+ }
+ }
+
+ throw new JsonException();
+ }
+
+ public override void Write(Utf8JsonWriter writer, Spacing value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
+}
diff --git a/src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs
new file mode 100644
index 0000000..fc5f0f0
--- /dev/null
+++ b/src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Synercoding.Primitives.JsonConverters;
+
+public class UnitJsonConverter : JsonConverter
+{
+ public static UnitJsonConverter Instance { get; } = new();
+
+ public override Unit Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType != JsonTokenType.String)
+ throw new JsonException();
+
+ var textValue = reader.GetString() ?? throw new JsonException();
+
+ if (Unit.TryParse(textValue, out var unit))
+ return unit;
+
+ throw new JsonException();
+ }
+
+ public override void Write(Utf8JsonWriter writer, Unit value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
+}
+
diff --git a/src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs
new file mode 100644
index 0000000..b632d1d
--- /dev/null
+++ b/src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Synercoding.Primitives.JsonConverters;
+
+public class ValueJsonConverter : JsonConverter
+{
+ public static ValueJsonConverter Instance { get; } = new();
+
+ public override Value Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ var textValue = reader.GetString() ?? throw new JsonException();
+
+ if (Value.TryParse(textValue, out var value))
+ return value;
+
+ throw new JsonException();
+ }
+
+ if (reader.TokenType != JsonTokenType.StartObject)
+ throw new JsonException();
+
+ var complexValue = default(Value);
+ while (reader.Read())
+ {
+ if (reader.TokenType == JsonTokenType.EndObject)
+ return complexValue;
+
+ if (reader.TokenType == JsonTokenType.PropertyName)
+ {
+ string propertyName = reader.GetString() ?? throw new JsonException();
+ reader.Read();
+ switch (propertyName)
+ {
+ case nameof(Value.Raw):
+ double raw = reader.GetDouble();
+ complexValue = complexValue with { Raw = raw };
+ break;
+ case nameof(Value.Unit):
+ Unit unit = UnitJsonConverter.Instance.Read(ref reader, typeof(Unit), options);
+ complexValue = complexValue with { Unit = unit };
+ break;
+ }
+ }
+ }
+
+ throw new JsonException();
+ }
+
+ public override void Write(Utf8JsonWriter writer, Value value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value.ToString());
+ }
+}
diff --git a/src/Synercoding.Primitives/PackageDetails.props b/src/Synercoding.Primitives/PackageDetails.props
index 14af0c7..8beb102 100644
--- a/src/Synercoding.Primitives/PackageDetails.props
+++ b/src/Synercoding.Primitives/PackageDetails.props
@@ -10,7 +10,7 @@
Synercoding.PrimitivesSynercoding.PrimitivesPrimitives with units attached (think mm, cm, in, px) that can be used for 2D graphics.
- - Fix default value of unitdesignation
+ Limit to latest .NET version (8) and add System.Json serialization support.
\ No newline at end of file
diff --git a/src/Synercoding.Primitives/Point.cs b/src/Synercoding.Primitives/Point.cs
index 741406f..e2e1f57 100644
--- a/src/Synercoding.Primitives/Point.cs
+++ b/src/Synercoding.Primitives/Point.cs
@@ -1,5 +1,6 @@
using Synercoding.Primitives.Abstract;
using System;
+using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace Synercoding.Primitives;
@@ -7,7 +8,8 @@ namespace Synercoding.Primitives;
///
/// A value type representing a point in a 2D space.
///
-public readonly struct Point : IConvertable, IEquatable
+[JsonConverter(typeof(JsonConverters.PointJsonConverter))]
+public readonly record struct Point : IConvertable, IEquatable
{
///
/// Constructor for a .
@@ -52,12 +54,12 @@ public static Point Origin
///
/// The X coordinate.
///
- public Value X { get; }
+ public Value X { get; init; }
///
/// The Y coordinate.
///
- public Value Y { get; }
+ public Value Y { get; init; }
///
public Point ConvertTo(Unit unit)
@@ -71,10 +73,6 @@ public Point ConvertTo(Unit unit)
public override int GetHashCode()
=> HashCode.Combine(X, Y);
- ///
- public override bool Equals(object? obj)
- => obj is Point unit && Equals(unit);
-
///
public bool Equals(Point other)
{
@@ -89,24 +87,6 @@ public bool Equals(Point other)
public override string ToString()
=> $"X: {X}, Y: {Y}";
- ///
- /// Returns a value that indicates whether two specified values are equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Point left, Point right)
- => left.Equals(right);
-
- ///
- /// Returns a value that indicates whether two specified values are not equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Point left, Point right)
- => !( left == right );
-
///
/// Parse a string into a
///
diff --git a/src/Synercoding.Primitives/Rectangle.cs b/src/Synercoding.Primitives/Rectangle.cs
index 9659aa9..76f00f0 100644
--- a/src/Synercoding.Primitives/Rectangle.cs
+++ b/src/Synercoding.Primitives/Rectangle.cs
@@ -1,5 +1,6 @@
using Synercoding.Primitives.Abstract;
using System;
+using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace Synercoding.Primitives;
@@ -7,7 +8,8 @@ namespace Synercoding.Primitives;
///
/// Value type representing a rectangle.
///
-public readonly struct Rectangle : IConvertable, IEquatable
+[JsonConverter(typeof(JsonConverters.RectangleJsonConverter))]
+public readonly record struct Rectangle : IConvertable, IEquatable
{
///
/// Constructor for .
@@ -88,22 +90,22 @@ public static Rectangle Zero
///
/// The lower left x coordinate.
///
- public Value LLX { get; }
+ public Value LLX { get; init; }
///
/// The lower left y coordinate.
///
- public Value LLY { get; }
+ public Value LLY { get; init; }
///
/// The upper right x coordinate.
///
- public Value URX { get; }
+ public Value URX { get; init; }
///
/// The upper right y coordinate.
///
- public Value URY { get; }
+ public Value URY { get; init; }
///
/// The width of this .
@@ -143,10 +145,6 @@ public Rectangle ConvertTo(Unit unit)
public override int GetHashCode()
=> HashCode.Combine(LLX, LLY, URX, URY);
- ///
- public override bool Equals(object? obj)
- => obj is Rectangle unit && Equals(unit);
-
///
public bool Equals(Rectangle other)
{
@@ -163,24 +161,6 @@ public bool Equals(Rectangle other)
public override string ToString()
=> $"LLX: {LLX}, LLY: {LLY}, URX: {URX}, URY: {URY}";
- ///
- /// Returns a value that indicates whether two specified values are equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Rectangle left, Rectangle right)
- => left.Equals(right);
-
- ///
- /// Returns a value that indicates whether two specified values are not equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Rectangle left, Rectangle right)
- => !( left == right );
-
///
/// Parse a string into a
///
diff --git a/src/Synercoding.Primitives/Size.cs b/src/Synercoding.Primitives/Size.cs
index b31efc2..d056553 100644
--- a/src/Synercoding.Primitives/Size.cs
+++ b/src/Synercoding.Primitives/Size.cs
@@ -1,5 +1,6 @@
using Synercoding.Primitives.Abstract;
using System;
+using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace Synercoding.Primitives;
@@ -7,7 +8,8 @@ namespace Synercoding.Primitives;
///
/// A value type representing a size using and .
///
-public readonly struct Size : IConvertable, IEquatable
+[JsonConverter(typeof(JsonConverters.SizeJsonConverter))]
+public readonly record struct Size : IConvertable, IEquatable
{
///
/// Constructor for a .
@@ -52,12 +54,12 @@ public static Size Empty
///
/// The width property.
///
- public Value Width { get; }
+ public Value Width { get; init; }
///
/// The height property.
///
- public Value Height { get; }
+ public Value Height { get; init; }
///
/// The rotated version of this .
@@ -92,10 +94,6 @@ public Size ConvertTo(Unit unit)
public override int GetHashCode()
=> HashCode.Combine(Width, Height);
- ///
- public override bool Equals(object? obj)
- => obj is Size unit && Equals(unit);
-
///
public bool Equals(Size other)
{
@@ -110,24 +108,6 @@ public bool Equals(Size other)
public override string ToString()
=> $"W: {Width}, H: {Height}";
- ///
- /// Returns a value that indicates whether two specified values are equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Size left, Size right)
- => left.Equals(right);
-
- ///
- /// Returns a value that indicates whether two specified values are not equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Size left, Size right)
- => !( left == right );
-
///
/// Parse a string into a
///
diff --git a/src/Synercoding.Primitives/Spacing.cs b/src/Synercoding.Primitives/Spacing.cs
index 74b7b0f..bd84858 100644
--- a/src/Synercoding.Primitives/Spacing.cs
+++ b/src/Synercoding.Primitives/Spacing.cs
@@ -1,5 +1,6 @@
using Synercoding.Primitives.Abstract;
using System;
+using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace Synercoding.Primitives;
@@ -7,7 +8,8 @@ namespace Synercoding.Primitives;
///
/// Value type representing spacing in or around an object.
///
-public readonly struct Spacing : IConvertable, IEquatable
+[JsonConverter(typeof(JsonConverters.SpacingJsonConverter))]
+public readonly record struct Spacing : IConvertable, IEquatable
{
///
/// Constructor for .
@@ -81,22 +83,22 @@ public static Spacing Nothing
///
/// The amount of spacing on the left side.
///
- public Value Left { get; }
+ public Value Left { get; init; }
///
/// The amount of spacing on the top side.
///
- public Value Top { get; }
+ public Value Top { get; init; }
///
/// The amount of spacing on the right side.
///
- public Value Right { get; }
+ public Value Right { get; init; }
///
/// The amount of spacing on the bottom side.
///
- public Value Bottom { get; }
+ public Value Bottom { get; init; }
///
public Spacing ConvertTo(Unit unit)
@@ -114,11 +116,13 @@ public override int GetHashCode()
=> HashCode.Combine(Left, Top, Right, Bottom);
///
- public override bool Equals(object? obj)
- => obj is Spacing unit && Equals(unit);
+ public override string ToString()
+ {
+ if (Left == Top && Top == Right && Right == Bottom)
+ return $"All: {Left}";
- ///
- public override string ToString() => $"L: {Left}, T: {Top}, R: {Right}, B: {Bottom}";
+ return $"L: {Left}, T: {Top}, R: {Right}, B: {Bottom}";
+ }
///
public bool Equals(Spacing other)
@@ -132,24 +136,6 @@ public bool Equals(Spacing other)
&& a.Bottom == b.Bottom;
}
- ///
- /// Returns a value that indicates whether two specified values are equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Spacing left, Spacing right)
- => left.Equals(right);
-
- ///
- /// Returns a value that indicates whether two specified values are not equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Spacing left, Spacing right)
- => !( left == right );
-
///
/// Parse a string into a
///
@@ -176,6 +162,12 @@ public static bool TryParse(string s, out Spacing spacing)
s = s.Trim();
+ if (s.StartsWith("All:") && Value.TryParse(s.Substring(4).TrimStart(), out var all))
+ {
+ spacing = new Spacing(all);
+ return true;
+ }
+
var match = Regex.Match(s, "^L: ?(.+), ?T: ?(.+), ?R: ?(.+), ?B: ?(.+)$");
if (match.Success && match.Groups.Count == 5)
{
diff --git a/src/Synercoding.Primitives/Synercoding.Primitives.csproj b/src/Synercoding.Primitives/Synercoding.Primitives.csproj
index aefbd57..444a59f 100644
--- a/src/Synercoding.Primitives/Synercoding.Primitives.csproj
+++ b/src/Synercoding.Primitives/Synercoding.Primitives.csproj
@@ -1,17 +1,5 @@
-
- enable
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Synercoding.Primitives/System/HashCode.cs b/src/Synercoding.Primitives/System/HashCode.cs
deleted file mode 100644
index aad27d7..0000000
--- a/src/Synercoding.Primitives/System/HashCode.cs
+++ /dev/null
@@ -1,446 +0,0 @@
-//
-// SOURCE: https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/HashCode.cs
-
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*
-The xxHash32 implementation is based on the code published by Yann Collet:
-https://raw.githubusercontent.com/Cyan4973/xxHash/5c174cfa4e45a42f94082dc0d4539b39696afea1/xxhash.c
- xxHash - Fast Hash algorithm
- Copyright (C) 2012-2016, Yann Collet
-
- BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following disclaimer
- in the documentation and/or other materials provided with the
- distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- You can contact the author at :
- - xxHash homepage: http://www.xxhash.com
- - xxHash source repository : https://github.com/Cyan4973/xxHash
-*/
-
-#if SUPPORTS_HASHCODE
-using System.Runtime.CompilerServices;
-
-[assembly: TypeForwardedTo(typeof(System.HashCode))]
-#else
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Runtime.CompilerServices;
-using System.Security.Cryptography;
-
-namespace System
-{
- // xxHash32 is used for the hash code.
- // https://github.com/Cyan4973/xxHash
- internal struct HashCode
- {
-#pragma warning disable SA1311 // Static readonly fields should begin with upper-case letter
- private static readonly uint s_seed = GenerateGlobalSeed();
-#pragma warning restore SA1311 // Static readonly fields should begin with upper-case letter
-
- private const uint Prime1 = 2654435761U;
- private const uint Prime2 = 2246822519U;
- private const uint Prime3 = 3266489917U;
- private const uint Prime4 = 668265263U;
- private const uint Prime5 = 374761393U;
-
- private uint _v1, _v2, _v3, _v4;
- private uint _queue1, _queue2, _queue3;
- private uint _length;
-
- private static uint GenerateGlobalSeed()
- {
- byte[] data = new byte[4];
-
- using (var rng = RandomNumberGenerator.Create())
- {
- rng.GetBytes(data);
- }
-
- return BitConverter.ToUInt32(data, 0);
- }
-
- public static int Combine(T1 value1)
- {
- // Provide a way of diffusing bits from something with a limited
- // input hash space. For example, many enums only have a few
- // possible hashes, only using the bottom few bits of the code. Some
- // collections are built on the assumption that hashes are spread
- // over a larger space, so diffusing the bits may help the
- // collection work more efficiently.
-
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
-
- uint hash = MixEmptyState();
- hash += 4;
-
- hash = QueueRound(hash, hc1);
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- public static int Combine(T1 value1, T2 value2)
- {
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
- var hc2 = (uint)(value2?.GetHashCode() ?? 0);
-
- uint hash = MixEmptyState();
- hash += 8;
-
- hash = QueueRound(hash, hc1);
- hash = QueueRound(hash, hc2);
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- public static int Combine(T1 value1, T2 value2, T3 value3)
- {
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
- var hc2 = (uint)(value2?.GetHashCode() ?? 0);
- var hc3 = (uint)(value3?.GetHashCode() ?? 0);
-
- uint hash = MixEmptyState();
- hash += 12;
-
- hash = QueueRound(hash, hc1);
- hash = QueueRound(hash, hc2);
- hash = QueueRound(hash, hc3);
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4)
- {
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
- var hc2 = (uint)(value2?.GetHashCode() ?? 0);
- var hc3 = (uint)(value3?.GetHashCode() ?? 0);
- var hc4 = (uint)(value4?.GetHashCode() ?? 0);
-
- Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
-
- v1 = Round(v1, hc1);
- v2 = Round(v2, hc2);
- v3 = Round(v3, hc3);
- v4 = Round(v4, hc4);
-
- uint hash = MixState(v1, v2, v3, v4);
- hash += 16;
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5)
- {
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
- var hc2 = (uint)(value2?.GetHashCode() ?? 0);
- var hc3 = (uint)(value3?.GetHashCode() ?? 0);
- var hc4 = (uint)(value4?.GetHashCode() ?? 0);
- var hc5 = (uint)(value5?.GetHashCode() ?? 0);
-
- Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
-
- v1 = Round(v1, hc1);
- v2 = Round(v2, hc2);
- v3 = Round(v3, hc3);
- v4 = Round(v4, hc4);
-
- uint hash = MixState(v1, v2, v3, v4);
- hash += 20;
-
- hash = QueueRound(hash, hc5);
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6)
- {
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
- var hc2 = (uint)(value2?.GetHashCode() ?? 0);
- var hc3 = (uint)(value3?.GetHashCode() ?? 0);
- var hc4 = (uint)(value4?.GetHashCode() ?? 0);
- var hc5 = (uint)(value5?.GetHashCode() ?? 0);
- var hc6 = (uint)(value6?.GetHashCode() ?? 0);
-
- Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
-
- v1 = Round(v1, hc1);
- v2 = Round(v2, hc2);
- v3 = Round(v3, hc3);
- v4 = Round(v4, hc4);
-
- uint hash = MixState(v1, v2, v3, v4);
- hash += 24;
-
- hash = QueueRound(hash, hc5);
- hash = QueueRound(hash, hc6);
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7)
- {
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
- var hc2 = (uint)(value2?.GetHashCode() ?? 0);
- var hc3 = (uint)(value3?.GetHashCode() ?? 0);
- var hc4 = (uint)(value4?.GetHashCode() ?? 0);
- var hc5 = (uint)(value5?.GetHashCode() ?? 0);
- var hc6 = (uint)(value6?.GetHashCode() ?? 0);
- var hc7 = (uint)(value7?.GetHashCode() ?? 0);
-
- Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
-
- v1 = Round(v1, hc1);
- v2 = Round(v2, hc2);
- v3 = Round(v3, hc3);
- v4 = Round(v4, hc4);
-
- uint hash = MixState(v1, v2, v3, v4);
- hash += 28;
-
- hash = QueueRound(hash, hc5);
- hash = QueueRound(hash, hc6);
- hash = QueueRound(hash, hc7);
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8)
- {
- var hc1 = (uint)(value1?.GetHashCode() ?? 0);
- var hc2 = (uint)(value2?.GetHashCode() ?? 0);
- var hc3 = (uint)(value3?.GetHashCode() ?? 0);
- var hc4 = (uint)(value4?.GetHashCode() ?? 0);
- var hc5 = (uint)(value5?.GetHashCode() ?? 0);
- var hc6 = (uint)(value6?.GetHashCode() ?? 0);
- var hc7 = (uint)(value7?.GetHashCode() ?? 0);
- var hc8 = (uint)(value8?.GetHashCode() ?? 0);
-
- Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
-
- v1 = Round(v1, hc1);
- v2 = Round(v2, hc2);
- v3 = Round(v3, hc3);
- v4 = Round(v4, hc4);
-
- v1 = Round(v1, hc5);
- v2 = Round(v2, hc6);
- v3 = Round(v3, hc7);
- v4 = Round(v4, hc8);
-
- uint hash = MixState(v1, v2, v3, v4);
- hash += 32;
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint Rol(uint value, int count)
- => (value << count) | (value >> (32 - count));
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4)
- {
- v1 = s_seed + Prime1 + Prime2;
- v2 = s_seed + Prime2;
- v3 = s_seed;
- v4 = s_seed - Prime1;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint Round(uint hash, uint input)
- {
- hash += input * Prime2;
- hash = Rol(hash, 13);
- hash *= Prime1;
- return hash;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint QueueRound(uint hash, uint queuedValue)
- {
- hash += queuedValue * Prime3;
- return Rol(hash, 17) * Prime4;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint MixState(uint v1, uint v2, uint v3, uint v4)
- {
- return Rol(v1, 1) + Rol(v2, 7) + Rol(v3, 12) + Rol(v4, 18);
- }
-
- private static uint MixEmptyState()
- {
- return s_seed + Prime5;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint MixFinal(uint hash)
- {
- hash ^= hash >> 15;
- hash *= Prime2;
- hash ^= hash >> 13;
- hash *= Prime3;
- hash ^= hash >> 16;
- return hash;
- }
-
- public void Add(T value)
- {
- Add(value?.GetHashCode() ?? 0);
- }
-
- public void Add(T value, IEqualityComparer comparer)
- {
- Add(comparer != null ? comparer.GetHashCode(value) : (value?.GetHashCode() ?? 0));
- }
-
- private void Add(int value)
- {
- // The original xxHash works as follows:
- // 0. Initialize immediately. We can't do this in a struct (no
- // default ctor).
- // 1. Accumulate blocks of length 16 (4 uints) into 4 accumulators.
- // 2. Accumulate remaining blocks of length 4 (1 uint) into the
- // hash.
- // 3. Accumulate remaining blocks of length 1 into the hash.
-
- // There is no need for #3 as this type only accepts ints. _queue1,
- // _queue2 and _queue3 are basically a buffer so that when
- // ToHashCode is called we can execute #2 correctly.
-
- // We need to initialize the xxHash32 state (_v1 to _v4) lazily (see
- // #0) nd the last place that can be done if you look at the
- // original code is just before the first block of 16 bytes is mixed
- // in. The xxHash32 state is never used for streams containing fewer
- // than 16 bytes.
-
- // To see what's really going on here, have a look at the Combine
- // methods.
-
- var val = (uint)value;
-
- // Storing the value of _length locally shaves of quite a few bytes
- // in the resulting machine code.
- uint previousLength = _length++;
- uint position = previousLength % 4;
-
- // Switch can't be inlined.
-
- if (position == 0)
- _queue1 = val;
- else if (position == 1)
- _queue2 = val;
- else if (position == 2)
- _queue3 = val;
- else // position == 3
- {
- if (previousLength == 3)
- Initialize(out _v1, out _v2, out _v3, out _v4);
-
- _v1 = Round(_v1, _queue1);
- _v2 = Round(_v2, _queue2);
- _v3 = Round(_v3, _queue3);
- _v4 = Round(_v4, val);
- }
- }
-
- public int ToHashCode()
- {
- // Storing the value of _length locally shaves of quite a few bytes
- // in the resulting machine code.
- uint length = _length;
-
- // position refers to the *next* queue position in this method, so
- // position == 1 means that _queue1 is populated; _queue2 would have
- // been populated on the next call to Add.
- uint position = length % 4;
-
- // If the length is less than 4, _v1 to _v4 don't contain anything
- // yet. xxHash32 treats this differently.
-
- uint hash = length < 4 ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4);
-
- // _length is incremented once per Add(Int32) and is therefore 4
- // times too small (xxHash length is in bytes, not ints).
-
- hash += length * 4;
-
- // Mix what remains in the queue
-
- // Switch can't be inlined right now, so use as few branches as
- // possible by manually excluding impossible scenarios (position > 1
- // is always false if position is not > 0).
- if (position > 0)
- {
- hash = QueueRound(hash, _queue1);
- if (position > 1)
- {
- hash = QueueRound(hash, _queue2);
- if (position > 2)
- hash = QueueRound(hash, _queue3);
- }
- }
-
- hash = MixFinal(hash);
- return (int)hash;
- }
-
-#pragma warning disable 0809
-
- // Obsolete member 'memberA' overrides non-obsolete member 'memberB'.
- // Disallowing GetHashCode and Equals is by design
-
- // * We decided to not override GetHashCode() to produce the hash code
- // as this would be weird, both naming-wise as well as from a
- // behavioral standpoint (GetHashCode() should return the object's
- // hash code, not the one being computed).
-
- // * Even though ToHashCode() can be called safely multiple times on
- // this implementation, it is not part of the contract. If the
- // implementation has to change in the future we don't want to worry
- // about people who might have incorrectly used this type.
-
- [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", error: true)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override int GetHashCode() => throw new NotSupportedException("Equality not supported");
-
- [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override bool Equals(object obj) => throw new NotSupportedException("Equality not supported");
-#pragma warning restore 0809
- }
-}
-#endif
-
-#pragma warning restore SA1636, SA1600, SA1503, SA1202, SA1101, SA1132, SA1309, SA1520, SA1108, SA1203, SA1028, SA1512, SA1308
\ No newline at end of file
diff --git a/src/Synercoding.Primitives/Unit.cs b/src/Synercoding.Primitives/Unit.cs
index 472ffb1..14a5f65 100644
--- a/src/Synercoding.Primitives/Unit.cs
+++ b/src/Synercoding.Primitives/Unit.cs
@@ -1,5 +1,6 @@
using Synercoding.Primitives.Extensions;
using System;
+using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace Synercoding.Primitives;
@@ -7,7 +8,8 @@ namespace Synercoding.Primitives;
///
/// Value type representing an .
///
-public readonly struct Unit : IEquatable
+[JsonConverter(typeof(JsonConverters.UnitJsonConverter))]
+public readonly record struct Unit : IEquatable
{
private Unit(double perInch, UnitDesignation unitDesignation)
{
@@ -23,12 +25,12 @@ private Unit(double perInch, UnitDesignation unitDesignation)
///
/// Value representing how many of this are in an inch.
///
- public double PerInch { get; }
+ public double PerInch { get; init; }
///
/// The designation of the unit.
///
- public UnitDesignation Designation { get; }
+ public UnitDesignation Designation { get; init; }
///
public bool Equals(Unit other)
@@ -44,29 +46,9 @@ public bool Equals(Unit other)
public override string ToString()
=> $"{Designation.Shortform()} ({PerInch} per inch)";
- ///
- public override bool Equals(object? obj)
- => obj is Unit unit && Equals(unit);
-
///
public override int GetHashCode() => HashCode.Combine(PerInch, Designation);
- ///
- /// Returns a value that indicates whether two specified values are equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Unit left, Unit right) => left.Equals(right);
-
- ///
- /// Returns a value that indicates whether two specified values are not equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Unit left, Unit right) => !( left == right );
-
///
/// Unit for millimeters.
///
@@ -135,7 +117,7 @@ public static bool TryParse(string s, out Unit unit)
{
s = s.Trim();
- if (Enum.TryParse(s, true, out var designation))
+ if (Enum.TryParse(s, true, out var designation) && designation != UnitDesignation.Pixels)
{
unit = FromDesignation(designation);
return true;
@@ -156,7 +138,7 @@ public static bool TryParse(string s, out Unit unit)
if(unit == default && s.StartsWith("dpi"))
{
- var match = Regex.Match(s, "^dpi\\(([0-9]+)\\)$");
+ var match = Regex.Match(s, "^dpi\\(([1-9][0-9]*(?:\\.[0-9]+)?)\\)$");
if(match.Success && match.Groups.Count == 2)
{
var dpi = int.Parse(match.Groups[1].Value);
diff --git a/src/Synercoding.Primitives/Value.cs b/src/Synercoding.Primitives/Value.cs
index 8280d40..2969d56 100644
--- a/src/Synercoding.Primitives/Value.cs
+++ b/src/Synercoding.Primitives/Value.cs
@@ -2,6 +2,7 @@
using Synercoding.Primitives.Extensions;
using System;
using System.Globalization;
+using System.Text.Json.Serialization;
namespace Synercoding.Primitives;
@@ -9,7 +10,8 @@ namespace Synercoding.Primitives;
/// Represents a double with a unit type attached.
///
/// 3mm or 2 inches
-public readonly struct Value : IConvertable, IComparable, IComparable, IEquatable
+[JsonConverter(typeof(JsonConverters.ValueJsonConverter))]
+public readonly record struct Value : IConvertable, IComparable, IComparable, IEquatable
{
private const int ROUND_DIGITS = 15;
@@ -27,12 +29,12 @@ public Value(double value, Unit unit)
///
/// The number part of the .
///
- public double Raw { get; }
+ public double Raw { get; init; }
///
/// The unit part of the .
///
- public Unit Unit { get; }
+ public Unit Unit { get; init; }
///
public Value ConvertTo(Unit unit)
@@ -77,10 +79,6 @@ public override int GetHashCode()
public override string ToString()
=> $"{Raw.ToString(CultureInfo.InvariantCulture)} {Unit.Designation.Shortform()}";
- ///
- public override bool Equals(object? obj)
- => obj is Value unit && Equals(unit);
-
///
public bool Equals(Value other)
=> CompareTo(other) == 0;
@@ -90,24 +88,6 @@ public bool Equals(Value other)
///
public static Value Zero => new Value(0, Unit.Inches);
- ///
- /// Returns a value that indicates whether two specified values are equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are equal; otherwise, false.
- public static bool operator ==(Value left, Value right)
- => left.Equals(right);
-
- ///
- /// Returns a value that indicates whether two specified values are not equal.
- ///
- /// The first value to compare.
- /// The second value to compare.
- /// true if left and right are not equal; otherwise, false.
- public static bool operator !=(Value left, Value right)
- => !( left == right );
-
///
/// Returns a value that indicates whether a specified value is less than another specified value.
///
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
index f896a2f..a8d7f09 100644
--- a/tests/Directory.Build.props
+++ b/tests/Directory.Build.props
@@ -14,7 +14,7 @@
- net6.0
+ net8.0false
diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets
index 272e157..dc35e9f 100644
--- a/tests/Directory.Build.targets
+++ b/tests/Directory.Build.targets
@@ -8,17 +8,13 @@
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
+
\ No newline at end of file
diff --git a/tests/Synercoding.Primitives.Tests/PointTests.cs b/tests/Synercoding.Primitives.Tests/PointTests.cs
index 50baf8c..4a82122 100644
--- a/tests/Synercoding.Primitives.Tests/PointTests.cs
+++ b/tests/Synercoding.Primitives.Tests/PointTests.cs
@@ -67,4 +67,28 @@ public static IEnumerable