1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
using System.Globalization;
using System.Text.Json;
namespace Cepis;
/// <summary>
/// Reads the <c>faixa</c> block of a 404 body, yielding <see langword="null"/>
/// for anything it cannot make sense of.
/// </summary>
/// <remarks>
/// <para>
/// A reader rather than a <see cref="System.Text.Json.Serialization.JsonConverter{T}"/>
/// because <c>faixa</c> is not a field of any model this library deserializes:
/// it hangs off an error body that is otherwise only read for its message.
/// </para>
/// <para>
/// Nothing in here throws. The block is a courtesy on top of a 404 — a missing,
/// misshapen or half-empty one must leave the caller with the same clean
/// <see cref="CepNotFoundException"/> it would have got before the API grew the
/// field, never with a parse failure on top of a not-found.
/// </para>
/// </remarks>
internal static class FaixaReader
{
/// <summary>Turn the <c>faixa</c> element into a range, or null.</summary>
/// <param name="element">the block, as it came off the wire</param>
/// <returns>the range, or null when there is nothing usable in it</returns>
internal static Faixa? Read(JsonElement element)
{
if (element.ValueKind != JsonValueKind.Object)
{
return null;
}
var localidade = ReadString(element, "localidade");
if (string.IsNullOrWhiteSpace(localidade))
{
return null;
}
return new Faixa
{
Localidade = localidade,
UF = ReadString(element, "uf"),
Estado = ReadString(element, "estado"),
Regiao = ReadString(element, "regiao"),
Ibge = ReadString(element, "ibge"),
CepIni = ReadString(element, "cep_ini"),
CepFim = ReadString(element, "cep_fim"),
Ceps = ReadInt(element, "ceps"),
};
}
/// <summary>
/// The property as text, or the empty string when it is absent or of a
/// shape that is not text.
/// </summary>
/// <remarks>
/// A number is accepted and taken verbatim, the way
/// <see cref="LenientStringConverter"/> does it for the address fields.
/// </remarks>
private static string ReadString(JsonElement owner, string name)
{
if (!owner.TryGetProperty(name, out var element))
{
return "";
}
return element.ValueKind switch
{
JsonValueKind.String => element.GetString() ?? "",
JsonValueKind.Number => element.GetRawText(),
_ => "",
};
}
/// <summary>The property as a count, or zero when it cannot be read.</summary>
private static int ReadInt(JsonElement owner, string name)
{
if (!owner.TryGetProperty(name, out var element))
{
return 0;
}
return element.ValueKind switch
{
JsonValueKind.Number => element.TryGetInt32(out var number) ? number : 0,
JsonValueKind.String => int.TryParse(
element.GetString(),
NumberStyles.Integer,
CultureInfo.InvariantCulture,
out var parsed)
? parsed
: 0,
_ => 0,
};
}
}
|