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
6df8d506
Commit
6df8d506
authored
Sep 05, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement new settings reader
parent
083126c8
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
918 additions
and
6 deletions
+918
-6
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+2
-0
libcaf_core/caf/detail/parse.hpp
libcaf_core/caf/detail/parse.hpp
+2
-0
libcaf_core/caf/sec.hpp
libcaf_core/caf/sec.hpp
+8
-6
libcaf_core/caf/settings.hpp
libcaf_core/caf/settings.hpp
+1
-0
libcaf_core/caf/settings_reader.hpp
libcaf_core/caf/settings_reader.hpp
+172
-0
libcaf_core/src/detail/parse.cpp
libcaf_core/src/detail/parse.cpp
+2
-0
libcaf_core/src/sec_strings.cpp
libcaf_core/src/sec_strings.cpp
+2
-0
libcaf_core/src/settings_reader.cpp
libcaf_core/src/settings_reader.cpp
+572
-0
libcaf_core/test/inspector-tests.hpp
libcaf_core/test/inspector-tests.hpp
+13
-0
libcaf_core/test/settings_reader.cpp
libcaf_core/test/settings_reader.cpp
+144
-0
No files found.
libcaf_core/CMakeLists.txt
View file @
6df8d506
...
...
@@ -158,6 +158,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/sec_strings.cpp
src/serializer.cpp
src/settings.cpp
src/settings_reader.cpp
src/settings_writer.cpp
src/size_based_credit_controller.cpp
src/skip.cpp
...
...
@@ -312,6 +313,7 @@ caf_add_test_suites(caf-core-test
serial_reply
serialization
settings
settings_reader
settings_writer
simple_timeout
span
...
...
libcaf_core/caf/detail/parse.hpp
View file @
6df8d506
...
...
@@ -97,6 +97,8 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, float& x);
CAF_CORE_EXPORT
void
parse
(
string_parser_state
&
ps
,
double
&
x
);
CAF_CORE_EXPORT
void
parse
(
string_parser_state
&
ps
,
long
double
&
x
);
// -- CAF types ----------------------------------------------------------------
CAF_CORE_EXPORT
void
parse
(
string_parser_state
&
ps
,
ipv4_address
&
x
);
...
...
libcaf_core/caf/sec.hpp
View file @
6df8d506
...
...
@@ -145,19 +145,21 @@ enum class sec : uint8_t {
no_tracing_context
,
/// No request produced a valid result.
all_requests_failed
,
/// Deserialization failed
,
because an invariant got violated after reading
/// Deserialization failed because an invariant got violated after reading
/// the content of a field.
field_invariant_check_failed
=
55
,
/// Deserialization failed
,
because a setter rejected the input.
/// Deserialization failed because a setter rejected the input.
field_value_synchronization_failed
,
/// Deserialization failed
,
because the source announced an invalid type.
/// Deserialization failed because the source announced an invalid type.
invalid_field_type
,
/// Serialization failed because a type was flagged as unsafe message type.
unsafe_type
,
/// Serialization failed
,
because a save callback returned `false`.
/// Serialization failed because a save callback returned `false`.
save_callback_failed
,
/// Deserialization failed, because a load callback returned `false`.
load_callback_failed
,
/// Deserialization failed because a load callback returned `false`.
load_callback_failed
=
60
,
/// Converting between two types failed.
conversion_failed
,
};
/// @relates sec
...
...
libcaf_core/caf/settings.hpp
View file @
6df8d506
...
...
@@ -25,6 +25,7 @@
#include "caf/optional.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_view.hpp"
#include "caf/sum_type.hpp"
namespace
caf
{
...
...
libcaf_core/caf/settings_reader.hpp
0 → 100644
View file @
6df8d506
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/deserializer.hpp"
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
#include <stack>
#include <vector>
namespace
caf
{
/// Extracts objects from @ref settings.
class
settings_reader
:
public
deserializer
{
public:
// -- member types------------------------------------------------------------
using
super
=
deserializer
;
using
key_ptr
=
const
std
::
string
*
;
struct
absent_field
{};
struct
sequence
{
using
list_pointer
=
const
std
::
vector
<
config_value
>*
;
size_t
index
;
list_pointer
ls
;
explicit
sequence
(
list_pointer
ls
)
:
index
(
0
),
ls
(
ls
)
{
// nop
}
bool
at_end
()
const
noexcept
;
const
config_value
&
current
();
void
advance
()
{
++
index
;
}
};
struct
associative_array
{
settings
::
const_iterator
pos
;
settings
::
const_iterator
end
;
bool
at_end
()
const
noexcept
;
const
std
::
pair
<
const
std
::
string
,
config_value
>&
current
();
};
using
value_type
=
variant
<
const
settings
*
,
const
config_value
*
,
key_ptr
,
absent_field
,
sequence
,
associative_array
>
;
using
stack_type
=
std
::
stack
<
value_type
,
std
::
vector
<
value_type
>>
;
// -- constructors, destructors, and assignment operators --------------------
settings_reader
(
const
settings
*
input
,
actor_system
&
sys
)
:
super
(
sys
),
root_
(
input
)
{
st_
.
push
(
input
);
has_human_readable_format_
=
true
;
}
settings_reader
(
const
settings
*
input
,
execution_unit
*
ctx
)
:
super
(
ctx
),
root_
(
input
)
{
has_human_readable_format_
=
true
;
}
explicit
settings_reader
(
const
settings
*
input
)
:
settings_reader
(
input
,
nullptr
)
{
// nop
}
~
settings_reader
()
override
;
// -- stack access -----------------------------------------------------------
value_type
&
top
()
{
return
st_
.
top
();
}
void
pop
()
{
return
st_
.
pop
();
}
// -- interface functions ----------------------------------------------------
bool
fetch_next_object_type
(
type_id_t
&
type
)
override
;
bool
begin_object
(
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
(
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
(
std
::
string
&
x
)
override
;
bool
value
(
std
::
u16string
&
x
)
override
;
bool
value
(
std
::
u32string
&
x
)
override
;
bool
value
(
span
<
byte
>
x
)
override
;
private:
bool
fetch_object_type
(
const
settings
*
obj
,
type_id_t
&
type
);
stack_type
st_
;
const
settings
*
root_
;
};
}
// namespace caf
libcaf_core/src/detail/parse.cpp
View file @
6df8d506
...
...
@@ -142,6 +142,8 @@ PARSE_IMPL(float, floating_point)
PARSE_IMPL
(
double
,
floating_point
)
PARSE_IMPL
(
long
double
,
floating_point
)
void
parse
(
string_parser_state
&
ps
,
uri
&
x
)
{
uri_builder
builder
;
if
(
ps
.
consume
(
'<'
))
{
...
...
libcaf_core/src/sec_strings.cpp
View file @
6df8d506
...
...
@@ -137,6 +137,8 @@ std::string to_string(sec x) {
return
"save_callback_failed"
;
case
sec
:
:
load_callback_failed
:
return
"load_callback_failed"
;
case
sec
:
:
conversion_failed
:
return
"conversion_failed"
;
};
}
...
...
libcaf_core/src/settings_reader.cpp
0 → 100644
View file @
6df8d506
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/settings_reader.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/append_hex.hpp"
#include "caf/detail/overload.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/print.hpp"
#include "caf/settings.hpp"
namespace
{
template
<
class
T
>
struct
pretty_name
;
#define PRETTY_NAME(type, pretty_str) \
template <> \
struct pretty_name<type> { \
[[maybe_unused]] static constexpr const char* value = pretty_str; \
}
PRETTY_NAME
(
const
caf
::
settings
*
,
"dictionary"
);
PRETTY_NAME
(
const
caf
::
config_value
*
,
"config_value"
);
PRETTY_NAME
(
const
std
::
string
*
,
"key"
);
PRETTY_NAME
(
caf
::
settings_reader
::
absent_field
,
"absent field"
);
PRETTY_NAME
(
caf
::
settings_reader
::
sequence
,
"sequence"
);
PRETTY_NAME
(
caf
::
settings_reader
::
associative_array
,
"associative array"
);
template
<
class
T
>
constexpr
auto
pretty_name_v
=
pretty_name
<
T
>::
value
;
auto
get_pretty_name
(
const
caf
::
settings_reader
::
value_type
&
x
)
{
const
char
*
pretty_names
[]
=
{
"dictionary"
,
"config_value"
,
"key"
,
"absent field"
,
"sequence"
,
"associative array"
,
};
return
pretty_names
[
x
.
index
()];
}
}
// namespace
#define CHECK_NOT_EMPTY() \
do { \
if (st_.empty()) { \
emplace_error(sec::runtime_error, "mismatching calls to begin/end"); \
return false; \
} \
} while (false)
#define SCOPE(top_type) \
CHECK_NOT_EMPTY(); \
if (!holds_alternative<top_type>(st_.top())) { \
std::string msg; \
msg += "type clash in function "; \
msg += __func__; \
msg += ": expected "; \
msg += pretty_name_v<top_type>; \
msg += " got "; \
msg += get_pretty_name(st_.top()); \
emplace_error(sec::runtime_error, std::move(msg)); \
return false; \
} \
[[maybe_unused]] auto& top = get<top_type>(st_.top());
namespace
caf
{
// -- member types--------------------------------------------------------------
bool
settings_reader
::
sequence
::
at_end
()
const
noexcept
{
return
index
>=
ls
->
size
();
}
const
config_value
&
settings_reader
::
sequence
::
current
()
{
return
(
*
ls
)[
index
];
}
bool
settings_reader
::
associative_array
::
at_end
()
const
noexcept
{
return
pos
==
end
;
}
const
std
::
pair
<
const
std
::
string
,
config_value
>&
settings_reader
::
associative_array
::
current
()
{
return
*
pos
;
}
// -- constructors, destructors, and assignment operators ----------------------
settings_reader
::~
settings_reader
()
{
// nop
}
// -- interface functions ------------------------------------------------------
bool
settings_reader
::
fetch_next_object_type
(
type_id_t
&
type
)
{
if
(
st_
.
empty
())
{
if
(
root_
==
nullptr
)
{
emplace_error
(
sec
::
runtime_error
,
"tried to read multiple objects from the root object"
);
return
false
;
}
return
fetch_object_type
(
root_
,
type
);
}
else
{
auto
f
=
detail
::
make_overload
(
[
this
](
const
settings
*
)
{
emplace_error
(
sec
::
runtime_error
,
"fetch_next_object_type called inside an object"
);
return
false
;
},
[
this
,
&
type
](
const
config_value
*
val
)
{
if
(
auto
obj
=
get_if
<
settings
>
(
val
);
obj
==
nullptr
)
{
emplace_error
(
sec
::
conversion_failed
,
"cannot read input as object"
);
return
false
;
}
else
{
return
fetch_object_type
(
obj
,
type
);
}
},
[
this
](
key_ptr
)
{
emplace_error
(
sec
::
runtime_error
,
"reading an object from a dictionary key not implemented yet"
);
return
false
;
},
[
this
](
absent_field
)
{
emplace_error
(
sec
::
runtime_error
,
"fetch_next_object_type called inside non-existent optional field"
);
return
false
;
},
[
this
,
&
type
](
sequence
&
seq
)
{
if
(
seq
.
at_end
())
{
emplace_error
(
sec
::
runtime_error
,
"list index out of bounds"
);
return
false
;
}
if
(
auto
obj
=
get_if
<
settings
>
(
std
::
addressof
(
seq
.
current
()));
!
obj
)
{
emplace_error
(
sec
::
conversion_failed
,
"cannot read input as object"
);
return
false
;
}
else
{
return
fetch_object_type
(
obj
,
type
);
}
},
[
this
](
associative_array
&
)
{
emplace_error
(
sec
::
runtime_error
,
"fetch_next_object_type called inside associative array"
);
return
false
;
});
return
visit
(
f
,
st_
.
top
());
}
}
bool
settings_reader
::
begin_object
(
string_view
)
{
if
(
st_
.
empty
())
{
if
(
root_
==
nullptr
)
{
emplace_error
(
sec
::
runtime_error
,
"tried to read multiple objects from the root object"
);
return
false
;
}
st_
.
push
(
root_
);
root_
=
nullptr
;
return
true
;
}
auto
f
=
detail
::
make_overload
(
[
this
](
const
settings
*
)
{
emplace_error
(
sec
::
runtime_error
,
"begin_object called inside another object"
);
return
false
;
},
[
this
](
const
config_value
*
val
)
{
if
(
auto
obj
=
get_if
<
settings
>
(
val
))
{
// Morph into an object. This value gets "consumed" by
// begin_object/end_object.
st_
.
top
()
=
obj
;
return
true
;
}
else
{
emplace_error
(
sec
::
conversion_failed
,
"cannot read input as object"
);
return
false
;
}
},
[
this
](
key_ptr
)
{
emplace_error
(
sec
::
runtime_error
,
"reading an object from a dictionary key not implemented yet"
);
return
false
;
},
[
this
](
absent_field
)
{
emplace_error
(
sec
::
runtime_error
,
"begin_object called inside non-existent optional field"
);
return
false
;
},
[
this
](
sequence
&
seq
)
{
if
(
seq
.
at_end
())
{
emplace_error
(
sec
::
runtime_error
,
"begin_object: sequence out of bounds"
);
return
false
;
}
if
(
auto
obj
=
get_if
<
settings
>
(
std
::
addressof
(
seq
.
current
())))
{
seq
.
advance
();
st_
.
push
(
obj
);
return
true
;
}
else
{
emplace_error
(
sec
::
conversion_failed
,
"cannot read input as object"
);
return
false
;
}
},
[
this
](
associative_array
&
)
{
emplace_error
(
sec
::
runtime_error
,
"fetch_next_object_type called inside associative array"
);
return
false
;
});
return
visit
(
f
,
st_
.
top
());
}
bool
settings_reader
::
end_object
()
{
SCOPE
(
const
settings
*
);
st_
.
pop
();
return
true
;
}
bool
settings_reader
::
begin_field
(
string_view
name
)
{
SCOPE
(
const
settings
*
);
if
(
auto
i
=
top
->
find
(
name
);
i
!=
top
->
end
())
{
st_
.
push
(
std
::
addressof
(
i
->
second
));
return
true
;
}
else
{
emplace_error
(
sec
::
runtime_error
,
"no such field: "
+
to_string
(
name
));
return
false
;
}
}
bool
settings_reader
::
begin_field
(
string_view
name
,
bool
&
is_present
)
{
SCOPE
(
const
settings
*
);
if
(
auto
i
=
top
->
find
(
name
);
i
!=
top
->
end
())
{
is_present
=
true
;
st_
.
push
(
std
::
addressof
(
i
->
second
));
}
else
{
is_present
=
false
;
}
return
true
;
}
bool
settings_reader
::
begin_field
(
string_view
name
,
span
<
const
type_id_t
>
types
,
size_t
&
index
)
{
SCOPE
(
const
settings
*
);
std
::
string
key
;
key
+=
'@'
;
key
.
insert
(
key
.
end
(),
name
.
begin
(),
name
.
end
());
key
+=
"-type"
;
type_id_t
id
=
0
;
if
(
auto
str
=
get_if
<
std
::
string
>
(
top
,
key
);
!
str
)
{
emplace_error
(
sec
::
runtime_error
,
"could not find type annotation: "
+
key
);
return
false
;
}
else
if
(
id
=
query_type_id
(
*
str
);
id
==
invalid_type_id
)
{
emplace_error
(
sec
::
runtime_error
,
"no such type: "
+
*
str
);
return
false
;
}
else
if
(
auto
i
=
std
::
find
(
types
.
begin
(),
types
.
end
(),
id
);
i
==
types
.
end
())
{
emplace_error
(
sec
::
conversion_failed
,
"instrid type for variant field: "
+
*
str
);
return
false
;
}
else
{
index
=
static_cast
<
size_t
>
(
std
::
distance
(
types
.
begin
(),
i
));
}
return
begin_field
(
name
);
}
bool
settings_reader
::
begin_field
(
string_view
name
,
bool
&
is_present
,
span
<
const
type_id_t
>
types
,
size_t
&
index
)
{
SCOPE
(
const
settings
*
);
if
(
top
->
contains
(
name
))
{
is_present
=
true
;
return
begin_field
(
name
,
types
,
index
);
}
else
{
is_present
=
false
;
return
true
;
}
}
bool
settings_reader
::
end_field
()
{
CHECK_NOT_EMPTY
();
// Note: no pop() here, because the value(s) were already consumed.
return
true
;
}
bool
settings_reader
::
begin_tuple
(
size_t
size
)
{
size_t
list_size
=
0
;
if
(
begin_sequence
(
list_size
))
{
if
(
list_size
==
size
)
return
true
;
std
::
string
msg
;
msg
+=
"expected tuple of size "
;
detail
::
print
(
msg
,
size
);
msg
+=
", got tuple of size "
;
detail
::
print
(
msg
,
list_size
);
emplace_error
(
sec
::
conversion_failed
,
std
::
move
(
msg
));
return
false
;
}
return
false
;
}
bool
settings_reader
::
end_tuple
()
{
return
end_sequence
();
}
bool
settings_reader
::
begin_key_value_pair
()
{
SCOPE
(
associative_array
);
if
(
top
.
at_end
())
{
emplace_error
(
sec
::
runtime_error
,
"tried to read associate array past its end"
);
return
false
;
}
auto
&
kvp
=
top
.
current
();
st_
.
push
(
std
::
addressof
(
kvp
.
second
));
st_
.
push
(
std
::
addressof
(
kvp
.
first
));
return
true
;
}
bool
settings_reader
::
end_key_value_pair
()
{
SCOPE
(
associative_array
);
++
top
.
pos
;
return
true
;
}
bool
settings_reader
::
begin_sequence
(
size_t
&
size
)
{
SCOPE
(
const
config_value
*
);
if
(
auto
ls
=
get_if
<
config_value
::
list
>
(
top
))
{
size
=
ls
->
size
();
// "Transform" the top element to a list. Otherwise, we would need some
// extra logic only to clean up the object.
st_
.
top
()
=
sequence
{
ls
};
return
true
;
}
std
::
string
msg
=
"expected a list, got a "
;
msg
+=
top
->
type_name
();
emplace_error
(
sec
::
conversion_failed
,
std
::
move
(
msg
));
return
false
;
}
bool
settings_reader
::
end_sequence
()
{
SCOPE
(
sequence
);
if
(
!
top
.
at_end
())
{
emplace_error
(
sec
::
runtime_error
,
"failed to consume all elements in a sequence"
);
return
false
;
}
st_
.
pop
();
return
true
;
}
bool
settings_reader
::
begin_associative_array
(
size_t
&
size
)
{
SCOPE
(
const
config_value
*
);
if
(
auto
dict
=
get_if
<
settings
>
(
top
))
{
size
=
dict
->
size
();
// Morph top object, it's being "consumed" by begin_.../end_....
st_
.
top
()
=
associative_array
{
dict
->
begin
(),
dict
->
end
()};
return
true
;
}
std
::
string
msg
=
"expected a dictionary, got a "
;
msg
+=
top
->
type_name
();
emplace_error
(
sec
::
conversion_failed
,
std
::
move
(
msg
));
return
false
;
}
bool
settings_reader
::
end_associative_array
()
{
SCOPE
(
associative_array
);
if
(
!
top
.
at_end
())
{
emplace_error
(
sec
::
runtime_error
,
"failed to consume all elements in an associative array"
);
return
false
;
}
st_
.
pop
();
return
true
;
}
namespace
{
template
<
class
T
>
bool
pull
(
settings_reader
&
reader
,
T
&
x
)
{
using
internal_type
=
std
::
conditional_t
<
std
::
is_floating_point
<
T
>::
value
,
config_value
::
real
,
T
>
;
auto
assign
=
[
&
x
](
auto
&
result
)
{
if
constexpr
(
std
::
is_floating_point
<
T
>::
value
)
{
x
=
static_cast
<
T
>
(
result
);
}
else
{
x
=
result
;
}
};
auto
&
top
=
reader
.
top
();
if
(
holds_alternative
<
const
config_value
*>
(
top
))
{
auto
ptr
=
get
<
const
config_value
*>
(
top
);
if
(
auto
val
=
get_if
<
internal_type
>
(
ptr
))
{
assign
(
*
val
);
reader
.
pop
();
return
true
;
}
else
{
std
::
string
msg
=
"expected a dictionary, got a "
;
msg
+=
to_string
(
type_name_v
<
T
>
);
reader
.
emplace_error
(
sec
::
conversion_failed
,
std
::
move
(
msg
));
return
false
;
}
}
if
(
holds_alternative
<
settings_reader
::
sequence
>
(
top
))
{
auto
&
seq
=
get
<
settings_reader
::
sequence
>
(
top
);
if
(
seq
.
at_end
())
{
reader
.
emplace_error
(
sec
::
runtime_error
,
"value: sequence out of bounds"
);
return
false
;
}
auto
ptr
=
std
::
addressof
(
seq
.
current
());
if
(
auto
val
=
get_if
<
internal_type
>
(
ptr
))
{
assign
(
*
val
);
seq
.
advance
();
return
true
;
}
else
{
std
::
string
msg
=
"expected a dictionary, got a "
;
msg
+=
to_string
(
type_name_v
<
T
>
);
reader
.
emplace_error
(
sec
::
conversion_failed
,
std
::
move
(
msg
));
return
false
;
}
}
if
(
holds_alternative
<
settings_reader
::
key_ptr
>
(
top
))
{
auto
ptr
=
get
<
settings_reader
::
key_ptr
>
(
top
);
if
constexpr
(
std
::
is_same
<
std
::
string
,
T
>::
value
)
{
x
=
*
ptr
;
reader
.
pop
();
return
true
;
}
else
{
if
(
auto
err
=
detail
::
parse
(
*
ptr
,
x
))
{
reader
.
set_error
(
std
::
move
(
err
));
return
false
;
}
return
true
;
}
}
reader
.
emplace_error
(
sec
::
conversion_failed
,
"expected a value, sequence, or key"
);
return
false
;
}
}
// namespace
bool
settings_reader
::
value
(
bool
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
int8_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
uint8_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
int16_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
uint16_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
int32_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
uint32_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
int64_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
uint64_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
float
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
double
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
long
double
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
std
::
string
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
settings_reader
::
value
(
std
::
u16string
&
)
{
emplace_error
(
sec
::
runtime_error
,
"u16string support not implemented yet"
);
return
false
;
}
bool
settings_reader
::
value
(
std
::
u32string
&
)
{
emplace_error
(
sec
::
runtime_error
,
"u32string support not implemented yet"
);
return
false
;
}
bool
settings_reader
::
value
(
span
<
byte
>
bytes
)
{
CHECK_NOT_EMPTY
();
std
::
string
x
;
if
(
!
pull
(
*
this
,
x
))
return
false
;
if
(
x
.
size
()
!=
bytes
.
size
()
*
2
)
{
emplace_error
(
sec
::
runtime_error
,
"hex-formatted string does not match expected size"
);
return
false
;
}
for
(
size_t
index
=
0
;
index
<
x
.
size
();
index
+=
2
)
{
uint8_t
value
=
0
;
for
(
size_t
i
=
0
;
i
<
2
;
++
i
)
{
auto
c
=
x
[
index
+
i
];
if
(
!
isxdigit
(
c
))
{
emplace_error
(
sec
::
runtime_error
,
"invalid character in hex-formatted string"
);
return
false
;
}
detail
::
parser
::
add_ascii
<
16
>
(
value
,
c
);
}
bytes
[
index
/
2
]
=
static_cast
<
byte
>
(
value
);
}
return
true
;
}
bool
settings_reader
::
fetch_object_type
(
const
settings
*
obj
,
type_id_t
&
type
)
{
if
(
auto
str
=
get_if
<
std
::
string
>
(
obj
,
"@type"
);
str
==
nullptr
)
{
emplace_error
(
sec
::
runtime_error
,
"cannot fetch object type: no '@type' entry found"
);
return
false
;
}
else
if
(
auto
id
=
query_type_id
(
*
str
);
id
==
invalid_type_id
)
{
emplace_error
(
sec
::
runtime_error
,
"no such type: "
+
*
str
);
return
false
;
}
else
{
type
=
id
;
return
true
;
}
}
}
// namespace caf
libcaf_core/test/inspector-tests.hpp
View file @
6df8d506
...
...
@@ -47,6 +47,10 @@ struct point_3d {
int32_t
z
;
};
[[
maybe_unused
]]
bool
operator
==
(
const
point_3d
&
x
,
const
point_3d
&
y
)
{
return
std
::
tie
(
x
.
x
,
x
.
y
,
x
.
z
)
==
std
::
tie
(
y
.
x
,
y
.
y
,
y
.
z
);
}
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
point_3d
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"x"
,
x
.
x
),
f
.
field
(
"y"
,
x
.
y
),
...
...
@@ -58,6 +62,10 @@ struct line {
point_3d
p2
;
};
[[
maybe_unused
]]
bool
operator
==
(
const
line
&
x
,
const
line
&
y
)
{
return
std
::
tie
(
x
.
p1
,
x
.
p2
)
==
std
::
tie
(
y
.
p1
,
y
.
p2
);
}
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
line
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"p1"
,
x
.
p1
),
f
.
field
(
"p2"
,
x
.
p2
));
...
...
@@ -141,6 +149,11 @@ struct dummy_message {
caf
::
variant
<
std
::
string
,
double
>
content
;
};
[[
maybe_unused
]]
bool
operator
==
(
const
dummy_message
&
x
,
const
dummy_message
&
y
)
{
return
x
.
content
==
y
.
content
;
}
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
dummy_message
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"content"
,
x
.
content
));
...
...
libcaf_core/test/settings_reader.cpp
0 → 100644
View file @
6df8d506
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE settings_reader
#include "caf/settings_reader.hpp"
#include "caf/test/dsl.hpp"
#include "inspector-tests.hpp"
#include "caf/settings_writer.hpp"
using
namespace
caf
;
using
namespace
std
::
literals
::
string_literals
;
namespace
{
using
i64
=
int64_t
;
constexpr
i64
operator
""
_i64
(
unsigned
long
long
int
x
)
{
return
static_cast
<
int64_t
>
(
x
);
}
using
i64_list
=
std
::
vector
<
i64
>
;
struct
fixture
{
settings
xs
;
template
<
class
T
>
void
deserialize
(
const
settings
&
src
,
T
&
value
)
{
settings_reader
reader
{
&
src
};
if
(
!
inspect_object
(
reader
,
value
))
CAF_FAIL
(
"failed to deserialize from settings: "
<<
reader
.
get_error
());
}
template
<
class
T
>
void
deserialize
(
T
&
value
)
{
return
deserialize
(
xs
,
value
);
}
template
<
class
T
>
optional
<
T
>
get
(
const
settings
&
cfg
,
string_view
key
)
{
if
(
auto
ptr
=
get_if
<
T
>
(
&
cfg
,
key
))
return
*
ptr
;
return
none
;
}
template
<
class
T
>
optional
<
T
>
get
(
string_view
key
)
{
return
get
<
T
>
(
xs
,
key
);
}
};
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
settings_reader_tests
,
fixture
)
CAF_TEST
(
readers
deserialize
simple
objects
from
configs
)
{
put
(
xs
,
"foo"
,
"hello"
);
put
(
xs
,
"bar"
,
"world"
);
foobar
fb
;
deserialize
(
fb
);
CAF_CHECK_EQUAL
(
fb
.
foo
(),
"hello"
s
);
CAF_CHECK_EQUAL
(
fb
.
bar
(),
"world"
s
);
}
CAF_TEST
(
readers
deserialize
complex
objects
from
configs
)
{
CAF_MESSAGE
(
"fill a dictionary with data for a 'basics' object"
);
put
(
xs
,
"v1"
,
settings
{});
put
(
xs
,
"v2"
,
42
_i64
);
put
(
xs
,
"v3"
,
i64_list
({
1
,
2
,
3
,
4
}));
settings
msg1
;
put
(
msg1
,
"content"
,
2.0
);
put
(
msg1
,
"@content-type"
,
"double"
);
settings
msg2
;
put
(
msg2
,
"content"
,
"foobar"
s
);
put
(
msg2
,
"@content-type"
,
"std::string"
);
put
(
xs
,
"v4"
,
make_config_value_list
(
msg1
,
msg2
));
put
(
xs
,
"v5"
,
i64_list
({
10
,
20
}));
config_value
::
list
v6
;
v6
.
emplace_back
(
i64
{
123
});
v6
.
emplace_back
(
msg1
);
put
(
xs
,
"v6"
,
v6
);
put
(
xs
,
"v7.one"
,
i64
{
1
});
put
(
xs
,
"v7.two"
,
i64
{
2
});
put
(
xs
,
"v7.three"
,
i64
{
3
});
put
(
xs
,
"v8"
,
i64_list
());
CAF_MESSAGE
(
"deserialize and verify the 'basics' object"
);
basics
obj
;
deserialize
(
obj
);
CAF_CHECK_EQUAL
(
obj
.
v2
,
42
);
CAF_CHECK_EQUAL
(
obj
.
v3
[
0
],
1
);
CAF_CHECK_EQUAL
(
obj
.
v3
[
1
],
2
);
CAF_CHECK_EQUAL
(
obj
.
v3
[
2
],
3
);
CAF_CHECK_EQUAL
(
obj
.
v3
[
3
],
4
);
CAF_CHECK_EQUAL
(
obj
.
v4
[
0
],
dummy_message
{{
2.0
}});
CAF_CHECK_EQUAL
(
obj
.
v4
[
1
],
dummy_message
{{
"foobar"
s
}});
CAF_CHECK_EQUAL
(
obj
.
v5
[
0
],
i64
{
10
});
CAF_CHECK_EQUAL
(
obj
.
v5
[
1
],
i64
{
20
});
CAF_CHECK_EQUAL
(
obj
.
v6
,
std
::
make_tuple
(
int32_t
{
123
},
dummy_message
{{
2.0
}}));
CAF_CHECK_EQUAL
(
obj
.
v7
[
"one"
],
1
);
CAF_CHECK_EQUAL
(
obj
.
v7
[
"two"
],
2
);
CAF_CHECK_EQUAL
(
obj
.
v7
[
"three"
],
3
);
}
CAF_TEST
(
readers
deserialize
objects
from
the
output
of
writers
)
{
CAF_MESSAGE
(
"serialize the 'line' object"
);
{
line
l
{{
10
,
20
,
30
},
{
70
,
60
,
50
}};
settings_writer
writer
{
&
xs
};
if
(
!
inspect_object
(
writer
,
l
))
CAF_FAIL
(
"failed two write to settings: "
<<
writer
.
get_error
());
}
CAF_MESSAGE
(
"serialize and verify the 'line' object"
);
{
line
l
{{
0
,
0
,
0
},
{
0
,
0
,
0
}};
deserialize
(
l
);
CAF_CHECK_EQUAL
(
l
.
p1
.
x
,
10
);
CAF_CHECK_EQUAL
(
l
.
p1
.
y
,
20
);
CAF_CHECK_EQUAL
(
l
.
p1
.
z
,
30
);
CAF_CHECK_EQUAL
(
l
.
p2
.
x
,
70
);
CAF_CHECK_EQUAL
(
l
.
p2
.
y
,
60
);
CAF_CHECK_EQUAL
(
l
.
p2
.
z
,
50
);
}
}
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