#ifndef RFL_YAML_READER_HPP_ #define RFL_YAML_READER_HPP_ #include #include #include #include #include #include #include #include #include #include #include #include #include "../Result.hpp" #include "../always_false.hpp" namespace rfl { namespace yaml { struct Reader { struct YAMLInputArray { YAMLInputArray(const YAML::Node& _node) : node_(_node) {} YAML::Node node_; }; struct YAMLInputObject { YAMLInputObject(const YAML::Node& _node) : node_(_node) {} YAML::Node node_; }; struct YAMLInputVar { YAMLInputVar(const YAML::Node& _node) : node_(_node) {} YAML::Node node_; }; using InputArrayType = YAMLInputArray; using InputObjectType = YAMLInputObject; using InputVarType = YAMLInputVar; template struct has_from_json_obj : std::false_type {}; template static constexpr bool has_custom_constructor = (requires(InputVarType var) { T::from_yaml_obj(var); }); rfl::Result get_field( const std::string& _name, const InputObjectType& _obj) const noexcept { auto var = InputVarType(_obj.node_[_name]); if (!var.node_) { return rfl::Error("Object contains no field named '" + _name + "'."); } return var; } bool is_empty(const InputVarType& _var) const noexcept { return !_var.node_ && true; } template rfl::Result to_basic_type(const InputVarType& _var) const noexcept { try { if constexpr (std::is_same, std::string>() || std::is_same, bool>() || std::is_floating_point>() || std::is_integral>()) { return _var.node_.as>(); } else { static_assert(rfl::always_false_v, "Unsupported type."); } } catch (std::exception& e) { return rfl::Error(e.what()); } } rfl::Result to_array( const InputVarType& _var) const noexcept { if (!_var.node_.IsSequence()) { return rfl::Error("Could not cast to sequence!"); } return InputArrayType(_var.node_); } template std::optional read_array(const ArrayReader& _array_reader, const InputArrayType& _arr) const noexcept { for (size_t i = 0; i < _arr.node_.size(); ++i) { const auto err = _array_reader.read(_arr.node_[i]); if (err) { return err; } } return std::nullopt; } template std::optional read_object(const ObjectReader& _object_reader, const InputObjectType& _obj) const noexcept { for (const auto& p : _obj.node_) { try { const auto k = p.first.as(); _object_reader.read(std::string_view(k), InputVarType(p.second)); } catch (std::exception& e) { continue; } } return std::nullopt; } rfl::Result to_object( const InputVarType& _var) const noexcept { if (!_var.node_.IsMap()) { return rfl::Error("Could not cast to map!"); } return InputObjectType(_var.node_); } template rfl::Result use_custom_constructor( const InputVarType _var) const noexcept { try { return T::from_yaml_obj(_var); } catch (std::exception& e) { return rfl::Error(e.what()); } } }; } // namespace yaml } // namespace rfl #endif