File: Reader.hpp

package info (click to toggle)
reflect-cpp 0.18.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 12,524 kB
  • sloc: cpp: 44,484; python: 131; makefile: 30; sh: 3
file content (136 lines) | stat: -rw-r--r-- 3,818 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#ifndef RFL_TOML_READER_HPP_
#define RFL_TOML_READER_HPP_

#include <array>
#include <exception>
#include <map>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#include <toml.hpp>
#pragma GCC diagnostic pop

#include "../Result.hpp"
#include "../always_false.hpp"

namespace rfl::toml {

struct Reader {
  using InputArrayType = const ::toml::array*;
  using InputObjectType = const ::toml::table*;
  using InputVarType = const ::toml::value*;

  template <class T>
  static constexpr bool has_custom_constructor =
      (requires(InputVarType var) { T::from_toml_obj(var); });

  rfl::Result<InputVarType> get_field_from_array(
      const size_t _idx, const InputArrayType _arr) const noexcept {
    if (_idx >= _arr->size()) {
      return error("Index " + std::to_string(_idx) + " of of bounds.");
    }
    return &(*_arr)[_idx];
  }

  rfl::Result<InputVarType> get_field_from_object(
      const std::string& _name, const InputObjectType _obj) const noexcept {
    const auto it = _obj->find(_name);
    if (it == _obj->end()) {
      return error("Object contains no field named '" + _name + "'.");
    }
    return &it->second;
  }

  bool is_empty(const InputVarType _var) const noexcept {
    return _var->is_empty();
  }

  template <class T>
  rfl::Result<T> to_basic_type(const InputVarType _var) const noexcept {
    if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
      if (!_var->is_string()) {
        return error("Could not cast to std::string!");
      }
      return _var->as_string();

    } else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
      if (!_var->is_boolean()) {
        return error("Could not cast to bool!");
      }
      return _var->as_boolean();

    } else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>()) {
      if (!_var->is_floating()) {
        return error("Could not cast to double!");
      }
      return static_cast<std::remove_cvref_t<T>>(_var->as_floating());

    } else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
      if (!_var->is_integer()) {
        return error("Could not cast to int64_t!");
      }
      return static_cast<std::remove_cvref_t<T>>(_var->as_integer());

    } else {
      static_assert(rfl::always_false_v<T>, "Unsupported type.");
    }
  }

  rfl::Result<InputArrayType> to_array(const InputVarType _var) const noexcept {
    if (!_var->is_array()) {
      return error("Could not cast to an array!");
    }
    return &_var->as_array();
  }

  template <class ArrayReader>
  std::optional<Error> read_array(const ArrayReader& _array_reader,
                                  const InputArrayType _arr) const noexcept {
    for (const auto& node : *_arr) {
      const auto err = _array_reader.read(&node);
      if (err) {
        return err;
      }
    }
    return std::nullopt;
  }

  template <class ObjectReader>
  std::optional<Error> read_object(const ObjectReader& _object_reader,
                                   InputObjectType _obj) const noexcept {
    for (const auto& [k, v] : *_obj) {
      _object_reader.read(std::string_view(k), &v);
    }
    return std::nullopt;
  }

  rfl::Result<InputObjectType> to_object(
      const InputVarType _var) const noexcept {
    if (!_var->is_table()) {
      return error("Could not cast to a table!");
    }
    return &_var->as_table();
  }

  template <class T>
  rfl::Result<T> use_custom_constructor(
      const InputVarType _var) const noexcept {
    try {
      return T::from_toml_obj(_var);
    } catch (std::exception& e) {
      return error(e.what());
    }
  }
};

}  // namespace rfl::toml

#endif