RuneJsonConverter.cs 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. using System;
  2. using System.Text;
  3. using System.Text.Json;
  4. using System.Text.Json.Serialization;
  5. namespace Terminal.Gui {
  6. /// <summary>
  7. /// Json converter for <see cref="Rune"/>. Supports
  8. /// A string as one of:
  9. /// - unicode char (e.g. "☑")
  10. /// - U+hex format (e.g. "U+2611")
  11. /// - \u format (e.g. "\\u2611")
  12. /// A number
  13. /// - The unicode code in decimal
  14. /// </summary>
  15. internal class RuneJsonConverter : JsonConverter<Rune> {
  16. public override Rune Read (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
  17. {
  18. if (reader.TokenType == JsonTokenType.String) {
  19. var value = reader.GetString ();
  20. if (value.StartsWith ("U+", StringComparison.OrdinalIgnoreCase) || value.StartsWith ("\\u")) {
  21. try {
  22. uint result = uint.Parse (value [2..^0], System.Globalization.NumberStyles.HexNumber);
  23. return new Rune (result);
  24. } catch (FormatException e) {
  25. throw new JsonException ($"Invalid Rune format: {value}.", e);
  26. }
  27. } else {
  28. return new Rune (value [0]);
  29. }
  30. throw new JsonException ($"Invalid Rune format: {value}.");
  31. } else if (reader.TokenType == JsonTokenType.Number) {
  32. return new Rune (reader.GetUInt32 ());
  33. }
  34. throw new JsonException ($"Unexpected StartObject token when parsing Rune: {reader.TokenType}.");
  35. }
  36. public override void Write (Utf8JsonWriter writer, Rune value, JsonSerializerOptions options)
  37. {
  38. // HACK: Writes a JSON comment in addition to the glyph to ease debugging.
  39. // Technically, JSON comments are not valid, but we use relaxed decoding
  40. // (ReadCommentHandling = JsonCommentHandling.Skip)
  41. writer.WriteCommentValue ($"(U+{value.Value:X4})");
  42. writer.WriteRawValue ($"\"{value}\"");
  43. }
  44. }
  45. #pragma warning restore 1591
  46. }