$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,
43  std::enable_if_t<std::is_integral_v<X> && std::is_unsigned_v<X>, int> = 0>
44  Duration(Type* ptr, std::string desc)
45  : Base<Duration<T, Period>>(JsonType::number_unsigned, std::move(desc)), ptr_(ptr) {}
46 
47  template <typename X = T, std::enable_if_t<std::is_integral_v<X> && std::is_signed_v<X>, int> = 0>
48  Duration(Type* ptr, std::string desc)
49  : Base<Duration<T, Period>>(JsonType::number_integer, std::move(desc)), ptr_(ptr) {}
50 
51  template <typename X = T, std::enable_if_t<std::is_floating_point_v<X>, int> = 0>
52  Duration(Type* ptr, std::string desc)
53  : Base<Duration<T, Period>>(JsonType::number_float, std::move(desc)), ptr_(ptr) {}
54 
55  public: // Special
56  [[nodiscard]] T minimum() const { return value_min_; }
57  [[nodiscard]] bool exclusive_minimum() const { return exclusive_min_; }
58  Duration<T, Period> minimum(T value) && {
59  value_min_ = value;
60  exclusive_min_ = false;
61  return std::move(*this);
62  }
63  Duration<T, Period> exclusive_minimum(T value) && {
64  value_min_ = value;
65  exclusive_min_ = true;
66  return std::move(*this);
67  }
68 
69  [[nodiscard]] T maximum() const { return value_max_; }
70  [[nodiscard]] bool exclusive_maximum() const { return exclusive_max_; }
71  Duration<T, Period> maximum(T value) && {
72  value_max_ = value;
73  exclusive_max_ = false;
74  return std::move(*this);
75  }
76  Duration<T, Period> exclusive_maximum(T value) && {
77  value_max_ = value;
78  exclusive_max_ = true;
79  return std::move(*this);
80  }
81 
82  [[nodiscard]] std::pair<T, T> bounds() const { return std::make_pair(value_min_, value_max_); }
83  Duration<T, Period> bounds(T min, T max) && {
84  exclusive_min_ = false;
85  value_min_ = min;
86  exclusive_max_ = false;
87  value_max_ = max;
88  return std::move(*this);
89  }
90 
91  public: // Overrides
92  [[nodiscard]] Json json_schema() const override {
93  Json j{
94  {"type", this->type_string()},
95  {exclusive_min_ ? "exclusiveMinimum" : "minimum", value_min_},
96  {exclusive_max_ ? "exclusiveMaximum" : "maximum", value_max_},
97  };
98  this->augment_schema(j);
99  return j;
100  }
101 
102  bool validate(const Conf& c, std::optional<SchemaError>& err) const override {
103  switch (c->type()) {
104  case JsonType::number_unsigned:
105  return validate_bounds<uint64_t>(c, err);
106  case JsonType::number_integer:
107  return validate_bounds<int64_t>(c, err);
108  case JsonType::number_float:
109  if (this->type() != JsonType::number_float) {
110  return this->set_wrong_type(err, c);
111  } else {
112  return validate_bounds<double>(c, err);
113  }
114  default:
115  return this->set_wrong_type(err, c);
116  }
117  }
118 
119  using Interface::to_json;
120  void to_json(Json& j) const override {
121  assert(ptr_ != nullptr);
122  j = serialize(*ptr_);
123  }
124 
125  void from_conf(const Conf& c) override {
126  assert(ptr_ != nullptr);
127  *ptr_ = deserialize(c);
128  }
129 
130  [[nodiscard]] Json serialize(const Type& x) const { return x.count(); }
131 
132  [[nodiscard]] Type deserialize(const Conf& c) const { return Type(c.get<T>()); }
133 
134  void serialize_into(Json& j, const Type& x) const { j = x.count(); }
135 
136  void deserialize_into(const Conf& c, Type& x) const { x = deserialize(c); }
137 
138  void reset_ptr() override { ptr_ = nullptr; }
139 
140  private:
144  template <typename B>
145  bool validate_bounds(const Conf& c, std::optional<SchemaError>& err) const {
146  auto original = c.get<B>();
147  auto value = static_cast<T>(original);
148  if constexpr (!std::is_floating_point_v<T>) {
149  if (!is_cast_safe<T>(original)) {
150  return this->set_error(err, c,
151  "failed to convert input to destination type {}, got {}( {} ) = {}",
152  typeinfo<T>::name, typeinfo<B>::name, original, value);
153  }
154  }
155 
156  // Check minimum value:
157  if (exclusive_min_) {
158  if (value <= value_min_) {
159  return this->set_error(err, c, "expected exclusive minimum of {}, got {}", value_min_,
160  value);
161  }
162  } else {
163  if (value < value_min_) {
164  return this->set_error(err, c, "expected minimum of {}, got {}", value_min_, value);
165  }
166  }
167 
168  if (exclusive_max_) {
169  if (value >= value_max_) {
170  return this->set_error(err, c, "expected exclusive maximum of {}, got {}", value_max_,
171  value);
172  }
173  } else {
174  if (value > value_max_) {
175  return this->set_error(err, c, "expected maximum of {}, got {}", value_max_, value);
176  }
177  }
178 
179  return true;
180  }
181 
182  private:
183  bool exclusive_min_{false};
184  bool exclusive_max_{false};
185  T value_min_{std::numeric_limits<T>::lowest()};
186  T value_max_{std::numeric_limits<T>::max()};
187  Type* ptr_{nullptr};
188 };
189 
190 template <typename Rep, typename Period>
191 inline Duration<Rep, Period> make_schema(std::chrono::duration<Rep, Period>* ptr,
192  std::string desc) {
193  return Duration<Rep, Period>(ptr, std::move(desc));
194 }
195 
196 } // namespace fable::schema
Definition: conf.hpp:76
T get() const
Definition: conf.hpp:166
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:120
void from_conf(const Conf &c) override
Definition: duration.hpp:125
Json json_schema() const override
Definition: duration.hpp:92
bool validate(const Conf &c, std::optional< SchemaError > &err) const override
Definition: duration.hpp:102
void reset_ptr() override
Definition: duration.hpp:138
virtual Json to_json() const
Definition: interface.hpp:254
nlohmann::json Json
Definition: fable_fwd.hpp:35
Definition: templates.hpp:66