3#include "pixelbullet/serialization/node.h"
4#include "pixelbullet/serialization/serialization_result.h"
18#include <system_error>
23namespace pixelbullet::serialization
25[[nodiscard]]
inline std::string NodeTypeName(
const NodeType type)
31 case NodeType::Object:
35 case NodeType::String:
37 case NodeType::Boolean:
39 case NodeType::Integer:
41 case NodeType::Decimal:
50 explicit NodeReader(std::string root_path = {})
51 : path_(std::move(root_path))
58 PathScope(NodeReader& reader, std::string next_path)
60 , previous_path_(std::move(reader.path_))
62 reader_.path_ = std::move(next_path);
65 PathScope(
const PathScope&) =
delete;
66 PathScope& operator=(
const PathScope&) =
delete;
70 reader_.path_ = std::move(previous_path_);
75 std::string previous_path_;
78 [[nodiscard]]
PathScope PushProperty(
const std::string_view property)
80 std::string next = path_.empty() ? std::string(property) : path_ +
"." + std::string(property);
84 [[nodiscard]] PathScope PushIndex(
const std::size_t index)
86 std::string next = path_.empty() ?
"[" + std::to_string(index) +
"]" : path_ +
"[" + std::to_string(index) +
"]";
87 return PathScope(*
this, std::move(next));
90 [[nodiscard]]
bool Fail(std::string message)
96 [[nodiscard]]
bool ExpectScalar(
const Node& node)
98 if (node.type() == NodeType::Object || node.type() == NodeType::Array || node.type() == NodeType::Null)
100 return Fail(
"Expected scalar node, got " + NodeTypeName(node.type()) +
".");
105 [[nodiscard]]
bool ExpectObjectOrNull(
const Node& node)
107 if (node.type() != NodeType::Object && node.type() != NodeType::Null)
109 return Fail(
"Expected object node, got " + NodeTypeName(node.type()) +
".");
114 [[nodiscard]]
bool ExpectArray(
const Node& node)
116 if (node.type() != NodeType::Array)
118 return Fail(
"Expected array node, got " + NodeTypeName(node.type()) +
".");
123 [[nodiscard]]
const std::vector<SerializationDiagnostic>& Diagnostics() const noexcept
128 [[nodiscard]]
bool HasErrors() const noexcept
130 return !diagnostics_.empty();
133 [[nodiscard]] SerializationResult ToResult()
const
135 if (diagnostics_.empty())
137 return SerializationResult{
true, {} };
140 const SerializationDiagnostic& first = diagnostics_.front();
141 std::string message = first.path.empty() ? first.message : first.path +
": " + first.message;
142 return SerializationResult{
false, std::move(message), diagnostics_ };
147 std::vector<SerializationDiagnostic> diagnostics_;
151[[nodiscard]]
bool TryReadNode(
const Node& node, T& value,
NodeReader& reader)
152 requires(std::is_integral_v<T> && !std::is_same_v<T, bool>)
154 if (!reader.ExpectScalar(node))
159 const std::string& serialized = node.value();
160 const char* begin = serialized.data();
161 const char* end = begin + serialized.size();
163 const auto result = std::from_chars(begin, end, parsed);
164 if (result.ec != std::errc() || result.ptr != end)
166 return reader.Fail(
"Expected integer value, got '" + serialized +
"'.");
174[[nodiscard]]
bool TryReadNode(
const Node& node, T& value,
NodeReader& reader)
175 requires std::is_floating_point_v<T>
177 if (!reader.ExpectScalar(node))
182 const std::string& serialized = node.value();
183 const char* begin = serialized.data();
184 const char* end = begin + serialized.size();
186 const auto result = std::from_chars(begin, end, parsed);
187 if (result.ec != std::errc() || result.ptr != end || !std::isfinite(
static_cast<long double>(parsed)))
189 return reader.Fail(
"Expected finite decimal value, got '" + serialized +
"'.");
196[[nodiscard]]
inline bool TryReadNode(
const Node& node,
bool& value,
NodeReader& reader)
198 if (!reader.ExpectScalar(node))
203 const std::string& serialized = node.value();
204 if (serialized ==
"true" || serialized ==
"1")
209 if (serialized ==
"false" || serialized ==
"0")
215 return reader.Fail(
"Expected boolean value, got '" + serialized +
"'.");
218[[nodiscard]]
inline bool TryReadNode(
const Node& node, std::string& value,
NodeReader& reader)
220 if (!reader.ExpectScalar(node))
225 value = node.value();
229[[nodiscard]]
inline bool TryReadNode(
const Node& node, glm::vec2& value,
NodeReader& reader)
231 if (!reader.ExpectArray(node))
235 if (node.properties().size() < 2)
237 return reader.Fail(
"Expected at least 2 array elements.");
242 static constexpr std::string_view kComponents[] = {
"x",
"y" };
243 for (std::size_t index = 0; index < 2; ++index)
245 auto scope = reader.PushProperty(kComponents[index]);
246 ok &= TryReadNode(node.properties()[index].second, parsed[
static_cast<int>(index)], reader);
256[[nodiscard]]
inline bool TryReadNode(
const Node& node, glm::vec3& value,
NodeReader& reader)
258 if (!reader.ExpectArray(node))
262 if (node.properties().size() < 3)
264 return reader.Fail(
"Expected at least 3 array elements.");
269 static constexpr std::string_view kComponents[] = {
"x",
"y",
"z" };
270 for (std::size_t index = 0; index < 3; ++index)
272 auto scope = reader.PushProperty(kComponents[index]);
273 ok &= TryReadNode(node.properties()[index].second, parsed[
static_cast<int>(index)], reader);
283[[nodiscard]]
inline bool TryReadNode(
const Node& node, glm::vec4& value,
NodeReader& reader)
285 if (!reader.ExpectArray(node))
289 if (node.properties().size() < 4)
291 return reader.Fail(
"Expected at least 4 array elements.");
296 static constexpr std::string_view kComponents[] = {
"x",
"y",
"z",
"w" };
297 for (std::size_t index = 0; index < 4; ++index)
299 auto scope = reader.PushProperty(kComponents[index]);
300 ok &= TryReadNode(node.properties()[index].second, parsed[
static_cast<int>(index)], reader);
311[[nodiscard]]
bool TryReadNode(
const Node& node, std::vector<T>& value,
NodeReader& reader)
313 if (!reader.ExpectArray(node))
318 std::vector<T> parsed;
319 parsed.reserve(node.properties().size());
321 std::size_t index = 0;
322 for (
const auto& [key, child] : node.properties())
327 auto scope = reader.PushIndex(index);
328 ok &= TryReadNode(child, item, reader);
330 parsed.push_back(std::move(item));
336 value = std::move(parsed);
342[[nodiscard]]
bool TryReadNode(
const Node& node, std::map<std::string, T>& value,
NodeReader& reader)
344 if (!reader.ExpectObjectOrNull(node))
349 std::map<std::string, T> parsed;
351 for (
const auto& [key, child] : node.properties())
355 auto scope = reader.PushProperty(key);
356 ok &= TryReadNode(child, item, reader);
358 parsed.emplace(key, std::move(item));
363 value = std::move(parsed);
369[[nodiscard]]
bool TryReadNode(
const Node& node, std::optional<T>& value,
NodeReader& reader)
371 if (node.type() == NodeType::Null || !node.is_valid())
378 if (!TryReadNode(node, parsed, reader))
383 value = std::move(parsed);
387template <
typename T,
typename ParseFn>
388[[nodiscard]]
bool TryReadEnumToken(
const Node& node, T& value,
NodeReader& reader, ParseFn&& parse_fn,
const std::string_view enum_name)
391 if (!TryReadNode(node, token, reader))
397 if (!parse_fn(token, parsed))
399 return reader.Fail(
"Unknown " + std::string(enum_name) +
" token '" + token +
"'.");
407[[nodiscard]]
bool TryReadRequiredProperty(
const Node& node,
const std::string_view property, T& value,
NodeReader& reader)
409 if (!reader.ExpectObjectOrNull(node))
414 const Node* child = node.get_property(std::string(property));
415 auto scope = reader.PushProperty(property);
416 if (child ==
nullptr)
418 return reader.Fail(
"Missing required property.");
420 return TryReadNode(*child, value, reader);
424[[nodiscard]]
bool TryReadOptionalProperty(
const Node& node,
const std::string_view property, T& value,
NodeReader& reader)
426 if (!reader.ExpectObjectOrNull(node))
431 const Node* child = node.get_property(std::string(property));
432 if (child ==
nullptr)
437 auto scope = reader.PushProperty(property);
438 return TryReadNode(*child, value, reader);
442[[nodiscard]]
bool TryReadOptionalProperty(
const Node& node,
const std::string_view property, T& value,
const T& default_value,
445 if (!reader.ExpectObjectOrNull(node))
450 if (!node.has_property(std::string(property)))
452 value = default_value;
455 return TryReadOptionalProperty(node, property, value, reader);
460 { TryReadNode(node, value, reader) } -> std::same_as<bool>;
Represents a hierarchical node capable of storing various data types and supporting YAML serializatio...
Definition node.h:49
Definition node_reader.h:56
Definition node_reader.h:48
Definition node_reader.h:459
Definition serialization_result.h:9