$darkmode
duration.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Robert Bosch GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * SPDX-License-Identifier: Apache-2.0
17  */
25 #pragma once
26 
27 #include <chrono> // for duration<>
28 #include <limits> // for numeric_limits<>
29 #include <string> // for string
30 #include <utility> // for move
31 
32 #include <fable/schema/interface.hpp> // for Base<>
33 #include <fable/utility/templates.hpp> // for is_safe_cast<>, typeinfo<>
34 
35 namespace fable::schema {
36 
37 template <typename T, typename Period>
38 class Duration : public Base<Duration<T, Period>> {
39  public: // Types and Constructors
40  using Type = std::chrono::duration<T, Period>;
41 
42  template <typename X = T, std::enable_if_t<std::is_integral_v<X> && std::is_unsigned_v<X>, int> = 0>
43  Duration(Type* ptr, std::string desc)
44  : Base<Duration<T, Period>>(JsonType::number_unsigned, std::move(desc)), ptr_(ptr) {}
45 
46  template <typename X = T, std::enable_if_t<std::is_integral_v<X> && std::is_signed_v<X>, int> = 0>
47  Duration(Type* ptr, std::string desc)
48  : Base<Duration<T, Period>>(JsonType::number_integer, std::move(desc)), ptr_(ptr) {}
49 
50  template <typename X = T, std::enable_if_t<std::is_floating_point_v<X>, int> = 0>
51  Duration(Type* ptr, std::string desc)
52  : Base<Duration<T, Period>>(JsonType::number_float, std::move(desc)), ptr_(ptr) {}
53 
54  public: // Special
55  [[nodiscard]] T minimum() const { return value_min_; }
56 
57  void set_minimum(T value) {
58  value_min_ = value;
59  exclusive_min_ = false;
60  }
61 
62  [[nodiscard]] Duration<T, Period> minimum(T value) && {
63  set_minimum(value);
64  return std::move(*this);
65  }
66 
67  [[nodiscard]] bool exclusive_minimum() const { return exclusive_min_; }
68 
69  void set_exclusive_minimum(T value) {
70  value_min_ = value;
71  exclusive_min_ = true;
72  }
73 
74  [[nodiscard]] Duration<T, Period> exclusive_minimum(T value) && {
75  set_exclusive_minimum(value);
76  return std::move(*this);
77  }
78 
79  [[nodiscard]] T maximum() const { return value_max_; }
80 
81  void set_maximum(T value) {
82  value_max_ = value;
83  exclusive_max_ = false;
84  }
85 
86  [[nodiscard]] Duration<T, Period> maximum(T value) && {
87  value_max_ = value;
88  exclusive_max_ = false;
89  return std::move(*this);
90  }
91 
92  [[nodiscard]] bool exclusive_maximum() const { return exclusive_max_; }
93 
94  void set_exclusive_maximum(T value) {
95  value_max_ = value;
96  exclusive_max_ = true;
97  }
98 
99  [[nodiscard]] Duration<T, Period> exclusive_maximum(T value) && {
100  value_max_ = value;
101  exclusive_max_ = true;
102  return std::move(*this);
103  }
104 
105  [[nodiscard]] std::pair<T, T> bounds() const { return std::make_pair(value_min_, value_max_); }
106 
107  void set_bounds(T min, T max) {
108  exclusive_min_ = false;
109  value_min_ = min;
110  exclusive_max_ = false;
111  value_max_ = max;
112  }
113 
114  [[nodiscard]] Duration<T, Period> bounds(T min, T max) && {
115  set_bounds(min, max);
116  return std::move(*this);
117  }
118 
119  public: // Overrides
120  [[nodiscard]] Json json_schema() const override {
121  Json j{
122  {"type", this->type_string()},
123  {exclusive_min_ ? "exclusiveMinimum" : "minimum", value_min_},
124  {exclusive_max_ ? "exclusiveMaximum" : "maximum", value_max_},
125  };
126  this->augment_schema(j);
127  return j;
128  }
129 
130  bool validate(const Conf& c, std::optional<SchemaError>& err) const override {
131  switch (c->type()) {
132  case JsonType::number_unsigned:
133  return validate_bounds<uint64_t>(c, err);
134  case JsonType::number_integer:
135  return validate_bounds<int64_t>(c, err);
136  case JsonType::number_float:
137  if (this->type() != JsonType::number_float) {
138  return this->set_wrong_type(err, c);
139  } else {
140  return validate_bounds<double>(c, err);
141  }
142  default:
143  return this->set_wrong_type(err, c);
144  }
145  }
146 
147  using Interface::to_json;
148 
149  void to_json(Json& j) const override {
150  assert(ptr_ != nullptr);
151  j = serialize(*ptr_);
152  }
153 
154  void from_conf(const Conf& c) override {
155  assert(ptr_ != nullptr);
156  *ptr_ = deserialize(c);
157  }
158 
159  [[nodiscard]] Json serialize(const Type& x) const { return x.count(); }
160 
161  [[nodiscard]] Type deserialize(const Conf& c) const { return Type(c.get<T>()); }
162 
163  void serialize_into(Json& j, const Type& x) const { j = x.count(); }
164 
165  void deserialize_into(const Conf& c, Type& x) const { x = deserialize(c); }
166 
167  void reset_ptr() override { ptr_ = nullptr; }
168 
169  private:
173  template <typename B>
174  bool validate_bounds(const Conf& c, std::optional<SchemaError>& err) const {
175  auto original = c.get<B>();
176  auto value = static_cast<T>(original);
177  if constexpr (!std::is_floating_point_v<T>) {
178  if (!is_cast_safe<T>(original)) {
179  return this->set_error(err, c,
180  "failed to convert input to destination type {}, got {}( {} ) = {}",
181  typeinfo<T>::name, typeinfo<B>::name, original, value);
182  }
183  }
184 
185  // Check minimum value:
186  if (exclusive_min_) {
187  if (value <= value_min_) {
188  return this->set_error(err, c, "expected exclusive minimum of {}, got {}", value_min_,
189  value);
190  }
191  } else {
192  if (value < value_min_) {
193  return this->set_error(err, c, "expected minimum of {}, got {}", value_min_, value);
194  }
195  }
196 
197  if (exclusive_max_) {
198  if (value >= value_max_) {
199  return this->set_error(err, c, "expected exclusive maximum of {}, got {}", value_max_,
200  value);
201  }
202  } else {
203  if (value > value_max_) {
204  return this->set_error(err, c, "expected maximum of {}, got {}", value_max_, value);
205  }
206  }
207 
208  return true;
209  }
210 
211  private:
212  bool exclusive_min_{false};
213  bool exclusive_max_{false};
214  T value_min_{std::numeric_limits<T>::lowest()};
215  T value_max_{std::numeric_limits<T>::max()};
216  Type* ptr_{nullptr};
217 };
218 
219 template <typename Rep, typename Period, typename S>
220 Duration<Rep, Period> make_schema(std::chrono::duration<Rep, Period>* ptr, S&& desc) {
221  return {ptr, std::forward<S>(desc)};
222 }
223 
224 } // namespace fable::schema
Definition: conf.hpp:82
T get() const
Definition: conf.hpp:298
Definition: interface.hpp:398
JsonType type() const override
Definition: interface.hpp:418
std::string type_string() const override
Definition: interface.hpp:419
Definition: duration.hpp:38
void to_json(Json &j) const override
Definition: duration.hpp:149
void from_conf(const Conf &c) override
Definition: duration.hpp:154
Json json_schema() const override
Definition: duration.hpp:120
bool validate(const Conf &c, std::optional< SchemaError > &err) const override
Definition: duration.hpp:130
void reset_ptr() override
Definition: duration.hpp:167
virtual Json to_json() const
Definition: interface.hpp:254
nlohmann::json Json
Definition: fable_fwd.hpp:35
Definition: templates.hpp:66