Skip to content

Commit f0842a1

Browse files
committed
Made primitives implement IParsable<Unit>, dpi/pixel units can now be made with doubles instead of ints, and becaus of the IParsable, IFormatProvider is supported during parsing.
1 parent c50bad9 commit f0842a1

21 files changed

+903
-439
lines changed

src/Synercoding.Primitives/JsonConverters/PointJsonConverter.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,24 @@
44

55
namespace Synercoding.Primitives.JsonConverters;
66

7+
/// <summary>
8+
/// Converts a <see cref="Point"/> object to or from JSON.
9+
/// </summary>
710
public class PointJsonConverter : JsonConverter<Point>
811
{
12+
/// <summary>
13+
/// Thread-safe instance of <see cref="PointJsonConverter"/> to be reused.
14+
/// </summary>
915
public static PointJsonConverter Instance { get; } = new();
1016

17+
/// <summary>
18+
/// Read a <see cref="Point"/> object from the <paramref name="reader"/>.
19+
/// </summary>
20+
/// <param name="reader">The reader that should contain a <see cref="Point"/>.</param>
21+
/// <param name="typeToConvert">The expected type to convert.</param>
22+
/// <param name="options">An object that specifies serialization options to use.</param>
23+
/// <returns>The <see cref="Point"/> that was read from the <paramref name="reader"/>.</returns>
24+
/// <exception cref="JsonException">Throws when the <paramref name="reader"/> does not contain <see cref="Point"/>.</exception>
1125
public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1226
{
1327
if (reader.TokenType == JsonTokenType.String)
@@ -50,6 +64,12 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe
5064
throw new JsonException();
5165
}
5266

67+
/// <summary>
68+
/// Write a <see cref="Point"/> to the <paramref name="writer"/>.
69+
/// </summary>
70+
/// <param name="writer">Writer to write the <see cref="Point"/> to.</param>
71+
/// <param name="value">The <see cref="Point"/> to write.</param>
72+
/// <param name="options">An object that specifies serialization options to use.</param>
5373
public override void Write(Utf8JsonWriter writer, Point value, JsonSerializerOptions options)
5474
{
5575
writer.WriteStringValue(value.ToString());

src/Synercoding.Primitives/JsonConverters/RectangleJsonConverter.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,24 @@
44

55
namespace Synercoding.Primitives.JsonConverters;
66

7+
/// <summary>
8+
/// Converts a <see cref="Rectangle"/> object to or from JSON.
9+
/// </summary>
710
public class RectangleJsonConverter : JsonConverter<Rectangle>
811
{
12+
/// <summary>
13+
/// Thread-safe instance of <see cref="RectangleJsonConverter"/> to be reused.
14+
/// </summary>
915
public static RectangleJsonConverter Instance { get; } = new();
1016

17+
/// <summary>
18+
/// Read a <see cref="Rectangle"/> object from the <paramref name="reader"/>.
19+
/// </summary>
20+
/// <param name="reader">The reader that should contain a <see cref="Rectangle"/>.</param>
21+
/// <param name="typeToConvert">The expected type to convert.</param>
22+
/// <param name="options">An object that specifies serialization options to use.</param>
23+
/// <returns>The <see cref="Rectangle"/> that was read from the <paramref name="reader"/>.</returns>
24+
/// <exception cref="JsonException">Throws when the <paramref name="reader"/> does not contain <see cref="Rectangle"/>.</exception>
1125
public override Rectangle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1226
{
1327
if (reader.TokenType == JsonTokenType.String)
@@ -58,6 +72,12 @@ public override Rectangle Read(ref Utf8JsonReader reader, Type typeToConvert, Js
5872
throw new JsonException();
5973
}
6074

75+
/// <summary>
76+
/// Write a <see cref="Rectangle"/> to the <paramref name="writer"/>.
77+
/// </summary>
78+
/// <param name="writer">Writer to write the <see cref="Rectangle"/> to.</param>
79+
/// <param name="value">The <see cref="Rectangle"/> to write.</param>
80+
/// <param name="options">An object that specifies serialization options to use.</param>
6181
public override void Write(Utf8JsonWriter writer, Rectangle value, JsonSerializerOptions options)
6282
{
6383
writer.WriteStringValue(value.ToString());

src/Synercoding.Primitives/JsonConverters/SizeJsonConverter.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,24 @@
44

55
namespace Synercoding.Primitives.JsonConverters;
66

7+
/// <summary>
8+
/// Converts a <see cref="Size"/> object to or from JSON.
9+
/// </summary>
710
public class SizeJsonConverter : JsonConverter<Size>
811
{
12+
/// <summary>
13+
/// Thread-safe instance of <see cref="SizeJsonConverter"/> to be reused.
14+
/// </summary>
915
public static SizeJsonConverter Instance { get; } = new();
1016

17+
/// <summary>
18+
/// Read a <see cref="Size"/> object from the <paramref name="reader"/>.
19+
/// </summary>
20+
/// <param name="reader">The reader that should contain a <see cref="Value"/>.</param>
21+
/// <param name="typeToConvert">The expected type to convert.</param>
22+
/// <param name="options">An object that specifies serialization options to use.</param>
23+
/// <returns>The <see cref="Size"/> that was read from the <paramref name="reader"/>.</returns>
24+
/// <exception cref="JsonException">Throws when the <paramref name="reader"/> does not contain <see cref="Size"/>.</exception>
1125
public override Size Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1226
{
1327
if (reader.TokenType == JsonTokenType.String)
@@ -50,6 +64,12 @@ public override Size Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSer
5064
throw new JsonException();
5165
}
5266

67+
/// <summary>
68+
/// Write a <see cref="Size"/> to the <paramref name="writer"/>.
69+
/// </summary>
70+
/// <param name="writer">Writer to write the <see cref="Size"/> to.</param>
71+
/// <param name="value">The <see cref="Size"/> to write.</param>
72+
/// <param name="options">An object that specifies serialization options to use.</param>
5373
public override void Write(Utf8JsonWriter writer, Size value, JsonSerializerOptions options)
5474
{
5575
writer.WriteStringValue(value.ToString());

src/Synercoding.Primitives/JsonConverters/SpacingJsonConverter.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,24 @@
44

55
namespace Synercoding.Primitives.JsonConverters;
66

7+
/// <summary>
8+
/// Converts a <see cref="Spacing"/> object to or from JSON.
9+
/// </summary>
710
public class SpacingJsonConverter : JsonConverter<Spacing>
811
{
12+
/// <summary>
13+
/// Thread-safe instance of <see cref="SpacingJsonConverter"/> to be reused.
14+
/// </summary>
915
public static SpacingJsonConverter Instance { get; } = new();
1016

17+
/// <summary>
18+
/// Read a <see cref="Spacing"/> object from the <paramref name="reader"/>.
19+
/// </summary>
20+
/// <param name="reader">The reader that should contain a <see cref="Spacing"/>.</param>
21+
/// <param name="typeToConvert">The expected type to convert.</param>
22+
/// <param name="options">An object that specifies serialization options to use.</param>
23+
/// <returns>The <see cref="Spacing"/> that was read from the <paramref name="reader"/>.</returns>
24+
/// <exception cref="JsonException">Throws when the <paramref name="reader"/> does not contain <see cref="Spacing"/>.</exception>
1125
public override Spacing Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1226
{
1327
if (reader.TokenType == JsonTokenType.String)
@@ -58,6 +72,12 @@ public override Spacing Read(ref Utf8JsonReader reader, Type typeToConvert, Json
5872
throw new JsonException();
5973
}
6074

75+
/// <summary>
76+
/// Write a <see cref="Spacing"/> to the <paramref name="writer"/>.
77+
/// </summary>
78+
/// <param name="writer">Writer to write the <see cref="Spacing"/> to.</param>
79+
/// <param name="value">The <see cref="Spacing"/> to write.</param>
80+
/// <param name="options">An object that specifies serialization options to use.</param>
6181
public override void Write(Utf8JsonWriter writer, Spacing value, JsonSerializerOptions options)
6282
{
6383
writer.WriteStringValue(value.ToString());

src/Synercoding.Primitives/JsonConverters/UnitJsonConverter.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,47 @@
11
using System;
2+
using System.Globalization;
23
using System.Text.Json;
34
using System.Text.Json.Serialization;
45

56
namespace Synercoding.Primitives.JsonConverters;
67

8+
/// <summary>
9+
/// Converts a <see cref="Unit"/> object to or from JSON.
10+
/// </summary>
711
public class UnitJsonConverter : JsonConverter<Unit>
812
{
13+
/// <summary>
14+
/// Thread-safe instance of <see cref="UnitJsonConverter"/> to be reused.
15+
/// </summary>
916
public static UnitJsonConverter Instance { get; } = new();
1017

18+
/// <summary>
19+
/// Read a <see cref="Unit"/> object from the <paramref name="reader"/>.
20+
/// </summary>
21+
/// <param name="reader">The reader that should contain a <see cref="Unit"/>.</param>
22+
/// <param name="typeToConvert">The expected type to convert.</param>
23+
/// <param name="options">An object that specifies serialization options to use.</param>
24+
/// <returns>The <see cref="Unit"/> that was read from the <paramref name="reader"/>.</returns>
25+
/// <exception cref="JsonException">Throws when the <paramref name="reader"/> does not contain <see cref="Unit"/>.</exception>
1126
public override Unit Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1227
{
1328
if (reader.TokenType != JsonTokenType.String)
1429
throw new JsonException();
1530

1631
var textValue = reader.GetString() ?? throw new JsonException();
1732

18-
if (Unit.TryParse(textValue, out var unit))
33+
if (Unit.TryParse(textValue, CultureInfo.InvariantCulture, out var unit))
1934
return unit;
2035

2136
throw new JsonException();
2237
}
2338

39+
/// <summary>
40+
/// Write a <see cref="Unit"/> to the <paramref name="writer"/>.
41+
/// </summary>
42+
/// <param name="writer">Writer to write the <see cref="Unit"/> to.</param>
43+
/// <param name="value">The <see cref="Unit"/> to write.</param>
44+
/// <param name="options">An object that specifies serialization options to use.</param>
2445
public override void Write(Utf8JsonWriter writer, Unit value, JsonSerializerOptions options)
2546
{
2647
writer.WriteStringValue(value.ToString());

src/Synercoding.Primitives/JsonConverters/ValueJsonConverter.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
using System;
2+
using System.Globalization;
23
using System.Text.Json;
34
using System.Text.Json.Serialization;
45

56
namespace Synercoding.Primitives.JsonConverters;
67

8+
/// <summary>
9+
/// Converts a <see cref="Value"/> object to or from JSON.
10+
/// </summary>
711
public class ValueJsonConverter : JsonConverter<Value>
812
{
13+
/// <summary>
14+
/// Thread-safe instance of <see cref="ValueJsonConverter"/> to be reused.
15+
/// </summary>
916
public static ValueJsonConverter Instance { get; } = new();
1017

18+
/// <summary>
19+
/// Read a <see cref="Value"/> object from the <paramref name="reader"/>.
20+
/// </summary>
21+
/// <param name="reader">The reader that should contain a <see cref="Value"/>.</param>
22+
/// <param name="typeToConvert">The expected type to convert.</param>
23+
/// <param name="options">An object that specifies serialization options to use.</param>
24+
/// <returns>The <see cref="Value"/> that was read from the <paramref name="reader"/>.</returns>
25+
/// <exception cref="JsonException">Throws when the <paramref name="reader"/> does not contain <see cref="Value"/>.</exception>
1126
public override Value Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1227
{
1328
if (reader.TokenType == JsonTokenType.String)
1429
{
1530
var textValue = reader.GetString() ?? throw new JsonException();
1631

17-
if (Value.TryParse(textValue, out var value))
32+
if (Value.TryParse(textValue, CultureInfo.InvariantCulture, out var value))
1833
return value;
1934

2035
throw new JsonException();
@@ -50,6 +65,12 @@ public override Value Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe
5065
throw new JsonException();
5166
}
5267

68+
/// <summary>
69+
/// Write a <see cref="Value"/> to the <paramref name="writer"/>.
70+
/// </summary>
71+
/// <param name="writer">Writer to write the <see cref="Value"/> to.</param>
72+
/// <param name="value">The <see cref="Value"/> to write.</param>
73+
/// <param name="options">An object that specifies serialization options to use.</param>
5374
public override void Write(Utf8JsonWriter writer, Value value, JsonSerializerOptions options)
5475
{
5576
writer.WriteStringValue(value.ToString());

src/Synercoding.Primitives/Point.cs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Synercoding.Primitives.Abstract;
22
using System;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.Text.Json.Serialization;
45
using System.Text.RegularExpressions;
56

@@ -9,7 +10,7 @@ namespace Synercoding.Primitives;
910
/// A value type representing a point in a 2D space.
1011
/// </summary>
1112
[JsonConverter(typeof(JsonConverters.PointJsonConverter))]
12-
public readonly record struct Point : IConvertable<Point>, IEquatable<Point>
13+
public readonly record struct Point : IConvertable<Point>, IEquatable<Point>, IParsable<Point>
1314
{
1415
/// <summary>
1516
/// Constructor for a <see cref="Point"/>.
@@ -85,7 +86,15 @@ public bool Equals(Point other)
8586

8687
/// <inheritdoc />
8788
public override string ToString()
88-
=> $"X: {X}, Y: {Y}";
89+
=> ToString(null);
90+
91+
/// <summary>
92+
/// Returns a string representation of the point using the specified format provider.
93+
/// </summary>
94+
/// <param name="provider">The format provider to use for formatting numeric values.</param>
95+
/// <returns>A string representation of the point.</returns>
96+
public string ToString(IFormatProvider? provider)
97+
=> $"X: {X.ToString(provider)}, Y: {Y.ToString(provider)}";
8998

9099
/// <summary>
91100
/// Parse a string into a <see cref="Point"/>
@@ -94,8 +103,27 @@ public override string ToString()
94103
/// <returns>A <see cref="Point"/> that was represented by <paramref name="s"/>.</returns>
95104
/// <exception cref="ArgumentException">Throws if <paramref name="s"/> can not be parsed.</exception>
96105
public static Point Parse(string s)
106+
=> Parse(s, null);
107+
108+
/// <summary>
109+
/// Try to converts a string representation of a <see cref="Point"/> into a <see cref="Point"/>.
110+
/// </summary>
111+
/// <param name="s"><see cref="string"/> to be parsed.</param>
112+
/// <param name="point">Ref parameter with the parsed <see cref="Point"/>.</param>
113+
/// <returns>A <see cref="bool"/> to indicate if the parsing was successful.</returns>
114+
public static bool TryParse([NotNullWhen(true)] string? s, out Point point)
115+
=> TryParse(s, null, out point);
116+
117+
/// <summary>
118+
/// Parse a string into a <see cref="Point"/>
119+
/// </summary>
120+
/// <param name="s"><see cref="string"/> to be parsed.</param>
121+
/// <param name="provider">Format provider used when parsing values.</param>
122+
/// <returns>A <see cref="Point"/> that was represented by <paramref name="s"/>.</returns>
123+
/// <exception cref="ArgumentException">Throws if <paramref name="s"/> can not be parsed.</exception>
124+
public static Point Parse(string s, IFormatProvider? provider)
97125
{
98-
if (TryParse(s, out var value))
126+
if (TryParse(s, provider, out var value))
99127
return value;
100128

101129
throw new ArgumentException("Argument can't be parsed.", nameof(s));
@@ -105,20 +133,24 @@ public static Point Parse(string s)
105133
/// Try to converts a string representation of a <see cref="Point"/> into a <see cref="Point"/>.
106134
/// </summary>
107135
/// <param name="s"><see cref="string"/> to be parsed.</param>
108-
/// <param name="point">Ref parameter with the parsed <see cref="Point"/>.</param>
136+
/// <param name="provider">Format provider used when parsing values.</param>
137+
/// <param name="result">Out parameter with the parsed <see cref="Point"/>.</param>
109138
/// <returns>A <see cref="bool"/> to indicate if the parsing was successful.</returns>
110-
public static bool TryParse(string s, out Point point)
139+
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Point result)
111140
{
112-
point = default;
141+
result = default;
142+
143+
if (s is null)
144+
return false;
113145

114146
s = s.Trim();
115147

116148
var match = Regex.Match(s, "^X: ?(.+), ?Y: ?(.+)$");
117149
if (match.Success && match.Groups.Count == 3)
118150
{
119-
if (Value.TryParse(match.Groups[1].Value, out var x) && Value.TryParse(match.Groups[2].Value, out var y))
151+
if (Value.TryParse(match.Groups[1].Value, provider, out var x) && Value.TryParse(match.Groups[2].Value, provider, out var y))
120152
{
121-
point = new Point(x, y);
153+
result = new Point(x, y);
122154
return true;
123155
}
124156
}

0 commit comments

Comments
 (0)