Skip to content

Commit 093ef12

Browse files
Merge branch 'main' into f/yas
2 parents 26c79ec + 4a54589 commit 093ef12

13 files changed

Lines changed: 480 additions & 57 deletions

File tree

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,9 @@ if (REFLECTCPP_YAML OR REFLECTCPP_CHECK_HEADERS)
439439
endif ()
440440

441441
if (REFLECTCPP_BOOST_SERIALIZATION OR REFLECTCPP_CHECK_HEADERS)
442+
list(APPEND REFLECT_CPP_SOURCES
443+
src/reflectcpp_boost_serialization.cpp
444+
)
442445
if (NOT TARGET Boost::serialization)
443446
find_package(Boost REQUIRED COMPONENTS serialization)
444447
endif ()

docs/timestamps.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# `rfl::Timestamp` and `std::chrono::duration`
1+
# `rfl::Timestamp`, `std::chrono::system_clock::time_point`, and `std::chrono::duration`
22

33
## `rfl::Timestamp`
44

@@ -45,6 +45,41 @@ const rfl::Result<rfl::Timestamp<"%Y-%m-%d">> result = rfl::Timestamp<"%Y-%m-%d"
4545
const rfl::Result<rfl::Timestamp<"%Y-%m-%d">> error = rfl::Timestamp<"%Y-%m-%d">::from_string("not a proper time format");
4646
```
4747

48+
## `std::chrono::system_clock::time_point`
49+
50+
`std::chrono::system_clock::time_point` is natively supported. It serializes as an ISO 8601 string with nanosecond precision:
51+
52+
```cpp
53+
struct Event {
54+
std::string name;
55+
std::chrono::system_clock::time_point created_at;
56+
};
57+
58+
rfl::json::write(Event{.name = "deploy", .created_at = std::chrono::system_clock::now()});
59+
```
60+
61+
This produces:
62+
63+
```json
64+
{"name":"deploy","created_at":"2024-01-15T12:00:00.123456789Z"}
65+
```
66+
67+
Trailing fractional zeros are stripped, so microsecond values appear as `.123456Z` and whole seconds appear without a decimal point.
68+
69+
On read, the following formats are accepted:
70+
71+
- `"2024-01-15T12:00:00Z"` — UTC, no fractional seconds
72+
- `"2024-01-15T12:00:00.123Z"` — milliseconds
73+
- `"2024-01-15T12:00:00.123456Z"` — microseconds
74+
- `"2024-01-15T12:00:00.123456789Z"` — nanoseconds
75+
- `"2024-01-15T12:00:00"` — no timezone suffix (assumed UTC)
76+
- `"2024-01-15T10:30:00+05:30"` — timezone offset (converted to UTC)
77+
- `"2024-01-15T02:00:00-08:00"` — negative offset
78+
79+
Timezone offsets are converted to UTC on read. The write path always outputs UTC with the `Z` suffix.
80+
81+
Only `std::chrono::system_clock::time_point` is supported — other clocks like `steady_clock` do not represent calendar time and cannot be serialized as ISO 8601.
82+
4883
## `std::chrono::duration`
4984

5085
`std::chrono::duration` types are serialized as an object with the count and unit as fields:

include/rfl/Commented.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ template <class T>
1414
struct Commented {
1515
public:
1616
using Type = std::remove_cvref_t<T>;
17+
using ReflectionType = Type;
1718

1819
Commented() : value_(Type()) {}
1920

@@ -134,6 +135,9 @@ struct Commented {
134135
return *this;
135136
}
136137

138+
/// Returns the underlying object.
139+
const ReflectionType& reflection() const { return value_; }
140+
137141
/// Assigns the underlying object.
138142
void set(const Type& _value) { value_ = _value; }
139143

include/rfl/boost_serialization/Parser.hpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -57,34 +57,6 @@ struct Parser<boost_serialization::Reader<IArchive>,
5757
/*_all_required=*/true, ProcessorsType,
5858
std::tuple<Ts...>> {};
5959

60-
template <class IArchive, class OArchive, class ProcessorsType>
61-
requires AreReaderAndWriter<boost_serialization::Reader<IArchive>,
62-
boost_serialization::Writer<OArchive>, Generic>
63-
struct Parser<boost_serialization::Reader<IArchive>,
64-
boost_serialization::Writer<OArchive>, Generic, ProcessorsType> {
65-
template <class T>
66-
static Result<Generic> read(const boost_serialization::Reader<IArchive>&,
67-
const T&) noexcept {
68-
static_assert(always_false_v<T>,
69-
"Generics are unsupported in Boost.Serialization.");
70-
return error("Unsupported");
71-
}
72-
73-
template <class P>
74-
static void write(const boost_serialization::Writer<OArchive>&,
75-
const Generic&, const P&) noexcept {
76-
static_assert(always_false_v<P>,
77-
"Generics are unsupported in Boost.Serialization.");
78-
}
79-
80-
template <class T>
81-
static schema::Type to_schema(T*) {
82-
static_assert(always_false_v<T>,
83-
"Generics are unsupported in Boost.Serialization.");
84-
return schema::Type{};
85-
}
86-
};
87-
8860
template <class IArchive, class OArchive, class T, bool _skip_serialization,
8961
bool _skip_deserialization, class ProcessorsType>
9062
requires AreReaderAndWriter<

include/rfl/boost_serialization/Writer.hpp

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ class Writer {
3535
~Writer() = default;
3636

3737
OutputArrayType array_as_root(const size_t _size) const {
38-
*ar_ << static_cast<std::uint64_t>(_size);
38+
write_size(_size);
3939
return OutputArrayType{};
4040
}
4141

4242
OutputMapType map_as_root(const size_t _size) const {
43-
*ar_ << static_cast<std::uint64_t>(_size);
43+
write_size(_size);
4444
return OutputMapType{};
4545
}
4646

4747
OutputObjectType object_as_root(const size_t _size) const {
48-
*ar_ << static_cast<std::uint64_t>(_size);
48+
write_size(_size);
4949
return OutputObjectType{};
5050
}
5151

@@ -61,85 +61,85 @@ class Writer {
6161

6262
OutputArrayType add_array_to_array(const size_t _size,
6363
OutputArrayType* /*_parent*/) const {
64-
*ar_ << static_cast<std::uint64_t>(_size);
64+
write_size(_size);
6565
return OutputArrayType{};
6666
}
6767

6868
OutputArrayType add_array_to_map(const std::string_view& _name,
6969
const size_t _size,
7070
OutputMapType* /*_parent*/) const {
71-
*ar_ << std::string(_name);
72-
*ar_ << static_cast<std::uint64_t>(_size);
71+
write_key(_name);
72+
write_size(_size);
7373
return OutputArrayType{};
7474
}
7575

7676
OutputArrayType add_array_to_object(const std::string_view& /*_name*/,
7777
const size_t _size,
7878
OutputObjectType* /*_parent*/) const {
79-
*ar_ << static_cast<std::uint64_t>(_size);
79+
write_size(_size);
8080
return OutputArrayType{};
8181
}
8282

8383
OutputArrayType add_array_to_union(const size_t _index, const size_t _size,
8484
OutputUnionType* /*_parent*/) const {
85-
*ar_ << static_cast<std::uint64_t>(_index);
86-
*ar_ << static_cast<std::uint64_t>(_size);
85+
write_index(_index);
86+
write_size(_size);
8787
return OutputArrayType{};
8888
}
8989

9090
OutputMapType add_map_to_array(const size_t _size,
9191
OutputArrayType* /*_parent*/) const {
92-
*ar_ << static_cast<std::uint64_t>(_size);
92+
write_size(_size);
9393
return OutputMapType{};
9494
}
9595

9696
OutputMapType add_map_to_map(const std::string_view& _name,
9797
const size_t _size,
9898
OutputMapType* /*_parent*/) const {
99-
*ar_ << std::string(_name);
100-
*ar_ << static_cast<std::uint64_t>(_size);
99+
write_key(_name);
100+
write_size(_size);
101101
return OutputMapType{};
102102
}
103103

104104
OutputMapType add_map_to_object(const std::string_view& /*_name*/,
105105
const size_t _size,
106106
OutputObjectType* /*_parent*/) const {
107-
*ar_ << static_cast<std::uint64_t>(_size);
107+
write_size(_size);
108108
return OutputMapType{};
109109
}
110110

111111
OutputMapType add_map_to_union(const size_t _index, const size_t _size,
112112
OutputUnionType* /*_parent*/) const {
113-
*ar_ << static_cast<std::uint64_t>(_index);
114-
*ar_ << static_cast<std::uint64_t>(_size);
113+
write_index(_index);
114+
write_size(_size);
115115
return OutputMapType{};
116116
}
117117

118118
OutputObjectType add_object_to_array(const size_t _size,
119119
OutputArrayType* /*_parent*/) const {
120-
*ar_ << static_cast<std::uint64_t>(_size);
120+
write_size(_size);
121121
return OutputObjectType{};
122122
}
123123

124124
OutputObjectType add_object_to_map(const std::string_view& _name,
125125
const size_t _size,
126126
OutputMapType* /*_parent*/) const {
127-
*ar_ << std::string(_name);
128-
*ar_ << static_cast<std::uint64_t>(_size);
127+
write_key(_name);
128+
write_size(_size);
129129
return OutputObjectType{};
130130
}
131131

132132
OutputObjectType add_object_to_object(const std::string_view& /*_name*/,
133133
const size_t _size,
134134
OutputObjectType* /*_parent*/) const {
135-
*ar_ << static_cast<std::uint64_t>(_size);
135+
write_size(_size);
136136
return OutputObjectType{};
137137
}
138138

139139
OutputObjectType add_object_to_union(const size_t _index, const size_t _size,
140140
OutputUnionType* /*_parent*/) const {
141-
*ar_ << static_cast<std::uint64_t>(_index);
142-
*ar_ << static_cast<std::uint64_t>(_size);
141+
write_index(_index);
142+
write_size(_size);
143143
return OutputObjectType{};
144144
}
145145

@@ -149,7 +149,7 @@ class Writer {
149149

150150
OutputUnionType add_union_to_map(const std::string_view& _name,
151151
OutputMapType* /*_parent*/) const {
152-
*ar_ << std::string(_name);
152+
write_key(_name);
153153
return OutputUnionType{};
154154
}
155155

@@ -160,7 +160,7 @@ class Writer {
160160

161161
OutputUnionType add_union_to_union(const size_t _index,
162162
OutputUnionType* /*_parent*/) const {
163-
*ar_ << static_cast<std::uint64_t>(_index);
163+
write_index(_index);
164164
return OutputUnionType{};
165165
}
166166

@@ -174,7 +174,7 @@ class Writer {
174174
template <class T>
175175
OutputVarType add_value_to_map(const std::string_view& _name, const T& _var,
176176
OutputMapType* /*_parent*/) const {
177-
*ar_ << std::string(_name);
177+
write_key(_name);
178178
new_value(_var);
179179
return OutputVarType{};
180180
}
@@ -190,7 +190,7 @@ class Writer {
190190
template <class T>
191191
OutputVarType add_value_to_union(const size_t _index, const T& _var,
192192
OutputUnionType* /*_parent*/) const {
193-
*ar_ << static_cast<std::uint64_t>(_index);
193+
write_index(_index);
194194
new_value(_var);
195195
return OutputVarType{};
196196
}
@@ -201,7 +201,7 @@ class Writer {
201201

202202
OutputVarType add_null_to_map(const std::string_view& _name,
203203
OutputMapType* /*_parent*/) const {
204-
*ar_ << std::string(_name);
204+
write_key(_name);
205205
return OutputVarType{};
206206
}
207207

@@ -212,7 +212,7 @@ class Writer {
212212

213213
OutputVarType add_null_to_union(const size_t _index,
214214
OutputUnionType* /*_parent*/) const {
215-
*ar_ << static_cast<std::uint64_t>(_index);
215+
write_index(_index);
216216
return OutputVarType{};
217217
}
218218

@@ -223,6 +223,18 @@ class Writer {
223223
void end_object(OutputObjectType* /*_obj*/) const {}
224224

225225
private:
226+
void write_size(const size_t _size) const {
227+
*ar_ << static_cast<std::uint64_t>(_size);
228+
}
229+
230+
void write_index(const size_t _index) const {
231+
*ar_ << static_cast<std::uint64_t>(_index);
232+
}
233+
234+
void write_key(const std::string_view& _name) const {
235+
*ar_ << std::string(_name);
236+
}
237+
226238
template <class T>
227239
void new_value(const T& _var) const {
228240
using Type = std::remove_cvref_t<T>;

include/rfl/parsing/Parser.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "Parser_span.hpp"
3535
#include "Parser_string_view.hpp"
3636
#include "Parser_tagged_union.hpp"
37+
#include "Parser_time_point.hpp"
3738
#include "Parser_tuple.hpp"
3839
#include "Parser_unique_ptr.hpp"
3940
#include "Parser_variant.hpp"

0 commit comments

Comments
 (0)