summaryrefslogtreecommitdiffstats
path: root/src/Cepis/GeoConverter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Cepis/GeoConverter.cs')
-rw-r--r--src/Cepis/GeoConverter.cs89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/Cepis/GeoConverter.cs b/src/Cepis/GeoConverter.cs
new file mode 100644
index 0000000..f5c78de
--- /dev/null
+++ b/src/Cepis/GeoConverter.cs
@@ -0,0 +1,89 @@
+using System.Globalization;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Cepis;
+
+/// <summary>
+/// Reads the <c>geo</c> block, yielding <see langword="null"/> for anything it
+/// cannot make sense of.
+/// </summary>
+/// <remarks>
+/// A malformed coordinate is not worth losing the whole address over: the rest
+/// of the response is still useful, and an address with no coordinate is a
+/// shape callers already handle, since about 43% of CEPs have none.
+/// </remarks>
+internal sealed class GeoConverter : JsonConverter<Geo?>
+{
+ public override Geo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ using var document = JsonDocument.ParseValue(ref reader);
+ var root = document.RootElement;
+ if (root.ValueKind != JsonValueKind.Object)
+ {
+ return null;
+ }
+
+ var lat = ReadDouble(root, "lat");
+ var lon = ReadDouble(root, "lon");
+ var raio = ReadDouble(root, "raio_m");
+ var precisao = ReadString(root, "precisao");
+
+ if (lat is null || lon is null || raio is null || precisao is null)
+ {
+ return null;
+ }
+
+ return new Geo
+ {
+ Lat = lat.Value,
+ Lon = lon.Value,
+ RaioM = (int)Math.Round(raio.Value),
+ Precisao = precisao,
+ };
+ }
+
+ public override void Write(Utf8JsonWriter writer, Geo? value, JsonSerializerOptions options)
+ {
+ ArgumentNullException.ThrowIfNull(writer);
+
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
+ writer.WriteStartObject();
+ writer.WriteNumber("lat", value.Lat);
+ writer.WriteNumber("lon", value.Lon);
+ writer.WriteNumber("raio_m", value.RaioM);
+ writer.WriteString("precisao", value.Precisao);
+ writer.WriteEndObject();
+ }
+
+ private static double? ReadDouble(JsonElement owner, string name)
+ {
+ if (!owner.TryGetProperty(name, out var element))
+ {
+ return null;
+ }
+
+ return element.ValueKind switch
+ {
+ JsonValueKind.Number => element.TryGetDouble(out var number) ? number : null,
+ JsonValueKind.String => double.TryParse(
+ element.GetString(),
+ NumberStyles.Float,
+ CultureInfo.InvariantCulture,
+ out var parsed)
+ ? parsed
+ : null,
+ _ => null,
+ };
+ }
+
+ private static string? ReadString(JsonElement owner, string name) =>
+ owner.TryGetProperty(name, out var element) && element.ValueKind == JsonValueKind.String
+ ? element.GetString()
+ : null;
+}