PropertyDeserializer.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "PropertyDeserializer.h"
  7. #include <AK/JsonObject.h>
  8. #include <AK/String.h>
  9. #include <LibGUI/Margins.h>
  10. #include <LibGUI/UIDimensions.h>
  11. #include <LibGfx/Color.h>
  12. #include <LibGfx/Rect.h>
  13. namespace GUI {
  14. template<>
  15. ErrorOr<bool> PropertyDeserializer<bool>::operator()(JsonValue const& value) const
  16. {
  17. if (value.is_bool())
  18. return value.as_bool();
  19. return Error::from_string_literal("Boolean is expected");
  20. }
  21. template<>
  22. ErrorOr<String> PropertyDeserializer<String>::operator()(JsonValue const& value) const
  23. {
  24. if (value.is_string()) {
  25. // FIXME: Port JsonValue to the new String class.
  26. return String::from_byte_string(value.as_string());
  27. }
  28. return Error::from_string_literal("UTF-8 string is expected");
  29. }
  30. template<>
  31. ErrorOr<ByteString> PropertyDeserializer<ByteString>::operator()(JsonValue const& value) const
  32. {
  33. if (value.is_string())
  34. return value.as_string();
  35. return Error::from_string_literal("String is expected");
  36. }
  37. template<>
  38. ErrorOr<Gfx::IntRect> PropertyDeserializer<Gfx::IntRect>::operator()(JsonValue const& value) const
  39. {
  40. if (!value.is_object() && !(value.is_array() && value.as_array().size() == 4))
  41. return Error::from_string_literal("An array with 4 integers or an object is expected");
  42. Gfx::IntRect rect;
  43. Optional<int> x;
  44. Optional<int> y;
  45. Optional<int> width;
  46. Optional<int> height;
  47. if (value.is_object()) {
  48. auto const& object = value.as_object();
  49. if (object.size() != 4 || !object.has("x"sv) || !object.has("y"sv) || !object.has("width"sv) || !object.has("height"sv))
  50. return Error::from_string_literal("Object with keys \"x\", \"y\", \"width\", and \"height\" is expected");
  51. x = object.get_i32("x"sv);
  52. y = object.get_i32("y"sv);
  53. width = object.get_i32("width"sv);
  54. height = object.get_i32("height"sv);
  55. } else {
  56. auto const& array = value.as_array();
  57. auto get_i32 = [](JsonValue const& value) -> Optional<int> {
  58. if (value.is_integer<i32>())
  59. return value.to_i32();
  60. return {};
  61. };
  62. x = get_i32(array[0]);
  63. y = get_i32(array[1]);
  64. width = get_i32(array[2]);
  65. height = get_i32(array[3]);
  66. }
  67. if (!x.has_value())
  68. return Error::from_string_literal("X coordinate must be an integer");
  69. if (!y.has_value())
  70. return Error::from_string_literal("Y coordinate must be an integer");
  71. if (!width.has_value())
  72. return Error::from_string_literal("Width must be an integer");
  73. if (!height.has_value())
  74. return Error::from_string_literal("Height must be an integer");
  75. rect.set_x(x.value());
  76. rect.set_y(y.value());
  77. rect.set_width(width.value());
  78. rect.set_height(height.value());
  79. return rect;
  80. }
  81. template<>
  82. ErrorOr<Gfx::IntSize> PropertyDeserializer<Gfx::IntSize>::operator()(JsonValue const& value) const
  83. {
  84. if (!value.is_array() || value.as_array().size() != 2)
  85. return Error::from_string_literal("Expected array with 2 integers");
  86. auto const& array = value.as_array();
  87. auto const& width = array[0];
  88. if (!width.is_integer<i32>())
  89. return Error::from_string_literal("Width must be an integer");
  90. auto const& height = array[1];
  91. if (!height.is_integer<i32>())
  92. return Error::from_string_literal("Height must be an integer");
  93. Gfx::IntSize size;
  94. size.set_width(width.to_i32());
  95. size.set_height(height.to_i32());
  96. return size;
  97. }
  98. template<>
  99. ErrorOr<GUI::Margins> PropertyDeserializer<GUI::Margins>::operator()(JsonValue const& value) const
  100. {
  101. if (!value.is_array() || value.as_array().size() < 1 || value.as_array().size() > 4)
  102. return Error::from_string_literal("Expected non-empty array with up to 4 integers");
  103. auto const& array = value.as_array();
  104. auto size = array.size();
  105. int m[4];
  106. for (size_t i = 0; i < size; ++i) {
  107. auto const& margin = array[i];
  108. if (!margin.is_integer<i32>())
  109. return Error::from_string_literal("Margin value should be an integer");
  110. m[i] = margin.to_i32();
  111. }
  112. if (size == 1)
  113. return GUI::Margins { m[0] };
  114. else if (size == 2)
  115. return GUI::Margins { m[0], m[1] };
  116. else if (size == 3)
  117. return GUI::Margins { m[0], m[1], m[2] };
  118. else
  119. return GUI::Margins { m[0], m[1], m[2], m[3] };
  120. }
  121. template<>
  122. ErrorOr<UIDimension> PropertyDeserializer<UIDimension>::operator()(JsonValue const& value) const
  123. {
  124. auto result = UIDimension::construct_from_json_value(value);
  125. if (result.has_value())
  126. return result.release_value();
  127. return Error::from_string_literal("Value is not a valid UIDimension");
  128. }
  129. template<>
  130. ErrorOr<UISize> PropertyDeserializer<UISize>::operator()(JsonValue const& value) const
  131. {
  132. if (!value.is_object() || !value.as_object().has("width"sv) || !value.as_object().has("height"sv))
  133. return Error::from_string_literal("Object with keys \"width\" and \"height\" is expected");
  134. auto const& object = value.as_object();
  135. auto const& width = object.get("width"sv).value();
  136. auto result_width = GUI::UIDimension::construct_from_json_value(width);
  137. if (!result_width.has_value())
  138. return Error::from_string_literal("width is not a valid UIDimension");
  139. auto const& height = object.get("height"sv).value();
  140. auto result_height = GUI::UIDimension::construct_from_json_value(height);
  141. if (!result_height.has_value())
  142. return Error::from_string_literal("height is not a valid UIDimension");
  143. return UISize { result_width.value(), result_height.value() };
  144. }
  145. template<>
  146. ErrorOr<Color> PropertyDeserializer<Color>::operator()(JsonValue const& value) const
  147. {
  148. if (value.is_string()) {
  149. auto c = Color::from_string(value.as_string());
  150. if (c.has_value())
  151. return c.release_value();
  152. }
  153. return Error::from_string_literal("Color is expected");
  154. }
  155. };