up
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Formats.Cbor;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Serialization;
|
||||
|
||||
internal static class DeterministicCborSerializer
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
WriteIndented = false
|
||||
};
|
||||
|
||||
public static byte[] Serialize<T>(T value)
|
||||
{
|
||||
using var document = JsonSerializer.SerializeToDocument(value, JsonOptions);
|
||||
var writer = new CborWriter(CborConformanceMode.Canonical);
|
||||
|
||||
WriteElement(writer, document.RootElement);
|
||||
return writer.Encode();
|
||||
}
|
||||
|
||||
private static void WriteElement(CborWriter writer, JsonElement element)
|
||||
{
|
||||
switch (element.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Object:
|
||||
WriteObject(writer, element);
|
||||
return;
|
||||
case JsonValueKind.Array:
|
||||
writer.WriteStartArray(element.GetArrayLength());
|
||||
foreach (var item in element.EnumerateArray())
|
||||
{
|
||||
WriteElement(writer, item);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
return;
|
||||
case JsonValueKind.String:
|
||||
writer.WriteTextString(element.GetString() ?? string.Empty);
|
||||
return;
|
||||
case JsonValueKind.Number:
|
||||
if (element.TryGetInt64(out var int64))
|
||||
{
|
||||
writer.WriteInt64(int64);
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteDouble(element.GetDouble());
|
||||
return;
|
||||
case JsonValueKind.True:
|
||||
writer.WriteBoolean(true);
|
||||
return;
|
||||
case JsonValueKind.False:
|
||||
writer.WriteBoolean(false);
|
||||
return;
|
||||
case JsonValueKind.Null:
|
||||
case JsonValueKind.Undefined:
|
||||
writer.WriteNull();
|
||||
return;
|
||||
default:
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteObject(CborWriter writer, JsonElement element)
|
||||
{
|
||||
var properties = new List<(byte[] KeyBytes, string Key, JsonElement Value)>();
|
||||
|
||||
foreach (var property in element.EnumerateObject())
|
||||
{
|
||||
var keyBytes = Encoding.UTF8.GetBytes(property.Name);
|
||||
properties.Add((keyBytes, property.Name, property.Value));
|
||||
}
|
||||
|
||||
properties.Sort(static (left, right) =>
|
||||
{
|
||||
var lengthCompare = left.KeyBytes.Length.CompareTo(right.KeyBytes.Length);
|
||||
if (lengthCompare != 0)
|
||||
{
|
||||
return lengthCompare;
|
||||
}
|
||||
|
||||
for (var i = 0; i < left.KeyBytes.Length; i++)
|
||||
{
|
||||
var byteCompare = left.KeyBytes[i].CompareTo(right.KeyBytes[i]);
|
||||
if (byteCompare != 0)
|
||||
{
|
||||
return byteCompare;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
writer.WriteStartMap(properties.Count);
|
||||
|
||||
foreach (var (_, key, value) in properties)
|
||||
{
|
||||
writer.WriteTextString(key);
|
||||
WriteElement(writer, value);
|
||||
}
|
||||
|
||||
writer.WriteEndMap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user