File: Validator.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 (144 lines) | stat: -rw-r--r-- 4,104 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
137
138
139
140
141
142
143
144
#ifndef RFL_VALIDATOR_HPP_
#define RFL_VALIDATOR_HPP_

#include <functional>
#include <string>
#include <type_traits>
#include <utility>

#include "AllOf.hpp"
#include "Result.hpp"
#include "internal/HasValidation.hpp"

namespace rfl {

template <class T, class V, class... Vs>
  requires internal::HasValidation<AllOf<V, Vs...>, T>
struct Validator {
 public:
  using ReflectionType = T;
  using ValidationType =
      std::conditional_t<sizeof...(Vs) == 0, V, AllOf<V, Vs...>>;

  /// Exception-free validation.
  static Result<Validator<T, V, Vs...>> from_value(const T& _value) noexcept {
    try {
      return Validator<T, V, Vs...>(_value);
    } catch (std::exception& e) {
      return error(e.what());
    }
  }

  Validator() : value_(ValidationType::validate(T()).value()) {}

  Validator(Validator<T, V, Vs...>&& _other) noexcept = default;

  Validator(const Validator<T, V, Vs...>& _other) = default;

  Validator(T&& _value) : value_(ValidationType::validate(_value).value()) {}

  Validator(const T& _value)
      : value_(ValidationType::validate(_value).value()) {}

  template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
                                             bool>::type = true>
  Validator(U&& _value)
      : value_(ValidationType::validate(T(std::forward<U>(_value))).value()) {}

  template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
                                             bool>::type = true>
  Validator(const U& _value)
      : value_(ValidationType::validate(T(_value)).value()) {}

  ~Validator() = default;

  /// Assigns the underlying object.
  auto& operator=(const T& _value) {
    value_ = ValidationType::validate(_value).value();
    return *this;
  }

  /// Assigns the underlying object.
  auto& operator=(T&& _value) {
    value_ = ValidationType::validate(std::forward<T>(_value)).value();
    return *this;
  }

  /// Assigns the underlying object.
  Validator<T, V, Vs...>& operator=(const Validator<T, V, Vs...>& _other) =
      default;

  /// Assigns the underlying object.
  Validator<T, V, Vs...>& operator=(Validator<T, V, Vs...>&& _other) noexcept =
      default;

  /// Assigns the underlying object.
  template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
                                             bool>::type = true>
  auto& operator=(U&& _value) noexcept {
    value_ = ValidationType::validate(T(std::forward<U>(_value))).value();
    return *this;
  }

  /// Assigns the underlying object.
  template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
                                             bool>::type = true>
  auto& operator=(const U& _value) {
    value_ = ValidationType::validate(T(_value)).value();
    return *this;
  }

  /// Equality operator other Validators.
  bool operator==(const Validator<T, V, Vs...>& _other) const {
    return value() == _other.value();
  }

  /// Exposes the underlying value.
  T& value() { return value_; }

  /// Exposes the underlying value.
  const T& value() const { return value_; }

  /// Necessary for the serialization to work.
  const T& reflection() const { return value_; }

 private:
  /// The underlying value.
  T value_;
};

template <class T, class V, class... Vs>
inline auto operator<=>(const Validator<T, V, Vs...>& _v1,
                        const Validator<T, V, Vs...>& _v2) {
#if __cpp_lib_three_way_comparison >= 201907L
  return _v1.value() <=> _v2.value();
#else
  if (_v1.value() < _v2.value()) {
    return std::strong_ordering::less;
  } else if (_v1.value() > _v2.value()) {
    return std::strong_ordering::greater;
  } else {
    return std::strong_ordering::equal;
  }
#endif
}

template <class T, class V, class... Vs>
inline auto operator<=>(const Validator<T, V, Vs...>& _v, const T& _t) {
  return _v.value() <=> _t;
}

}  // namespace rfl

namespace std {

template <class T, class V, class... Vs>
struct hash<rfl::Validator<T, V, Vs...>> {
  size_t operator()(const rfl::Validator<T, V, Vs...>& _v) const {
    return hash<T>()(_v.value());
  }
};

}  // namespace std

#endif