Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/content/processors.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ reflect-cpp currently supports the following processors:
- `rfl::AddNamespacedTagsToVariants`
- `rfl::AllowRawPtrs`
- `rfl::DefaultIfMissing`
- `rfl::DurationsAsCount`
- `rfl::EnumNamesOnly`
- `rfl::NoExtraFields`
- `rfl::NoFieldNames`
Expand Down Expand Up @@ -290,6 +291,27 @@ have gotten had you read the following JSON string:
Because you have not passed a default value to town, the default value
of the type is used instead.

### `rfl::DurationsAsCount`

By default, `std::chrono::duration` types are written as an object containing
the count and the unit. By passing the processor `rfl::DurationsAsCount`,
they will be written and read as a plain count in the unit of the C++ type:

```cpp
struct MyStruct {
std::chrono::milliseconds timeout;
};

rfl::json::write<rfl::DurationsAsCount>(
MyStruct{.timeout = std::chrono::milliseconds(1500)});
```

The resulting JSON string looks like this:

```json
{"timeout":1500}
```

### `rfl::EnumNamesOnly`

By default, when reading an enum from a string, numeric values are accepted
Expand Down
4 changes: 4 additions & 0 deletions docs/content/timestamps.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,7 @@ The following units are supported: `std::chrono::nanoseconds`, `std::chrono::mic
`std::chrono::milliseconds`, `std::chrono::seconds`,
`std::chrono::minutes`, `std::chrono::hours`, `std::chrono::days`,
`std::chrono::weeks`, `std::chrono::months`, and `std::chrono::years`.

To write and read durations as a plain count in the unit of the C++ type
(e.g. `{"duration":10}`), pass the `rfl::DurationsAsCount` processor
(see [processors](../processors)).
1 change: 1 addition & 0 deletions include/rfl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "rfl/DefaultIfMissing.hpp"
#include "rfl/DefaultVal.hpp"
#include "rfl/Description.hpp"
#include "rfl/DurationsAsCount.hpp"
#include "rfl/EnumNamesOnly.hpp"
#include "rfl/ExtraFields.hpp"
#include "rfl/Field.hpp"
Expand Down
19 changes: 19 additions & 0 deletions include/rfl/DurationsAsCount.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef RFL_DURATIONSASCOUNT_HPP_
#define RFL_DURATIONSASCOUNT_HPP_

namespace rfl {

/// This is a 'fake' processor - it doesn't do much by itself, but its
/// inclusion instructs parsers to write and read std::chrono::duration types
/// as a plain count in the unit of the C++ type, instead of {count, unit}.
struct DurationsAsCount {
public:
template <class StructType>
static auto process(auto&& _named_tuple) {
return _named_tuple;
}
};

} // namespace rfl

#endif
32 changes: 32 additions & 0 deletions include/rfl/internal/durations_as_count_v.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef RFL_INTERNAL_DURATIONSASCOUNT_HPP_
#define RFL_INTERNAL_DURATIONSASCOUNT_HPP_

#include <type_traits>

#include "../Processors.hpp"
#include "../DurationsAsCount.hpp"

namespace rfl::internal {

template <class T>
class durations_as_count;

template <class T>
class durations_as_count : public std::false_type {};

template <>
class durations_as_count<DurationsAsCount> : public std::true_type {};

template <class Head, class... Tail>
struct durations_as_count<Processors<Head, Tail...>> {
static constexpr bool value =
(durations_as_count<Head>::value || ... || durations_as_count<Tail>::value);
};

template <class T>
constexpr bool durations_as_count_v =
durations_as_count<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;

} // namespace rfl::internal

#endif
34 changes: 24 additions & 10 deletions include/rfl/parsing/ParserDuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "../Literal.hpp"
#include "../Variant.hpp"
#include "../always_false.hpp"
#include "../internal/durations_as_count_v.hpp"
#include "Parent.hpp"
#include "Parser_base.hpp"
#include "schema/Type.hpp"
Expand Down Expand Up @@ -55,13 +56,18 @@ struct ParserDuration {
*/
static Result<DurationType> read(const R& _r,
const InputVarType& _var) noexcept {
return Parser<R, W, RType, ProcessorsType>::read(_r, _var)
.and_then(to_duration)
.transform([](auto&& _duration) {
return _duration.visit([](auto&& _d) -> DurationType {
return std::chrono::duration_cast<DurationType>(std::move(_d));
if constexpr (internal::durations_as_count_v<ProcessorsType>) {
return Parser<R, W, Rep, ProcessorsType>::read(_r, _var).transform(
[](const Rep _count) { return DurationType(_count); });
} else {
return Parser<R, W, RType, ProcessorsType>::read(_r, _var)
.and_then(to_duration)
.transform([](auto&& _duration) {
return _duration.visit([](auto&& _d) -> DurationType {
return std::chrono::duration_cast<DurationType>(std::move(_d));
});
});
});
}
}

/**
Expand All @@ -74,9 +80,13 @@ struct ParserDuration {
*/
template <class P>
static void write(const W& _w, const DurationType& _d, const P& _parent) {
const auto r =
RType{.count = static_cast<int64_t>(_d.count()), .unit = make_unit()};
return Parser<R, W, RType, ProcessorsType>::write(_w, r, _parent);
if constexpr (internal::durations_as_count_v<ProcessorsType>) {
Parser<R, W, Rep, ProcessorsType>::write(_w, _d.count(), _parent);
} else {
const auto r = RType{.count = static_cast<int64_t>(_d.count()),
.unit = make_unit()};
Parser<R, W, RType, ProcessorsType>::write(_w, r, _parent);
}
}

/**
Expand All @@ -87,7 +97,11 @@ struct ParserDuration {
*/
static schema::Type to_schema(
std::map<std::string, schema::Type>* _definitions) {
return Parser<R, W, RType, ProcessorsType>::to_schema(_definitions);
if constexpr (internal::durations_as_count_v<ProcessorsType>) {
return Parser<R, W, Rep, ProcessorsType>::to_schema(_definitions);
} else {
return Parser<R, W, RType, ProcessorsType>::to_schema(_definitions);
}
}

private:
Expand Down
22 changes: 22 additions & 0 deletions tests/json/test_durations_as_count.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <chrono>
#include <rfl.hpp>
#include <rfl/json.hpp>

#include "write_and_read.hpp"

namespace test_durations_as_count {

struct TestStruct {
std::chrono::milliseconds ms;
std::chrono::seconds s;
std::chrono::duration<double> d;
};

TEST(json, test_durations_as_count) {
const auto test = TestStruct{.ms = std::chrono::milliseconds(1500),
.s = std::chrono::seconds(10),
.d = std::chrono::duration<double>(0.5)};
write_and_read<rfl::DurationsAsCount>(test,
R"({"ms":1500,"s":10,"d":0.5})");
}
} // namespace test_durations_as_count
Loading