Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
8a1850df
Commit
8a1850df
authored
Apr 10, 2022
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new API for customizing type names in JSON
parent
4b8d5abf
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
146 additions
and
11 deletions
+146
-11
libcaf_core/caf/json_reader.hpp
libcaf_core/caf/json_reader.hpp
+16
-0
libcaf_core/caf/json_writer.hpp
libcaf_core/caf/json_writer.hpp
+17
-0
libcaf_core/caf/timestamp.hpp
libcaf_core/caf/timestamp.hpp
+7
-3
libcaf_core/caf/type_id.hpp
libcaf_core/caf/type_id.hpp
+23
-2
libcaf_core/src/json_reader.cpp
libcaf_core/src/json_reader.cpp
+2
-2
libcaf_core/src/json_writer.cpp
libcaf_core/src/json_writer.cpp
+3
-3
libcaf_core/src/timestamp.cpp
libcaf_core/src/timestamp.cpp
+11
-1
libcaf_core/src/type_id.cpp
libcaf_core/src/type_id.cpp
+12
-0
libcaf_core/test/json_reader.cpp
libcaf_core/test/json_reader.cpp
+55
-0
No files found.
libcaf_core/caf/json_reader.hpp
View file @
8a1850df
...
...
@@ -112,6 +112,16 @@ public:
field_type_suffix_
=
suffix
;
}
/// Returns the type ID mapper used by the writer.
[[
nodiscard
]]
const
type_id_mapper
*
mapper
()
const
noexcept
{
return
mapper_
;
}
/// Changes the type ID mapper for the writer.
void
mapper
(
const
type_id_mapper
*
ptr
)
noexcept
{
mapper_
=
ptr
;
}
// -- modifiers --------------------------------------------------------------
/// Parses @p json_text into an internal representation. After loading the
...
...
@@ -247,6 +257,12 @@ private:
/// Keeps track of the current field for better debugging output.
std
::
vector
<
std
::
string_view
>
field_
;
/// The mapper implementation we use by default.
default_type_id_mapper
default_mapper_
;
/// Configures which ID mapper we use to translate between type IDs and names.
const
type_id_mapper
*
mapper_
=
&
default_mapper_
;
};
}
// namespace caf
libcaf_core/caf/json_writer.hpp
View file @
8a1850df
...
...
@@ -115,6 +115,16 @@ public:
field_type_suffix_
=
suffix
;
}
/// Returns the type ID mapper used by the writer.
[[
nodiscard
]]
const
type_id_mapper
*
mapper
()
const
noexcept
{
return
mapper_
;
}
/// Changes the type ID mapper for the writer.
void
mapper
(
const
type_id_mapper
*
ptr
)
noexcept
{
mapper_
=
ptr
;
}
// -- modifiers --------------------------------------------------------------
/// Removes all characters from the buffer and restores the writer to its
...
...
@@ -280,7 +290,14 @@ private:
// Configures whether we omit the top-level '@type' annotation.
bool
skip_object_type_annotation_
=
false
;
// Configures how we generate type annotations for fields.
std
::
string_view
field_type_suffix_
=
field_type_suffix_default
;
// The mapper implementation we use by default.
default_type_id_mapper
default_mapper_
;
// Configures which ID mapper we use to translate between type IDs and names.
const
type_id_mapper
*
mapper_
=
&
default_mapper_
;
};
}
// namespace caf
libcaf_core/caf/timestamp.hpp
View file @
8a1850df
...
...
@@ -4,13 +4,14 @@
#pragma once
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp"
#include "caf/timespan.hpp"
#include <chrono>
#include <cstdint>
#include <string>
#include "caf/detail/core_export.hpp"
#include "caf/timespan.hpp"
namespace
caf
{
/// A portable timestamp with nanosecond resolution anchored at the UNIX epoch.
...
...
@@ -23,6 +24,9 @@ CAF_CORE_EXPORT timestamp make_timestamp();
/// Prints `x` in ISO 8601 format, e.g., `2018-11-15T06:25:01.462`.
CAF_CORE_EXPORT
std
::
string
timestamp_to_string
(
timestamp
x
);
/// Converts an ISO 8601 formatted timestamp into its native representation.
CAF_CORE_EXPORT
expected
<
timestamp
>
timestamp_from_string
(
std
::
string_view
str
);
/// Appends the timestamp `x` in ISO 8601 format, e.g.,
/// `2018-11-15T06:25:01.462`, to `y`.
CAF_CORE_EXPORT
void
append_timestamp_to_string
(
std
::
string
&
x
,
timestamp
y
);
...
...
libcaf_core/caf/type_id.hpp
View file @
8a1850df
...
...
@@ -96,13 +96,34 @@ type_id_t type_id_or_invalid() {
return
invalid_type_id
;
}
/// Returns the type name
of given `type` or an empty string if `type`
is an
/// Returns the type name
for @p type or an empty string if @p type
is an
/// invalid ID.
CAF_CORE_EXPORT
std
::
string_view
query_type_name
(
type_id_t
type
);
/// Returns the type
of given `name` or `invalid_type_id` if no type matches
.
/// Returns the type
for @p name or `invalid_type_id` if @p name is unknown
.
CAF_CORE_EXPORT
type_id_t
query_type_id
(
std
::
string_view
name
);
/// Translates between human-readable type names and type IDs.
class
CAF_CORE_EXPORT
type_id_mapper
{
public:
virtual
~
type_id_mapper
();
/// Returns the type name for @p type or an empty string if @p type is an
/// invalid ID.
virtual
std
::
string_view
operator
()(
type_id_t
type
)
const
=
0
;
/// Returns the type for @p name or `invalid_type_id` if @p name is unknown.
virtual
type_id_t
operator
()(
std
::
string_view
name
)
const
=
0
;
};
/// Dispatches to @ref query_type_name and @ref query_type_id.
class
default_type_id_mapper
:
public
type_id_mapper
{
public:
std
::
string_view
operator
()(
type_id_t
type
)
const
override
;
type_id_t
operator
()(
std
::
string_view
name
)
const
override
;
};
}
// namespace caf
// -- CAF_BEGIN_TYPE_ID_BLOCK --------------------------------------------------
...
...
libcaf_core/src/json_reader.cpp
View file @
8a1850df
...
...
@@ -182,7 +182,7 @@ void json_reader::reset() {
bool
json_reader
::
fetch_next_object_type
(
type_id_t
&
type
)
{
std
::
string_view
type_name
;
if
(
fetch_next_object_name
(
type_name
))
{
if
(
auto
id
=
query_type_id
(
type_name
);
id
!=
invalid_type_id
)
{
if
(
auto
id
=
(
*
mapper_
)
(
type_name
);
id
!=
invalid_type_id
)
{
type
=
id
;
return
true
;
}
else
{
...
...
@@ -311,7 +311,7 @@ bool json_reader::begin_field(std::string_view name, bool& is_present,
member
!=
nullptr
&&
member
->
val
->
data
.
index
()
!=
detail
::
json
::
value
::
null_index
)
{
auto
ft
=
field_type
(
top
<
position
::
object
>
(),
name
,
field_type_suffix_
);
if
(
auto
id
=
query_type_id
(
ft
);
id
!=
invalid_type_id
)
{
if
(
auto
id
=
(
*
mapper_
)
(
ft
);
id
!=
invalid_type_id
)
{
if
(
auto
i
=
std
::
find
(
types
.
begin
(),
types
.
end
(),
id
);
i
!=
types
.
end
())
{
index
=
static_cast
<
size_t
>
(
std
::
distance
(
types
.
begin
(),
i
));
...
...
libcaf_core/src/json_writer.cpp
View file @
8a1850df
...
...
@@ -92,7 +92,7 @@ bool json_writer::begin_object(type_id_t id, std::string_view name) {
add
(
R"_("@type": )_"
);
pop
();
CAF_ASSERT
(
top
()
==
type
::
element
);
if
(
auto
tname
=
query_type_name
(
id
);
!
tname
.
empty
())
{
if
(
auto
tname
=
(
*
mapper_
)
(
id
);
!
tname
.
empty
())
{
add
(
'"'
);
add
(
tname
);
add
(
'"'
);
...
...
@@ -177,12 +177,12 @@ bool json_writer::begin_field(std::string_view name,
pop
();
CAF_ASSERT
(
top
()
==
type
::
element
);
pop
();
if
(
auto
tname
=
query_type_name
(
types
[
index
]);
!
tname
.
empty
())
{
if
(
auto
tname
=
(
*
mapper_
)
(
types
[
index
]);
!
tname
.
empty
())
{
add
(
'"'
);
add
(
tname
);
add
(
'"'
);
}
else
{
emplace_error
(
sec
::
runtime_error
,
"
query_type_name failed
"
);
emplace_error
(
sec
::
runtime_error
,
"
failed to retrieve type name
"
);
return
false
;
}
return
end_key_value_pair
()
&&
begin_field
(
name
);
...
...
libcaf_core/src/timestamp.cpp
View file @
8a1850df
...
...
@@ -2,8 +2,10 @@
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/deep_to_string.hpp"
#include "caf/timestamp.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/detail/parse.hpp"
#include "caf/expected.hpp"
namespace
caf
{
...
...
@@ -15,6 +17,14 @@ std::string timestamp_to_string(timestamp x) {
return
deep_to_string
(
x
.
time_since_epoch
().
count
());
}
expected
<
timestamp
>
timestamp_from_string
(
std
::
string_view
str
)
{
timestamp
result
;
if
(
auto
err
=
detail
::
parse
(
str
,
result
);
!
err
)
return
result
;
else
return
err
;
}
void
append_timestamp_to_string
(
std
::
string
&
x
,
timestamp
y
)
{
x
+=
timestamp_to_string
(
y
);
}
...
...
libcaf_core/src/type_id.cpp
View file @
8a1850df
...
...
@@ -22,4 +22,16 @@ type_id_t query_type_id(std::string_view name) {
return
invalid_type_id
;
}
type_id_mapper
::~
type_id_mapper
()
{
// nop
}
std
::
string_view
default_type_id_mapper
::
operator
()(
type_id_t
type
)
const
{
return
query_type_name
(
type
);
}
type_id_t
default_type_id_mapper
::
operator
()(
std
::
string_view
name
)
const
{
return
query_type_id
(
name
);
}
}
// namespace caf
libcaf_core/test/json_reader.cpp
View file @
8a1850df
...
...
@@ -12,6 +12,8 @@
using
namespace
caf
;
using
namespace
std
::
literals
;
namespace
{
struct
fixture
{
...
...
@@ -124,4 +126,57 @@ CAF_TEST(json baselines) {
}
}
SCENARIO
(
"mappers enable custom type names in JSON input"
)
{
GIVEN
(
"a custom mapper"
)
{
class
custom_mapper
:
public
type_id_mapper
{
std
::
string_view
operator
()(
type_id_t
type
)
const
override
{
switch
(
type
)
{
case
type_id_v
<
std
:
:
string
>:
return
"String"
;
case
type_id_v
<
int32_t
>
:
return
"Int"
;
default:
return
query_type_name
(
type
);
}
}
type_id_t
operator
()(
std
::
string_view
name
)
const
override
{
if
(
name
==
"String"
)
return
type_id_v
<
std
::
string
>
;
else
if
(
name
==
"Int"
)
return
type_id_v
<
int32_t
>
;
else
return
query_type_id
(
name
);
}
};
custom_mapper
mapper_instance
;
WHEN
(
"reading a variant from JSON"
)
{
using
value_type
=
std
::
variant
<
int32_t
,
std
::
string
>
;
THEN
(
"the custom mapper translates between external and internal names"
)
{
json_reader
reader
;
reader
.
mapper
(
&
mapper_instance
);
auto
value
=
value_type
{};
auto
input1
=
R"_({"@value-type": "String", "value": "hello world"})_"
s
;
if
(
CHECK
(
reader
.
load
(
input1
)))
{
if
(
!
CHECK
(
reader
.
apply
(
value
)))
MESSAGE
(
"reader reported error: "
<<
reader
.
get_error
());
if
(
CHECK
(
std
::
holds_alternative
<
std
::
string
>
(
value
)))
CHECK_EQ
(
std
::
get
<
std
::
string
>
(
value
),
"hello world"
s
);
}
else
{
MESSAGE
(
"reader reported error: "
<<
reader
.
get_error
());
}
reader
.
reset
();
auto
input2
=
R"_({"@value-type": "Int", "value": 42})_"
sv
;
if
(
CHECK
(
reader
.
load
(
input2
)))
{
if
(
!
CHECK
(
reader
.
apply
(
value
)))
MESSAGE
(
"reader reported error: "
<<
reader
.
get_error
());
if
(
CHECK
(
std
::
holds_alternative
<
int32_t
>
(
value
)))
CHECK_EQ
(
std
::
get
<
int32_t
>
(
value
),
42
);
}
else
{
MESSAGE
(
"reader reported error: "
<<
reader
.
get_error
());
}
}
}
}
}
END_FIXTURE_SCOPE
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment