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
5b4905fb
Commit
5b4905fb
authored
Jan 11, 2021
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new serializer for generating JSON output
parent
1ed9a0b4
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
863 additions
and
9 deletions
+863
-9
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+2
-0
libcaf_core/caf/detail/append_hex.hpp
libcaf_core/caf/detail/append_hex.hpp
+5
-9
libcaf_core/caf/json_writer.hpp
libcaf_core/caf/json_writer.hpp
+232
-0
libcaf_core/src/json_writer.cpp
libcaf_core/src/json_writer.cpp
+485
-0
libcaf_core/test/json_writer.cpp
libcaf_core/test/json_writer.cpp
+139
-0
No files found.
libcaf_core/CMakeLists.txt
View file @
5b4905fb
...
...
@@ -154,6 +154,7 @@ caf_add_component(
src/ipv6_address.cpp
src/ipv6_endpoint.cpp
src/ipv6_subnet.cpp
src/json_writer.cpp
src/load_inspector.cpp
src/local_actor.cpp
src/logger.cpp
...
...
@@ -290,6 +291,7 @@ caf_add_component(
ipv6_address
ipv6_endpoint
ipv6_subnet
json_writer
load_inspector
logger
mailbox_element
...
...
libcaf_core/caf/detail/append_hex.hpp
View file @
5b4905fb
...
...
@@ -18,24 +18,20 @@ enum class hex_format {
lowercase
,
};
template
<
hex_format
format
=
hex_format
::
uppercase
>
void
append_hex
(
std
::
string
&
result
,
const
void
*
vptr
,
size_t
n
)
{
if
(
n
==
0
)
{
result
+=
"00"
;
template
<
hex_format
format
=
hex_format
::
uppercase
,
class
Buf
=
std
::
string
>
void
append_hex
(
Buf
&
result
,
const
void
*
vptr
,
size_t
n
)
{
if
(
n
==
0
)
return
;
}
auto
xs
=
reinterpret_cast
<
const
uint8_t
*>
(
vptr
);
const
char
*
tbl
;
if
constexpr
(
format
==
hex_format
::
uppercase
)
tbl
=
"0123456789ABCDEF"
;
else
tbl
=
"0123456789abcdef"
;
char
buf
[
3
]
=
{
0
,
0
,
0
};
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
{
auto
c
=
xs
[
i
];
buf
[
0
]
=
tbl
[
c
>>
4
];
buf
[
1
]
=
tbl
[
c
&
0x0F
];
result
+=
buf
;
result
.
push_back
(
tbl
[
c
>>
4
]);
result
.
push_back
(
tbl
[
c
&
0x0F
]);
}
}
...
...
libcaf_core/caf/json_writer.hpp
0 → 100644
View file @
5b4905fb
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <vector>
#include "caf/detail/core_export.hpp"
#include "caf/serializer.hpp"
namespace
caf
{
/// Serializes an inspectable object to a JSON-formatted string.
class
CAF_CORE_EXPORT
json_writer
:
public
serializer
{
public:
// -- member types -----------------------------------------------------------
using
super
=
serializer
;
/// Reflects the structure of JSON objects according to ECMA-404. This enum
/// skips types such as `members` or `value` since they are not needed to
/// generate JSON.
enum
class
type
:
uint8_t
{
element
,
/// Can morph into any other type except `member`.
object
,
/// Contains any number of members.
member
,
/// A single object member (key/value pair).
array
,
/// Contains any number of elements.
string
,
/// A character sequence (terminal type).
number
,
/// An integer or floating point (terminal type).
boolean
,
/// Either "true" or "false" (terminal type).
null
,
/// The literal "null" (terminal type).
};
// -- constructors, destructors, and assignment operators --------------------
json_writer
();
explicit
json_writer
(
actor_system
&
sys
);
explicit
json_writer
(
execution_unit
*
ctx
);
~
json_writer
()
override
;
// -- properties -------------------------------------------------------------
/// Returns a string view into the internal buffer.
/// @warning This view becomes invalid when calling any non-const member
/// function on the writer object.
[[
nodiscard
]]
string_view
str
()
const
noexcept
{
return
{
buf_
.
data
(),
buf_
.
size
()};
}
/// Returns the current indentation factor.
[[
nodiscard
]]
size_t
indentation
()
const
noexcept
{
return
indentation_factor_
;
}
/// Sets the indentation level.
/// @param factor The number of spaces to add to each level of indentation. A
/// value of 0 (the default) disables indentation, printing the
/// entire JSON output into a single line.
void
indentation
(
size_t
factor
)
noexcept
{
indentation_factor_
=
factor
;
}
/// Returns whether the writer generates compact JSON output without any
/// spaces or newlines to separate values.
[[
nodiscard
]]
bool
compact
()
const
noexcept
{
return
indentation_factor_
==
0
;
}
// -- modifiers --------------------------------------------------------------
/// Removes all characters from the buffer and restores the writer to its
/// initial state.
/// @warning Invalidates all string views into the buffer.
void
reset
();
// -- overrides --------------------------------------------------------------
bool
begin_object
(
type_id_t
type
,
string_view
name
)
override
;
bool
end_object
()
override
;
bool
begin_field
(
string_view
)
override
;
bool
begin_field
(
string_view
name
,
bool
is_present
)
override
;
bool
begin_field
(
string_view
name
,
span
<
const
type_id_t
>
types
,
size_t
index
)
override
;
bool
begin_field
(
string_view
name
,
bool
is_present
,
span
<
const
type_id_t
>
types
,
size_t
index
)
override
;
bool
end_field
()
override
;
bool
begin_tuple
(
size_t
size
)
override
;
bool
end_tuple
()
override
;
bool
begin_key_value_pair
()
override
;
bool
end_key_value_pair
()
override
;
bool
begin_sequence
(
size_t
size
)
override
;
bool
end_sequence
()
override
;
bool
begin_associative_array
(
size_t
size
)
override
;
bool
end_associative_array
()
override
;
bool
value
(
byte
x
)
override
;
bool
value
(
bool
x
)
override
;
bool
value
(
int8_t
x
)
override
;
bool
value
(
uint8_t
x
)
override
;
bool
value
(
int16_t
x
)
override
;
bool
value
(
uint16_t
x
)
override
;
bool
value
(
int32_t
x
)
override
;
bool
value
(
uint32_t
x
)
override
;
bool
value
(
int64_t
x
)
override
;
bool
value
(
uint64_t
x
)
override
;
bool
value
(
float
x
)
override
;
bool
value
(
double
x
)
override
;
bool
value
(
long
double
x
)
override
;
bool
value
(
string_view
x
)
override
;
bool
value
(
const
std
::
u16string
&
x
)
override
;
bool
value
(
const
std
::
u32string
&
x
)
override
;
bool
value
(
span
<
const
byte
>
x
)
override
;
private:
// -- implementation details -------------------------------------------------
template
<
class
T
>
bool
number
(
T
);
// -- state management -------------------------------------------------------
void
init
();
// Returns the current top of the stack or `null_literal` if empty.
type
top
();
// Enters a new level of nesting.
void
push
(
type
=
type
::
element
);
// Enters a new level of nesting if the current top is `expected`.
bool
push_if
(
type
expected
,
type
=
type
::
element
);
// Backs up one level of nesting.
bool
pop
();
// Backs up one level of nesting but checks that current top is `t` before.
bool
pop_if
(
type
t
);
// Backs up one level of nesting but checks that the top is `t` afterwards.
bool
pop_if_next
(
type
t
);
// Tries to morph the current top of the stack to t.
bool
morph
(
type
t
);
// Tries to morph the current top of the stack to t. Stores the previous value
// to `prev`.
bool
morph
(
type
t
,
type
&
prev
);
// Morphs the current top of the stack to t without performing *any* checks.
void
unsafe_morph
(
type
t
);
// Sets an error reason that the inspector failed to write a t.
void
fail
(
type
t
);
// -- printing ---------------------------------------------------------------
// Adds a newline unless `compact() == true`.
void
nl
();
// Adds `c` to the output buffer.
void
add
(
char
c
)
{
buf_
.
push_back
(
c
);
}
// Adds `str` to the output buffer.
void
add
(
string_view
str
)
{
buf_
.
insert
(
buf_
.
end
(),
str
.
begin
(),
str
.
end
());
}
// Adds a separator to the output buffer unless the current entry is empty.
// The separator is just a comma when in compact mode and otherwise a comma
// followed by a newline.
void
sep
();
// -- member variables -------------------------------------------------------
// The current level of indentation.
size_t
indentation_level_
=
0
;
// The number of whitespaces to add per indentation level.
size_t
indentation_factor_
=
0
;
// Buffer for producing the JSON output.
std
::
vector
<
char
>
buf_
;
struct
entry
{
type
t
;
bool
filled
;
friend
bool
operator
==
(
entry
x
,
type
y
)
noexcept
{
return
x
.
t
==
y
;
};
};
// Bookkeeping for where we are in the current object.
std
::
vector
<
entry
>
stack_
;
};
}
// namespace caf
libcaf_core/src/json_writer.cpp
0 → 100644
View file @
5b4905fb
This diff is collapsed.
Click to expand it.
libcaf_core/test/json_writer.cpp
0 → 100644
View file @
5b4905fb
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE json_writer
#include "caf/json_writer.hpp"
#include "core-test.hpp"
using
namespace
caf
;
using
namespace
std
::
literals
::
string_literals
;
namespace
{
struct
fixture
{
template
<
class
T
>
expected
<
std
::
string
>
to_json_string
(
T
&&
x
,
size_t
indentation_factor
)
{
json_writer
writer
;
writer
.
indentation
(
indentation_factor
);
if
(
writer
.
apply
(
std
::
forward
<
T
>
(
x
)))
{
auto
buf
=
writer
.
str
();
return
{
std
::
string
{
buf
.
begin
(),
buf
.
end
()}};
}
else
{
MESSAGE
(
"partial JSON output: "
<<
writer
.
str
());
return
{
writer
.
get_error
()};
}
}
};
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
json_writer_tests
,
fixture
)
SCENARIO
(
"the JSON writer converts builtin types to strings"
)
{
GIVEN
(
"an integer"
)
{
auto
x
=
42
;
WHEN
(
"converting it to JSON with any indentation factor"
)
{
THEN
(
"the JSON output is the number"
)
{
CHECK_EQ
(
to_json_string
(
x
,
0
),
"42"
s
);
CHECK_EQ
(
to_json_string
(
x
,
2
),
"42"
s
);
}
}
}
GIVEN
(
"a string"
)
{
auto
x
=
R"_(hello "world"!)_"
s
;
WHEN
(
"converting it to JSON with any indentation factor"
)
{
THEN
(
"the JSON output is the escaped string"
)
{
CHECK_EQ
(
to_json_string
(
x
,
0
),
R"_("hello \"world\"!")_"
s
);
CHECK_EQ
(
to_json_string
(
x
,
2
),
R"_("hello \"world\"!")_"
s
);
}
}
}
GIVEN
(
"a list"
)
{
auto
x
=
std
::
vector
<
int
>
{
1
,
2
,
3
};
WHEN
(
"converting it to JSON with indentation factor 0"
)
{
THEN
(
"the JSON output is a single line"
)
{
CHECK_EQ
(
to_json_string
(
x
,
0
),
"[1, 2, 3]"
s
);
}
}
WHEN
(
"converting it to JSON with indentation factor 2"
)
{
THEN
(
"the JSON output uses multiple lines"
)
{
auto
out
=
R"_([
1,
2,
3
])_"
s
;
CHECK_EQ
(
to_json_string
(
x
,
2
),
out
);
}
}
}
GIVEN
(
"a dictionary"
)
{
std
::
map
<
std
::
string
,
std
::
string
>
x
;
x
.
emplace
(
"a"
,
"A"
);
x
.
emplace
(
"b"
,
"B"
);
x
.
emplace
(
"c"
,
"C"
);
WHEN
(
"converting it to JSON with indentation factor 0"
)
{
THEN
(
"the JSON output is a single line"
)
{
CHECK_EQ
(
to_json_string
(
x
,
0
),
R"_({"a": "A", "b": "B", "c": "C"})_"
s
);
}
}
WHEN
(
"converting it to JSON with indentation factor 2"
)
{
THEN
(
"the JSON output uses multiple lines"
)
{
auto
out
=
R"_({
"a": "A",
"b": "B",
"c": "C"
})_"
s
;
CHECK_EQ
(
to_json_string
(
x
,
2
),
out
);
}
}
}
GIVEN
(
"a message"
)
{
auto
x
=
make_message
(
put_atom_v
,
"foo"
,
42
);
WHEN
(
"converting it to JSON with indentation factor 0"
)
{
THEN
(
"the JSON output is a single line"
)
{
CHECK_EQ
(
to_json_string
(
x
,
0
),
R"_([{"@type": "caf::put_atom"}, "foo", 42])_"
s
);
}
}
WHEN
(
"converting it to JSON with indentation factor 2"
)
{
THEN
(
"the JSON output uses multiple lines"
)
{
auto
out
=
R"_([
{
"@type": "caf::put_atom"
},
"foo",
42
])_"
s
;
CHECK_EQ
(
to_json_string
(
x
,
2
),
out
);
}
}
}
}
SCENARIO
(
"the JSON writer converts simple structs to strings"
)
{
GIVEN
(
"a dummy_struct object"
)
{
dummy_struct
x
{
10
,
"foo"
};
WHEN
(
"converting it to JSON with indentation factor 0"
)
{
THEN
(
"the JSON output is a single line"
)
{
auto
out
=
R"_({"@type": "dummy_struct", "a": 10, "b": "foo"})_"
s
;
CHECK_EQ
(
to_json_string
(
x
,
0
),
out
);
}
}
WHEN
(
"converting it to JSON with indentation factor 2"
)
{
THEN
(
"the JSON output uses multiple lines"
)
{
auto
out
=
R"_({
"@type": "dummy_struct",
"a": 10,
"b": "foo"
})_"
s
;
CHECK_EQ
(
to_json_string
(
x
,
2
),
out
);
}
}
}
}
CAF_TEST_FIXTURE_SCOPE_END
()
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