diff --git a/.github/workflows/dotnet-core.yml b/.github/workflows/dotnet-core.yml
index 41a1d8b..a8b06ab 100644
--- a/.github/workflows/dotnet-core.yml
+++ b/.github/workflows/dotnet-core.yml
@@ -45,7 +45,7 @@ jobs:
run: dotnet pack -v normal -c Release --no-restore --include-symbols --include-source -p:SymbolPackageFormat=snupkg -p:PackageVersion=1.0.0-pre+$GITHUB_RUN_ID src/$PROJECT_NAME/$PROJECT_NAME.*proj
- name: Upload Artifact
if: matrix.os == 'ubuntu-latest'
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: nupkg
path: ./artifacts/pkg/Release/${{ env.PROJECT_NAME }}.*.nupkg
@@ -55,7 +55,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download Artifact
- uses: actions/download-artifact@v1
+ uses: actions/download-artifact@v4
with:
name: nupkg
- name: Push to GitHub Feed
diff --git a/src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs
index 7208fcb..7fc31d2 100644
--- a/src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs
+++ b/src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs
@@ -1,13 +1,28 @@
using System;
+using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Synercoding.Primitives.JsonConverters;
+///
+/// Converts a object to or from JSON.
+///
public class PointJsonConverter : JsonConverter
{
+ ///
+ /// Thread-safe instance of to be reused.
+ ///
public static PointJsonConverter Instance { get; } = new();
+ ///
+ /// Read a object from the .
+ ///
+ /// The reader that should contain a .
+ /// The expected type to convert.
+ /// An object that specifies serialization options to use.
+ /// The that was read from the .
+ /// Throws when the does not contain .
public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
@@ -50,8 +65,14 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe
throw new JsonException();
}
+ ///
+ /// Write a to the .
+ ///
+ /// Writer to write the to.
+ /// The to write.
+ /// An object that specifies serialization options to use.
public override void Write(Utf8JsonWriter writer, Point value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString());
+ writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
}
}
\ No newline at end of file
diff --git a/src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs
index e860b27..a4a1b70 100644
--- a/src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs
+++ b/src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs
@@ -1,13 +1,28 @@
using System;
+using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Synercoding.Primitives.JsonConverters;
+///
+/// Converts a object to or from JSON.
+///
public class RectangleJsonConverter : JsonConverter
{
+ ///
+ /// Thread-safe instance of to be reused.
+ ///
public static RectangleJsonConverter Instance { get; } = new();
+ ///
+ /// Read a object from the .
+ ///
+ /// The reader that should contain a .
+ /// The expected type to convert.
+ /// An object that specifies serialization options to use.
+ /// The that was read from the .
+ /// Throws when the does not contain .
public override Rectangle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
@@ -58,8 +73,14 @@ public override Rectangle Read(ref Utf8JsonReader reader, Type typeToConvert, Js
throw new JsonException();
}
+ ///
+ /// Write a to the .
+ ///
+ /// Writer to write the to.
+ /// The to write.
+ /// An object that specifies serialization options to use.
public override void Write(Utf8JsonWriter writer, Rectangle value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString());
+ writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
}
}
diff --git a/src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs
index 2d0ae51..b9db000 100644
--- a/src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs
+++ b/src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs
@@ -1,13 +1,28 @@
using System;
+using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Synercoding.Primitives.JsonConverters;
+///
+/// Converts a object to or from JSON.
+///
public class SizeJsonConverter : JsonConverter
{
+ ///
+ /// Thread-safe instance of to be reused.
+ ///
public static SizeJsonConverter Instance { get; } = new();
+ ///
+ /// Read a object from the .
+ ///
+ /// The reader that should contain a .
+ /// The expected type to convert.
+ /// An object that specifies serialization options to use.
+ /// The that was read from the .
+ /// Throws when the does not contain .
public override Size Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
@@ -50,8 +65,14 @@ public override Size Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSer
throw new JsonException();
}
+ ///
+ /// Write a to the .
+ ///
+ /// Writer to write the to.
+ /// The to write.
+ /// An object that specifies serialization options to use.
public override void Write(Utf8JsonWriter writer, Size value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString());
+ writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
}
}
diff --git a/src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs
index 3f82f4d..de5dfd9 100644
--- a/src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs
+++ b/src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs
@@ -1,13 +1,28 @@
using System;
+using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Synercoding.Primitives.JsonConverters;
+///
+/// Converts a object to or from JSON.
+///
public class SpacingJsonConverter : JsonConverter
{
+ ///
+ /// Thread-safe instance of to be reused.
+ ///
public static SpacingJsonConverter Instance { get; } = new();
+ ///
+ /// Read a object from the .
+ ///
+ /// The reader that should contain a .
+ /// The expected type to convert.
+ /// An object that specifies serialization options to use.
+ /// The that was read from the .
+ /// Throws when the does not contain .
public override Spacing Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
@@ -58,8 +73,14 @@ public override Spacing Read(ref Utf8JsonReader reader, Type typeToConvert, Json
throw new JsonException();
}
+ ///
+ /// Write a to the .
+ ///
+ /// Writer to write the to.
+ /// The to write.
+ /// An object that specifies serialization options to use.
public override void Write(Utf8JsonWriter writer, Spacing value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString());
+ writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
}
}
diff --git a/src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs
index fc5f0f0..45b14b3 100644
--- a/src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs
+++ b/src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs
@@ -1,13 +1,28 @@
using System;
+using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Synercoding.Primitives.JsonConverters;
+///
+/// Converts a object to or from JSON.
+///
public class UnitJsonConverter : JsonConverter
{
+ ///
+ /// Thread-safe instance of to be reused.
+ ///
public static UnitJsonConverter Instance { get; } = new();
+ ///
+ /// Read a object from the .
+ ///
+ /// The reader that should contain a .
+ /// The expected type to convert.
+ /// An object that specifies serialization options to use.
+ /// The that was read from the .
+ /// Throws when the does not contain .
public override Unit Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
@@ -15,15 +30,21 @@ public override Unit Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSer
var textValue = reader.GetString() ?? throw new JsonException();
- if (Unit.TryParse(textValue, out var unit))
+ if (Unit.TryParse(textValue, CultureInfo.InvariantCulture, out var unit))
return unit;
throw new JsonException();
}
+ ///
+ /// Write a to the .
+ ///
+ /// Writer to write the to.
+ /// The to write.
+ /// An object that specifies serialization options to use.
public override void Write(Utf8JsonWriter writer, Unit value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString());
+ writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
}
}
diff --git a/src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs b/src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs
index b632d1d..87a9a28 100644
--- a/src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs
+++ b/src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs
@@ -1,20 +1,35 @@
using System;
+using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Synercoding.Primitives.JsonConverters;
+///
+/// Converts a object to or from JSON.
+///
public class ValueJsonConverter : JsonConverter
{
+ ///
+ /// Thread-safe instance of to be reused.
+ ///
public static ValueJsonConverter Instance { get; } = new();
+ ///
+ /// Read a object from the .
+ ///
+ /// The reader that should contain a .
+ /// The expected type to convert.
+ /// An object that specifies serialization options to use.
+ /// The that was read from the .
+ /// Throws when the does not contain .
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))
+ if (Value.TryParse(textValue, CultureInfo.InvariantCulture, out var value))
return value;
throw new JsonException();
@@ -50,8 +65,14 @@ public override Value Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe
throw new JsonException();
}
+ ///
+ /// Write a to the .
+ ///
+ /// Writer to write the to.
+ /// The to write.
+ /// An object that specifies serialization options to use.
public override void Write(Utf8JsonWriter writer, Value value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString());
+ writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
}
}
diff --git a/src/Synercoding.Primitives/PackageDetails.props b/src/Synercoding.Primitives/PackageDetails.props
index 8beb102..a3db11f 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.
- Limit to latest .NET version (8) and add System.Json serialization support.
+ Added IParsable support and added overload for ToString to be culture aware.
\ No newline at end of file
diff --git a/src/Synercoding.Primitives/Point.cs b/src/Synercoding.Primitives/Point.cs
index e2e1f57..a43d61e 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.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
@@ -9,7 +10,7 @@ namespace Synercoding.Primitives;
/// A value type representing a point in a 2D space.
///
[JsonConverter(typeof(JsonConverters.PointJsonConverter))]
-public readonly record struct Point : IConvertable, IEquatable
+public readonly record struct Point : IConvertable, IEquatable, IParsable
{
///
/// Constructor for a .
@@ -85,7 +86,15 @@ public bool Equals(Point other)
///
public override string ToString()
- => $"X: {X}, Y: {Y}";
+ => ToString(null);
+
+ ///
+ /// Returns a string representation of the point using the specified format provider.
+ ///
+ /// The format provider to use for formatting numeric values.
+ /// A string representation of the point.
+ public string ToString(IFormatProvider? provider)
+ => $"X: {X.ToString(provider)}, Y: {Y.ToString(provider)}";
///
/// Parse a string into a
@@ -94,8 +103,27 @@ public override string ToString()
/// A that was represented by .
/// Throws if can not be parsed.
public static Point Parse(string s)
+ => Parse(s, null);
+
+ ///
+ /// Try to converts a string representation of a into a .
+ ///
+ /// to be parsed.
+ /// Ref parameter with the parsed .
+ /// A to indicate if the parsing was successful.
+ public static bool TryParse([NotNullWhen(true)] string? s, out Point point)
+ => TryParse(s, null, out point);
+
+ ///
+ /// Parse a string into a
+ ///
+ /// to be parsed.
+ /// Format provider used when parsing values.
+ /// A that was represented by .
+ /// Throws if can not be parsed.
+ public static Point Parse(string s, IFormatProvider? provider)
{
- if (TryParse(s, out var value))
+ if (TryParse(s, provider, out var value))
return value;
throw new ArgumentException("Argument can't be parsed.", nameof(s));
@@ -105,20 +133,24 @@ public static Point Parse(string s)
/// Try to converts a string representation of a into a .
///
/// to be parsed.
- /// Ref parameter with the parsed .
+ /// Format provider used when parsing values.
+ /// Out parameter with the parsed .
/// A to indicate if the parsing was successful.
- public static bool TryParse(string s, out Point point)
+ public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Point result)
{
- point = default;
+ result = default;
+
+ if (s is null)
+ return false;
s = s.Trim();
var match = Regex.Match(s, "^X: ?(.+), ?Y: ?(.+)$");
if (match.Success && match.Groups.Count == 3)
{
- if (Value.TryParse(match.Groups[1].Value, out var x) && Value.TryParse(match.Groups[2].Value, out var y))
+ if (Value.TryParse(match.Groups[1].Value, provider, out var x) && Value.TryParse(match.Groups[2].Value, provider, out var y))
{
- point = new Point(x, y);
+ result = new Point(x, y);
return true;
}
}
diff --git a/src/Synercoding.Primitives/Rectangle.cs b/src/Synercoding.Primitives/Rectangle.cs
index 76f00f0..fec3787 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.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
@@ -9,7 +10,7 @@ namespace Synercoding.Primitives;
/// Value type representing a rectangle.
///
[JsonConverter(typeof(JsonConverters.RectangleJsonConverter))]
-public readonly record struct Rectangle : IConvertable, IEquatable
+public readonly record struct Rectangle : IConvertable, IEquatable, IParsable
{
///
/// Constructor for .
@@ -159,7 +160,15 @@ public bool Equals(Rectangle other)
///
public override string ToString()
- => $"LLX: {LLX}, LLY: {LLY}, URX: {URX}, URY: {URY}";
+ => ToString(null);
+
+ ///
+ /// Returns a string representation of the rectangle using the specified format provider.
+ ///
+ /// The format provider to use for formatting numeric values.
+ /// A string representation of the rectangle.
+ public string ToString(IFormatProvider? provider)
+ => $"LLX: {LLX.ToString(provider)}, LLY: {LLY.ToString(provider)}, URX: {URX.ToString(provider)}, URY: {URY.ToString(provider)}";
///
/// Parse a string into a
@@ -168,8 +177,27 @@ public override string ToString()
/// A that was represented by .
/// Throws if can not be parsed.
public static Rectangle Parse(string s)
+ => Parse(s, null);
+
+ ///
+ /// Try to converts a string representation of a into a .
+ ///
+ /// to be parsed.
+ /// Out parameter with the parsed .
+ /// A to indicate if the parsing was successful.
+ public static bool TryParse([NotNullWhen(true)] string s, out Rectangle result)
+ => TryParse(s, null, out result);
+
+ ///
+ /// Parse a string into a
+ ///
+ /// to be parsed.
+ /// Format provider used when parsing values.
+ /// A that was represented by .
+ /// Throws if can not be parsed.
+ public static Rectangle Parse(string s, IFormatProvider? provider)
{
- if (TryParse(s, out var value))
+ if (TryParse(s, provider, out var value))
return value;
throw new ArgumentException("Argument can't be parsed.", nameof(s));
@@ -179,23 +207,27 @@ public static Rectangle Parse(string s)
/// Try to converts a string representation of a into a .
///
/// to be parsed.
- /// Ref parameter with the parsed .
+ /// Format provider used when parsing values.
+ /// Out parameter with the parsed .
/// A to indicate if the parsing was successful.
- public static bool TryParse(string s, out Rectangle rectangle)
+ public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Rectangle result)
{
- rectangle = default;
+ result = default;
+
+ if(s is null)
+ return false;
s = s.Trim();
var match = Regex.Match(s, "^LLX: ?(.+), ?LLY: ?(.+), ?URX: ?(.+), ?URY: ?(.+)$");
if (match.Success && match.Groups.Count == 5)
{
- if (Value.TryParse(match.Groups[1].Value, out var llx)
- && Value.TryParse(match.Groups[2].Value, out var lly)
- && Value.TryParse(match.Groups[3].Value, out var urx)
- && Value.TryParse(match.Groups[4].Value, out var ury))
+ if (Value.TryParse(match.Groups[1].Value, provider, out var llx)
+ && Value.TryParse(match.Groups[2].Value, provider, out var lly)
+ && Value.TryParse(match.Groups[3].Value, provider, out var urx)
+ && Value.TryParse(match.Groups[4].Value, provider, out var ury))
{
- rectangle = new Rectangle(llx, lly, urx, ury);
+ result = new Rectangle(llx, lly, urx, ury);
return true;
}
}
diff --git a/src/Synercoding.Primitives/Size.cs b/src/Synercoding.Primitives/Size.cs
index d056553..d9bf731 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.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
@@ -9,7 +10,7 @@ namespace Synercoding.Primitives;
/// A value type representing a size using and .
///
[JsonConverter(typeof(JsonConverters.SizeJsonConverter))]
-public readonly record struct Size : IConvertable, IEquatable
+public readonly record struct Size : IConvertable, IEquatable, IParsable
{
///
/// Constructor for a .
@@ -106,7 +107,15 @@ public bool Equals(Size other)
///
public override string ToString()
- => $"W: {Width}, H: {Height}";
+ => ToString(null);
+
+ ///
+ /// Returns a string representation of the size using the specified format provider.
+ ///
+ /// The format provider to use for formatting numeric values.
+ /// A string representation of the size.
+ public string ToString(IFormatProvider? provider)
+ => $"W: {Width.ToString(provider)}, H: {Height.ToString(provider)}";
///
/// Parse a string into a
@@ -115,8 +124,27 @@ public override string ToString()
/// A that was represented by .
/// Throws if can not be parsed.
public static Size Parse(string s)
+ => Parse(s, null);
+
+ ///
+ /// Try to converts a string representation of a into a .
+ ///
+ /// to be parsed.
+ /// Ref parameter with the parsed .
+ /// A to indicate if the parsing was successful.
+ public static bool TryParse([NotNullWhen(true)] string s, out Size result)
+ => TryParse(s, null, out result);
+
+ ///
+ /// Parse a string into a
+ ///
+ /// to be parsed.
+ /// Format provider used when parsing values.
+ /// A that was represented by .
+ /// Throws if can not be parsed.
+ public static Size Parse(string s, IFormatProvider? provider)
{
- if (TryParse(s, out var value))
+ if (TryParse(s, provider, out var value))
return value;
throw new ArgumentException("Argument can't be parsed.", nameof(s));
@@ -126,20 +154,24 @@ public static Size Parse(string s)
/// Try to converts a string representation of a into a .
///
/// to be parsed.
- /// Ref parameter with the parsed .
+ /// Format provider used when parsing values.
+ /// Out parameter with the parsed .
/// A to indicate if the parsing was successful.
- public static bool TryParse(string s, out Size size)
+ public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Size result)
{
- size = default;
+ result = default;
+
+ if (s is null)
+ return false;
s = s.Trim();
var match = Regex.Match(s, "^W: ?(.+), ?H: ?(.+)$");
if (match.Success && match.Groups.Count == 3)
{
- if(Value.TryParse(match.Groups[1].Value, out var width) && Value.TryParse(match.Groups[2].Value, out var height))
+ if (Value.TryParse(match.Groups[1].Value, provider, out var width) && Value.TryParse(match.Groups[2].Value, provider, out var height))
{
- size = new Size(width, height);
+ result = new Size(width, height);
return true;
}
}
diff --git a/src/Synercoding.Primitives/Spacing.cs b/src/Synercoding.Primitives/Spacing.cs
index bd84858..a81268b 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.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
@@ -9,7 +10,7 @@ namespace Synercoding.Primitives;
/// Value type representing spacing in or around an object.
///
[JsonConverter(typeof(JsonConverters.SpacingJsonConverter))]
-public readonly record struct Spacing : IConvertable, IEquatable
+public readonly record struct Spacing : IConvertable, IEquatable, IParsable
{
///
/// Constructor for .
@@ -117,11 +118,19 @@ public override int GetHashCode()
///
public override string ToString()
+ => ToString(null);
+
+ ///
+ /// Returns a string representation of the spacing using the specified format provider.
+ ///
+ /// The format provider to use for formatting numeric values.
+ /// A string representation of the spacing.
+ public string ToString(IFormatProvider? provider)
{
if (Left == Top && Top == Right && Right == Bottom)
- return $"All: {Left}";
+ return $"All: {Left.ToString(provider)}";
- return $"L: {Left}, T: {Top}, R: {Right}, B: {Bottom}";
+ return $"L: {Left.ToString(provider)}, T: {Top.ToString(provider)}, R: {Right.ToString(provider)}, B: {Bottom.ToString(provider)}";
}
///
@@ -143,8 +152,27 @@ public bool Equals(Spacing other)
/// A that was represented by .
/// Throws if can not be parsed.
public static Spacing Parse(string s)
+ => Parse(s, null);
+
+ ///
+ /// Try to converts a string representation of a into a .
+ ///
+ /// to be parsed.
+ /// Ref parameter with the parsed .
+ /// A to indicate if the parsing was successful.
+ public static bool TryParse([NotNullWhen(true)] string? s, [MaybeNullWhen(false)] out Spacing result)
+ => TryParse(s, null, out result);
+
+ ///
+ /// Parse a string into a
+ ///
+ /// to be parsed.
+ /// Format provider used when parsing values.
+ /// A that was represented by .
+ /// Throws if can not be parsed.
+ public static Spacing Parse(string s, IFormatProvider? provider)
{
- if (TryParse(s, out var value))
+ if (TryParse(s, provider, out var value))
return value;
throw new ArgumentException("Argument can't be parsed.", nameof(s));
@@ -154,29 +182,33 @@ public static Spacing Parse(string s)
/// Try to converts a string representation of a into a .
///
/// to be parsed.
- /// Ref parameter with the parsed .
+ /// Format provider used when parsing values.
+ /// Out parameter with the parsed .
/// A to indicate if the parsing was successful.
- public static bool TryParse(string s, out Spacing spacing)
+ public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Spacing result)
{
- spacing = default;
+ result = default;
+
+ if (s is null)
+ return false;
s = s.Trim();
if (s.StartsWith("All:") && Value.TryParse(s.Substring(4).TrimStart(), out var all))
{
- spacing = new Spacing(all);
+ result = new Spacing(all);
return true;
}
var match = Regex.Match(s, "^L: ?(.+), ?T: ?(.+), ?R: ?(.+), ?B: ?(.+)$");
if (match.Success && match.Groups.Count == 5)
{
- if (Value.TryParse(match.Groups[1].Value, out var left)
- && Value.TryParse(match.Groups[2].Value, out var top)
- && Value.TryParse(match.Groups[3].Value, out var right)
- && Value.TryParse(match.Groups[4].Value, out var bottom))
+ if (Value.TryParse(match.Groups[1].Value, provider, out var left)
+ && Value.TryParse(match.Groups[2].Value, provider, out var top)
+ && Value.TryParse(match.Groups[3].Value, provider, out var right)
+ && Value.TryParse(match.Groups[4].Value, provider, out var bottom))
{
- spacing = new Spacing(left, top, right, bottom);
+ result = new Spacing(left, top, right, bottom);
return true;
}
}
diff --git a/src/Synercoding.Primitives/Unit.cs b/src/Synercoding.Primitives/Unit.cs
index 14a5f65..7583338 100644
--- a/src/Synercoding.Primitives/Unit.cs
+++ b/src/Synercoding.Primitives/Unit.cs
@@ -1,7 +1,7 @@
using Synercoding.Primitives.Extensions;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
-using System.Text.RegularExpressions;
namespace Synercoding.Primitives;
@@ -9,13 +9,13 @@ namespace Synercoding.Primitives;
/// Value type representing an .
///
[JsonConverter(typeof(JsonConverters.UnitJsonConverter))]
-public readonly record struct Unit : IEquatable
+public readonly record struct Unit : IEquatable, IParsable
{
private Unit(double perInch, UnitDesignation unitDesignation)
{
if (perInch <= 0)
throw new ArgumentOutOfRangeException(nameof(perInch), "The value needs to be a non-zero-non-negative number.");
- if (!Enum.IsDefined(typeof(UnitDesignation), unitDesignation))
+ if (!Enum.IsDefined(unitDesignation))
throw new ArgumentOutOfRangeException(nameof(unitDesignation), $"The value needs to be a defined value of {nameof(UnitDesignation)}.");
PerInch = perInch;
@@ -43,8 +43,20 @@ public bool Equals(Unit other)
}
///
- public override string ToString()
- => $"{Designation.Shortform()} ({PerInch} per inch)";
+ public override string ToString()
+ => ToString(null);
+
+ ///
+ /// Returns a string representation of the unit using the specified format provider.
+ ///
+ /// The format provider to use for formatting numeric values in pixel units (DPI). Ignored for other unit types.
+ /// A string representation of the unit. For pixel units, returns "dpi(value)" format. For other units, returns their short form (e.g., "mm", "cm", "in", "pts").
+ public string ToString(IFormatProvider? formatProvider)
+ => Designation switch
+ {
+ UnitDesignation.Pixels => $"dpi({PerInch.ToString(formatProvider)})",
+ var x => x.Shortform()
+ };
///
public override int GetHashCode() => HashCode.Combine(PerInch, Designation);
@@ -74,14 +86,14 @@ public override string ToString()
///
/// The DPI the will represent.
/// The representing pixels at a certain DPI.
- public static Unit Pixels(int dpi) => new Unit(dpi, UnitDesignation.Pixels);
+ public static Unit Pixels(double dpi) => new Unit(dpi, UnitDesignation.Pixels);
///
- /// Get the that correspons to the .
+ /// Get the that corresponds to the .
///
/// The to get the for.
/// The correct .
- /// Throws when is provided. can only be used in combination with DPI by using the method.
+ /// Throws when is provided. can only be used in combination with DPI by using the method.
public static Unit FromDesignation(UnitDesignation designation)
=> designation switch
{
@@ -93,15 +105,24 @@ public static Unit FromDesignation(UnitDesignation designation)
_ => throw new NotImplementedException($"{designation} can not be used to get a Unit type.")
};
+ ///
+ /// Parse a string into a .
+ ///
+ /// to be parsed.
+ /// A that was represented by .
+ public static Unit Parse(string s)
+ => Parse(s, null);
+
///
/// Parse a string into a
///
/// to be parsed.
+ /// Format provider used when parsing DPI values.
/// A that was represented by .
/// Throws if can not be parsed.
- public static Unit Parse(string s)
+ public static Unit Parse(string s, IFormatProvider? provider)
{
- if (TryParse(s, out var unit))
+ if (TryParse(s, provider, out var unit))
return unit;
throw new ArgumentException("Argument can't be parsed.", nameof(s));
@@ -111,41 +132,53 @@ public static Unit Parse(string s)
/// Try to converts a string representation of a into a .
///
/// to be parsed.
- /// Ref parameter with the parsed .
+ /// Out parameter with the parsed .
/// A to indicate if the parsing was successful.
- public static bool TryParse(string s, out Unit unit)
+ public static bool TryParse([NotNullWhen(true)] string? s, [MaybeNullWhen(false)] out Unit result)
+ => TryParse(s, null, out result);
+
+ ///
+ /// Try to converts a string representation of a into a .
+ ///
+ /// to be parsed.
+ /// Format provider used when parsing DPI values.
+ /// Out parameter with the parsed .
+ /// A to indicate if the parsing was successful.
+ public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Unit result)
{
+ result = default;
+ if (string.IsNullOrEmpty(s))
+ return false;
+
s = s.Trim();
if (Enum.TryParse(s, true, out var designation) && designation != UnitDesignation.Pixels)
{
- unit = FromDesignation(designation);
+ result = FromDesignation(designation);
return true;
}
- unit = s.ToLowerInvariant() switch
+ result = s.ToLowerInvariant() switch
{
UnitDesignationExtensions.MM => Millimeters,
UnitDesignationExtensions.CM => Centimeters,
UnitDesignationExtensions.IN => Inches,
UnitDesignationExtensions.PTS => Points,
- "millimeter" => Millimeters,
- "centimeter" => Centimeters,
- "inch" => Inches,
- "point" => Points,
+ "millimeter" or "millimeters" => Millimeters,
+ "centimeter" or "centimeters" => Centimeters,
+ "inch" or "inches" or "\"" => Inches,
+ "point" or "points" => Points,
_ => default
};
- if(unit == default && s.StartsWith("dpi"))
+ if (result == default && s.StartsWith("dpi(", StringComparison.OrdinalIgnoreCase) && s.EndsWith(')'))
{
- var match = Regex.Match(s, "^dpi\\(([1-9][0-9]*(?:\\.[0-9]+)?)\\)$");
- if(match.Success && match.Groups.Count == 2)
+ if (double.TryParse(s[4..^1], provider, out double dpi))
{
- var dpi = int.Parse(match.Groups[1].Value);
- unit = Pixels(dpi);
+ result = Pixels(dpi);
}
}
- return unit != default;
+ return result != default;
}
}
diff --git a/src/Synercoding.Primitives/UnitDesignation.cs b/src/Synercoding.Primitives/UnitDesignation.cs
index e5f579f..47d9d0e 100644
--- a/src/Synercoding.Primitives/UnitDesignation.cs
+++ b/src/Synercoding.Primitives/UnitDesignation.cs
@@ -25,4 +25,4 @@ public enum UnitDesignation : byte
/// Inches
///
Inches = 5
-}
+}
\ No newline at end of file
diff --git a/src/Synercoding.Primitives/Value.cs b/src/Synercoding.Primitives/Value.cs
index 2969d56..e569cea 100644
--- a/src/Synercoding.Primitives/Value.cs
+++ b/src/Synercoding.Primitives/Value.cs
@@ -1,6 +1,7 @@
using Synercoding.Primitives.Abstract;
using Synercoding.Primitives.Extensions;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.Json.Serialization;
@@ -11,7 +12,7 @@ namespace Synercoding.Primitives;
///
/// 3mm or 2 inches
[JsonConverter(typeof(JsonConverters.ValueJsonConverter))]
-public readonly record struct Value : IConvertable, IComparable, IComparable, IEquatable
+public readonly record struct Value : IConvertable, IComparable, IComparable, IEquatable, IParsable
{
private const int ROUND_DIGITS = 15;
@@ -77,7 +78,15 @@ public override int GetHashCode()
///
public override string ToString()
- => $"{Raw.ToString(CultureInfo.InvariantCulture)} {Unit.Designation.Shortform()}";
+ => ToString(null);
+
+ ///
+ /// Returns a string representation of the value using the specified format provider.
+ ///
+ /// The format provider to use for formatting numeric values.
+ /// A string representation of the value.
+ public string ToString(IFormatProvider? provider)
+ => $"{Raw.ToString(provider)} {Unit.Designation.Shortform()}";
///
public bool Equals(Value other)
@@ -234,9 +243,33 @@ public bool Equals(Value other)
/// to be parsed.
/// A that was represented by .
/// Throws if can not be parsed.
- public static Value Parse(string s)
+ /// Throws when is null.
+ public static Value Parse(string? s)
+ => Parse(s, null);
+
+ ///
+ /// Try to converts a string representation of a into a .
+ ///
+ /// to be parsed.
+ /// Out parameter with the parsed .
+ /// A to indicate if the parsing was successful.
+ public static bool TryParse([NotNullWhen(true)] string? s, out Value value)
+ => TryParse(s, null, out value);
+
+ ///
+ /// Parse a string into a
+ ///
+ /// to be parsed.
+ /// Format provider used when parsing values.
+ /// The parsed value
+ /// Throws if can not be parsed.
+ /// Throws when is null.
+ public static Value Parse(string? s, IFormatProvider? provider)
{
- if (TryParse(s, out var value))
+ if (s is null)
+ throw new ArgumentNullException(nameof(s));
+
+ if (TryParse(s, provider, out var value))
return value;
throw new ArgumentException("Argument can't be parsed.", nameof(s));
@@ -246,11 +279,15 @@ public static Value Parse(string s)
/// Try to converts a string representation of a into a .
///
/// to be parsed.
- /// Ref parameter with the parsed .
+ /// Format provider used when parsing values.
+ /// Out parameter with the parsed .
/// A to indicate if the parsing was successful.
- public static bool TryParse(string s, out Value value)
+ public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Value result)
{
- value = default;
+ result = default;
+
+ if (s is null)
+ return false;
s = s.Trim();
@@ -258,9 +295,9 @@ public static bool TryParse(string s, out Value value)
while (index < s.Length)
{
- if (Unit.TryParse(s.Substring(index), out var unit) && double.TryParse(s.Substring(0, index), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var number))
+ if (Unit.TryParse(s.Substring(index), provider, out var unit) && double.TryParse(s.Substring(0, index), provider, out var number))
{
- value = new Value(number, unit);
+ result = new Value(number, unit);
return true;
}
index++;
diff --git a/src/Synercoding.Primitives/ValueCreator.cs b/src/Synercoding.Primitives/ValueCreator.cs
index 6377b94..ed6a690 100644
--- a/src/Synercoding.Primitives/ValueCreator.cs
+++ b/src/Synercoding.Primitives/ValueCreator.cs
@@ -34,10 +34,10 @@ public static class ValueCreator
public static Value Pts(double pts) => new Value(pts, Unit.Points);
///
- /// Create a new with
+ /// Create a new with
///
/// The amount of pixels
/// The dpi
/// A new object.
- public static Value Pixels(double dots, int dpi) => new Value(dots, Unit.Pixels(dpi));
+ public static Value Pixels(double dots, double dpi) => new Value(dots, Unit.Pixels(dpi));
}
diff --git a/tests/Synercoding.Primitives.Tests/PointTests.cs b/tests/Synercoding.Primitives.Tests/PointTests.cs
index 4a82122..0963351 100644
--- a/tests/Synercoding.Primitives.Tests/PointTests.cs
+++ b/tests/Synercoding.Primitives.Tests/PointTests.cs
@@ -1,10 +1,12 @@
using System.Collections.Generic;
+using System.Globalization;
using Xunit;
namespace Synercoding.Primitives.Tests;
public class PointTests
{
+
[Fact]
public void EqualityOperator_InchAndMillimeters_NotEqual()
{
@@ -35,10 +37,10 @@ public void EqualityOperator_InchAnd254Millimeters_AreEqual()
[Theory]
[MemberData(nameof(DataForTryParse_With_IsCorrect))]
- public void TryParse_With_IsCorrect(string input, Point value)
+ public void TryParse_With_IsCorrect(string input, Point value, CultureInfo culture)
{
// Act
- _ = Point.TryParse(input, out var result);
+ _ = Point.TryParse(input, culture, out var result);
// Assert
Assert.Equal(value, result);
@@ -47,16 +49,21 @@ public void TryParse_With_IsCorrect(string input, Point value)
public static IEnumerable