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
c6e7fdb6
Commit
c6e7fdb6
authored
Sep 08, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Plain Diff
Merge 'topic/inspector-api'
parents
97fea3fd
e26b322a
Changes
29
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
1520 additions
and
1931 deletions
+1520
-1931
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+4
-4
libcaf_core/caf/all.hpp
libcaf_core/caf/all.hpp
+0
-7
libcaf_core/caf/config_value.hpp
libcaf_core/caf/config_value.hpp
+398
-316
libcaf_core/caf/config_value_adaptor.hpp
libcaf_core/caf/config_value_adaptor.hpp
+0
-93
libcaf_core/caf/config_value_adaptor_access.hpp
libcaf_core/caf/config_value_adaptor_access.hpp
+0
-116
libcaf_core/caf/config_value_adaptor_field.hpp
libcaf_core/caf/config_value_adaptor_field.hpp
+0
-62
libcaf_core/caf/config_value_field.hpp
libcaf_core/caf/config_value_field.hpp
+0
-63
libcaf_core/caf/config_value_object_access.hpp
libcaf_core/caf/config_value_object_access.hpp
+0
-172
libcaf_core/caf/config_value_reader.hpp
libcaf_core/caf/config_value_reader.hpp
+171
-0
libcaf_core/caf/config_value_writer.hpp
libcaf_core/caf/config_value_writer.hpp
+12
-15
libcaf_core/caf/detail/config_value_adaptor_field_impl.hpp
libcaf_core/caf/detail/config_value_adaptor_field_impl.hpp
+0
-72
libcaf_core/caf/detail/config_value_field_base.hpp
libcaf_core/caf/detail/config_value_field_base.hpp
+0
-109
libcaf_core/caf/detail/config_value_field_impl.hpp
libcaf_core/caf/detail/config_value_field_impl.hpp
+0
-146
libcaf_core/caf/detail/parse.hpp
libcaf_core/caf/detail/parse.hpp
+2
-0
libcaf_core/caf/make_config_option.hpp
libcaf_core/caf/make_config_option.hpp
+3
-3
libcaf_core/caf/make_config_value_field.hpp
libcaf_core/caf/make_config_value_field.hpp
+0
-92
libcaf_core/caf/sec.hpp
libcaf_core/caf/sec.hpp
+8
-6
libcaf_core/caf/settings.hpp
libcaf_core/caf/settings.hpp
+2
-1
libcaf_core/src/config_value_reader.cpp
libcaf_core/src/config_value_reader.cpp
+567
-0
libcaf_core/src/config_value_writer.cpp
libcaf_core/src/config_value_writer.cpp
+95
-74
libcaf_core/src/detail/parse.cpp
libcaf_core/src/detail/parse.cpp
+2
-0
libcaf_core/src/make_config_option.cpp
libcaf_core/src/make_config_option.cpp
+13
-16
libcaf_core/src/sec_strings.cpp
libcaf_core/src/sec_strings.cpp
+2
-0
libcaf_core/test/config_value.cpp
libcaf_core/test/config_value.cpp
+55
-0
libcaf_core/test/config_value_adaptor.cpp
libcaf_core/test/config_value_adaptor.cpp
+0
-239
libcaf_core/test/config_value_reader.cpp
libcaf_core/test/config_value_reader.cpp
+162
-0
libcaf_core/test/config_value_writer.cpp
libcaf_core/test/config_value_writer.cpp
+11
-5
libcaf_core/test/inspector-tests.hpp
libcaf_core/test/inspector-tests.hpp
+13
-0
libcaf_core/test/make_config_value_field.cpp
libcaf_core/test/make_config_value_field.cpp
+0
-320
No files found.
libcaf_core/CMakeLists.txt
View file @
c6e7fdb6
...
@@ -68,6 +68,8 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
...
@@ -68,6 +68,8 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/config_option_adder.cpp
src/config_option_adder.cpp
src/config_option_set.cpp
src/config_option_set.cpp
src/config_value.cpp
src/config_value.cpp
src/config_value_reader.cpp
src/config_value_writer.cpp
src/credit_controller.cpp
src/credit_controller.cpp
src/decorator/sequencer.cpp
src/decorator/sequencer.cpp
src/default_attachable.cpp
src/default_attachable.cpp
...
@@ -160,7 +162,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
...
@@ -160,7 +162,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/sec_strings.cpp
src/sec_strings.cpp
src/serializer.cpp
src/serializer.cpp
src/settings.cpp
src/settings.cpp
src/settings_writer.cpp
src/skip.cpp
src/skip.cpp
src/stream_aborter.cpp
src/stream_aborter.cpp
src/stream_manager.cpp
src/stream_manager.cpp
...
@@ -232,7 +233,8 @@ caf_add_test_suites(caf-core-test
...
@@ -232,7 +233,8 @@ caf_add_test_suites(caf-core-test
config_option
config_option
config_option_set
config_option_set
config_value
config_value
config_value_adaptor
config_value_reader
config_value_writer
const_typed_message_view
const_typed_message_view
constructor_attach
constructor_attach
continuous_streaming
continuous_streaming
...
@@ -288,7 +290,6 @@ caf_add_test_suites(caf-core-test
...
@@ -288,7 +290,6 @@ caf_add_test_suites(caf-core-test
local_group
local_group
logger
logger
mailbox_element
mailbox_element
make_config_value_field
message
message
message_builder
message_builder
message_id
message_id
...
@@ -312,7 +313,6 @@ caf_add_test_suites(caf-core-test
...
@@ -312,7 +313,6 @@ caf_add_test_suites(caf-core-test
serial_reply
serial_reply
serialization
serialization
settings
settings
settings_writer
simple_timeout
simple_timeout
span
span
stateful_actor
stateful_actor
...
...
libcaf_core/caf/all.hpp
View file @
c6e7fdb6
...
@@ -48,16 +48,10 @@
...
@@ -48,16 +48,10 @@
#include "caf/config_option.hpp"
#include "caf/config_option.hpp"
#include "caf/config_option_adder.hpp"
#include "caf/config_option_adder.hpp"
#include "caf/config_value.hpp"
#include "caf/config_value.hpp"
#include "caf/config_value_adaptor.hpp"
#include "caf/config_value_adaptor_access.hpp"
#include "caf/config_value_adaptor_field.hpp"
#include "caf/config_value_field.hpp"
#include "caf/config_value_object_access.hpp"
#include "caf/const_typed_message_view.hpp"
#include "caf/const_typed_message_view.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/defaults.hpp"
#include "caf/defaults.hpp"
#include "caf/deserializer.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/config_value_adaptor_field_impl.hpp"
#include "caf/downstream_msg.hpp"
#include "caf/downstream_msg.hpp"
#include "caf/error.hpp"
#include "caf/error.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
...
@@ -74,7 +68,6 @@
...
@@ -74,7 +68,6 @@
#include "caf/local_actor.hpp"
#include "caf/local_actor.hpp"
#include "caf/logger.hpp"
#include "caf/logger.hpp"
#include "caf/make_config_option.hpp"
#include "caf/make_config_option.hpp"
#include "caf/make_config_value_field.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/memory_managed.hpp"
#include "caf/memory_managed.hpp"
#include "caf/message.hpp"
#include "caf/message.hpp"
...
...
libcaf_core/caf/config_value.hpp
View file @
c6e7fdb6
...
@@ -28,6 +28,8 @@
...
@@ -28,6 +28,8 @@
#include <type_traits>
#include <type_traits>
#include <vector>
#include <vector>
#include "caf/config_value_reader.hpp"
#include "caf/config_value_writer.hpp"
#include "caf/detail/bounds_checker.hpp"
#include "caf/detail/bounds_checker.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/move_if_not_ptr.hpp"
#include "caf/detail/move_if_not_ptr.hpp"
...
@@ -257,11 +259,9 @@ struct default_config_value_access {
...
@@ -257,11 +259,9 @@ struct default_config_value_access {
}
}
};
};
struct
config_value_access_unspecialized
{};
/// @relates config_value
/// @relates config_value
template
<
class
T
>
template
<
class
T
>
struct
config_value_access
:
config_value_access_unspecialized
{}
;
struct
config_value_access
;
#define CAF_DEFAULT_CONFIG_VALUE_ACCESS(type, name) \
#define CAF_DEFAULT_CONFIG_VALUE_ACCESS(type, name) \
template <> \
template <> \
...
@@ -279,6 +279,36 @@ CAF_DEFAULT_CONFIG_VALUE_ACCESS(uri, "uri");
...
@@ -279,6 +279,36 @@ CAF_DEFAULT_CONFIG_VALUE_ACCESS(uri, "uri");
#undef CAF_DEFAULT_CONFIG_VALUE_ACCESS
#undef CAF_DEFAULT_CONFIG_VALUE_ACCESS
template
<
>
struct
CAF_CORE_EXPORT
config_value_access
<
float
>
{
static
std
::
string
type_name
()
{
return
"real32"
;
}
static
bool
is
(
const
config_value
&
x
)
{
return
holds_alternative
<
double
>
(
x
.
get_data
());
}
static
optional
<
float
>
get_if
(
const
config_value
*
x
)
{
if
(
auto
res
=
caf
::
get_if
<
double
>
(
&
(
x
->
get_data
())))
return
static_cast
<
float
>
(
*
res
);
return
none
;
}
static
float
get
(
const
config_value
&
x
)
{
return
static_cast
<
float
>
(
caf
::
get
<
double
>
(
x
.
get_data
()));
}
static
double
convert
(
float
x
)
{
return
x
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
float
&
x
,
Nested
)
{
detail
::
parse
(
ps
,
x
);
}
};
template
<
>
template
<
>
struct
CAF_CORE_EXPORT
config_value_access
<
std
::
string
>
{
struct
CAF_CORE_EXPORT
config_value_access
<
std
::
string
>
{
using
super
=
default_config_value_access
<
std
::
string
>
;
using
super
=
default_config_value_access
<
std
::
string
>
;
...
@@ -313,380 +343,317 @@ struct CAF_CORE_EXPORT config_value_access<std::string> {
...
@@ -313,380 +343,317 @@ struct CAF_CORE_EXPORT config_value_access<std::string> {
}
}
};
};
enum
class
select_config_value_hint
{
// -- implementation details for get/get_if/holds_alternative ------------------
is_integral
,
is_map
,
namespace
detail
{
is_list
,
is_custom
,
/// Wraps tag types for static dispatching.
is_missing
,
/// @relates config_value_access_type
struct
config_value_access_type
{
/// Flags types that provide a `config_value_access` specialization.
struct
specialization
{};
/// Flags builtin integral types.
struct
integral
{};
/// Flags types with `std::tuple`-like API.
struct
tuple
{};
/// Flags types with `std::map`-like API.
struct
map
{};
/// Flags types with `std::vector`-like API.
struct
list
{};
/// Flags types without default access that shall fall back to using the
/// inspection API.
struct
inspect
{};
};
};
/// @relates config_value_access_type
template
<
class
T
>
template
<
class
T
>
constexpr
select_config_value_hint
select_config_value_oracle
()
{
constexpr
auto
config_value_access_token
()
{
return
std
::
is_integral
<
T
>::
value
&&
!
std
::
is_same
<
T
,
bool
>::
value
if
constexpr
(
detail
::
is_complete
<
config_value_access
<
T
>>
)
?
select_config_value_hint
::
is_integral
return
config_value_access_type
::
specialization
{};
:
(
detail
::
is_map_like
<
T
>::
value
else
if
constexpr
(
std
::
is_integral
<
T
>::
value
)
?
select_config_value_hint
::
is_map
return
config_value_access_type
::
integral
{};
:
(
detail
::
is_list_like
<
T
>::
value
else
if
constexpr
(
detail
::
is_stl_tuple_type_v
<
T
>
)
?
select_config_value_hint
::
is_list
return
config_value_access_type
::
tuple
{};
:
(
!
std
::
is_base_of
<
config_value_access_unspecialized
,
else
if
constexpr
(
detail
::
is_map_like
<
T
>::
value
)
config_value_access
<
T
>>::
value
return
config_value_access_type
::
map
{};
?
select_config_value_hint
::
is_custom
else
if
constexpr
(
detail
::
is_list_like
<
T
>::
value
)
:
select_config_value_hint
::
is_missing
)));
return
config_value_access_type
::
list
{};
else
return
config_value_access_type
::
inspect
{};
}
}
/// Delegates to config_value_access for all specialized versions.
template
<
class
T
>
template
<
class
T
,
struct
integral_config_value_access
;
select_config_value_hint
Hint
=
select_config_value_oracle
<
T
>()
>
struct
select_config_value_access
{
static_assert
(
Hint
==
select_config_value_hint
::
is_custom
,
"no default or specialization for config_value_access found"
);
using
type
=
config_value_access
<
T
>
;
};
template
<
class
T
>
template
<
class
T
>
using
select_config_value_access_t
=
struct
tuple_config_value_access
;
typename
select_config_value_access
<
T
>::
type
;
template
<
>
template
<
class
T
>
struct
sum_type_access
<
config_value
>
{
struct
map_config_value_access
;
using
types
=
typename
config_value
::
types
;
using
type0
=
typename
detail
::
tl_head
<
types
>::
type
;
template
<
class
T
>
struct
list_config_value_access
;
static
constexpr
bool
specialized
=
true
;
template
<
class
T
>
struct
inspect_config_value_access
;
template
<
class
U
,
int
Pos
>
template
<
class
T
,
class
Token
>
static
bool
is
(
const
config_value
&
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
struct
config_value_access_oracle
;
return
x
.
get_data
().
is
(
pos
(
token
));
}
template
<
class
U
>
template
<
class
T
>
static
bool
is
(
const
config_value
&
x
,
sum_type_token
<
U
,
-
1
>
)
{
struct
config_value_access_oracle
<
T
,
config_value_access_type
::
specialization
>
{
return
select_config_value_access_t
<
U
>::
is
(
x
)
;
using
type
=
config_value_access
<
T
>
;
}
};
template
<
class
U
,
int
Pos
>
#define CAF_CONFIG_VALUE_ACCESS_ORACLE(access_type) \
static
U
&
get
(
config_value
&
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
template <class T> \
return
x
.
get_data
().
get
(
pos
(
token
));
struct config_value_access_oracle<T, \
config_value_access_type::access_type> { \
using type = access_type##_config_value_access<T>; \
}
}
template
<
class
U
>
CAF_CONFIG_VALUE_ACCESS_ORACLE
(
integral
);
static
U
get
(
config_value
&
x
,
sum_type_token
<
U
,
-
1
>
)
{
CAF_CONFIG_VALUE_ACCESS_ORACLE
(
tuple
);
return
select_config_value_access_t
<
U
>::
get
(
x
);
CAF_CONFIG_VALUE_ACCESS_ORACLE
(
map
);
}
CAF_CONFIG_VALUE_ACCESS_ORACLE
(
list
);
CAF_CONFIG_VALUE_ACCESS_ORACLE
(
inspect
);
template
<
class
U
,
int
Pos
>
#undef CAF_CONFIG_VALUE_ACCESS_ORACLE
static
const
U
&
get
(
const
config_value
&
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
return
x
.
get_data
().
get
(
pos
(
token
));
}
template
<
class
U
>
template
<
class
T
>
static
U
get
(
const
config_value
&
x
,
sum_type_token
<
U
,
-
1
>
)
{
using
config_value_access_t
=
typename
config_value_access_oracle
<
return
select_config_value_access_t
<
U
>::
get
(
x
);
T
,
decltype
(
config_value_access_token
<
T
>
())
>::
type
;
}
template
<
class
U
,
int
Pos
>
template
<
class
T
>
static
U
*
get_if
(
config_value
*
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
struct
integral_config_value_access
{
return
is
(
*
x
,
token
)
?
&
get
(
*
x
,
token
)
:
nullptr
;
using
integer_type
=
config_value
::
integer
;
static
std
::
string
type_name
()
{
std
::
string
result
;
if
(
std
::
is_signed
<
T
>::
value
)
result
=
"int"
;
else
result
=
"uint"
;
result
+=
std
::
to_string
(
sizeof
(
T
)
*
8
);
return
result
;
}
}
template
<
class
U
>
static
bool
is
(
const
config_value
&
x
)
{
static
optional
<
U
>
get_if
(
config_value
*
x
,
sum_type_token
<
U
,
-
1
>
)
{
auto
ptr
=
caf
::
get_if
<
integer_type
>
(
x
.
get_data_ptr
());
return
select_config_value_access_t
<
U
>::
get_if
(
x
);
return
ptr
!=
nullptr
&&
detail
::
bounds_checker
<
T
>::
check
(
*
ptr
);
}
}
template
<
class
U
,
int
Pos
>
static
optional
<
T
>
get_if
(
const
config_value
*
x
)
{
static
const
U
*
get_if
(
const
config_value
*
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
auto
ptr
=
caf
::
get_if
<
integer_type
>
(
x
->
get_data_ptr
());
return
is
(
*
x
,
token
)
?
&
get
(
*
x
,
token
)
:
nullptr
;
if
(
ptr
!=
nullptr
&&
detail
::
bounds_checker
<
T
>::
check
(
*
ptr
))
return
static_cast
<
T
>
(
*
ptr
);
return
none
;
}
}
template
<
class
U
>
static
T
get
(
const
config_value
&
x
)
{
static
optional
<
U
>
get_if
(
const
config_value
*
x
,
sum_type_token
<
U
,
-
1
>
)
{
auto
res
=
get_if
(
&
x
);
return
select_config_value_access_t
<
U
>::
get_if
(
x
);
CAF_ASSERT
(
res
!=
none
);
return
*
res
;
}
}
template
<
class
Result
,
class
Visitor
,
class
...
Ts
>
static
T
convert
(
T
x
)
{
static
Result
apply
(
config_value
&
x
,
Visitor
&&
visitor
,
Ts
&&
...
xs
)
{
return
x
;
return
x
.
get_data
().
template
apply
<
Result
>(
std
::
forward
<
Visitor
>
(
visitor
),
std
::
forward
<
Ts
>
(
xs
)...);
}
}
template
<
class
Result
,
class
Visitor
,
class
...
Ts
>
template
<
class
Nested
>
static
Result
apply
(
const
config_value
&
x
,
Visitor
&&
visitor
,
Ts
&&
...
xs
)
{
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
x
,
Nested
)
{
return
x
.
get_data
().
template
apply
<
Result
>(
std
::
forward
<
Visitor
>
(
visitor
),
detail
::
parse
(
ps
,
x
);
std
::
forward
<
Ts
>
(
xs
)...);
}
}
};
};
/// Catches all non-specialized integer types.
template
<
class
T
>
template
<
class
T
>
struct
select_config_value_access
<
T
,
select_config_value_hint
::
is_integral
>
{
struct
list_config_value_access
{
struct
type
{
using
list_type
=
T
;
using
integer_type
=
config_value
::
integer
;
static
std
::
string
type_name
()
{
std
::
string
result
;
if
(
std
::
is_signed
<
T
>::
value
)
result
=
"int"
;
else
result
=
"uint"
;
result
+=
std
::
to_string
(
sizeof
(
T
)
*
8
);
return
result
;
}
static
bool
is
(
const
config_value
&
x
)
{
using
value_type
=
typename
list_type
::
value_type
;
auto
ptr
=
caf
::
get_if
<
integer_type
>
(
x
.
get_data_ptr
());
return
ptr
!=
nullptr
&&
detail
::
bounds_checker
<
T
>::
check
(
*
ptr
);
}
static
optional
<
T
>
get_if
(
const
config_value
*
x
)
{
using
value_access
=
config_value_access_t
<
value_type
>
;
auto
ptr
=
caf
::
get_if
<
integer_type
>
(
x
->
get_data_ptr
());
if
(
ptr
!=
nullptr
&&
detail
::
bounds_checker
<
T
>::
check
(
*
ptr
))
return
static_cast
<
T
>
(
*
ptr
);
return
none
;
}
static
T
get
(
const
config_value
&
x
)
{
static
std
::
string
type_name
()
{
auto
res
=
get_if
(
&
x
);
return
"list of "
+
value_access
::
type_name
();
CAF_ASSERT
(
res
!=
none
);
}
return
*
res
;
}
static
T
convert
(
T
x
)
{
return
x
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
x
,
Nested
)
{
detail
::
parse
(
ps
,
x
);
}
};
};
/// Catches all non-specialized list types.
template
<
class
T
>
struct
select_config_value_access
<
T
,
select_config_value_hint
::
is_list
>
{
struct
type
{
using
list_type
=
T
;
using
value_type
=
typename
list_type
::
value_type
;
using
value_trait
=
select_config_value_access_t
<
value_type
>
;
static
std
::
string
type_name
()
{
static
bool
is
(
const
config_value
&
x
)
{
return
"list of "
+
value_trait
::
type_name
();
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
(
x
.
get_data
()));
}
return
lst
!=
nullptr
&&
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
[](
const
config_value
&
y
)
{
return
caf
::
holds_alternative
<
value_type
>
(
y
);
});
return
false
;
}
static
bool
is
(
const
config_value
&
x
)
{
static
optional
<
list_type
>
get_if
(
const
config_value
*
x
)
{
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
x
);
list_type
result
;
return
lst
!=
nullptr
auto
out
=
std
::
inserter
(
result
,
result
.
end
());
&&
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
auto
extract
=
[
&
](
const
config_value
&
y
)
{
[](
const
config_value
&
y
)
{
if
(
auto
opt
=
caf
::
get_if
<
value_type
>
(
&
y
))
{
return
caf
::
holds_alternative
<
value_type
>
(
y
);
*
out
++
=
move_if_optional
(
opt
);
});
return
true
;
}
return
false
;
return
false
;
}
};
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
(
x
->
get_data
()));
if
(
lst
!=
nullptr
&&
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
extract
))
return
result
;
return
none
;
}
static
optional
<
list_type
>
get_if
(
const
config_value
*
x
)
{
static
list_type
get
(
const
config_value
&
x
)
{
list_type
result
;
auto
result
=
get_if
(
&
x
);
auto
out
=
std
::
inserter
(
result
,
result
.
end
());
if
(
!
result
)
auto
extract
=
[
&
](
const
config_value
&
y
)
{
CAF_RAISE_ERROR
(
"invalid type found"
);
if
(
auto
opt
=
caf
::
get_if
<
value_type
>
(
&
y
))
{
return
std
::
move
(
*
result
);
*
out
++
=
move_if_optional
(
opt
);
}
return
true
;
}
return
false
;
};
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
x
);
if
(
lst
!=
nullptr
&&
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
extract
))
return
result
;
return
none
;
}
static
list_type
get
(
const
config_value
&
x
)
{
static
config_value
::
list
convert
(
const
list_type
&
xs
)
{
auto
result
=
get_if
(
&
x
)
;
config_value
::
list
result
;
if
(
!
result
)
for
(
const
auto
&
x
:
xs
)
CAF_RAISE_ERROR
(
"invalid type found"
);
result
.
emplace_back
(
value_access
::
convert
(
x
)
);
return
std
::
move
(
*
result
)
;
return
result
;
}
}
static
config_value
::
list
convert
(
const
list_type
&
xs
)
{
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
xs
,
config_value
::
list
result
;
top_level_cli_parsing_t
)
{
for
(
const
auto
&
x
:
xs
)
bool
has_open_token
;
result
.
emplace_back
(
value_trait
::
convert
(
x
));
auto
val_token
=
config_value_access_token
<
value_type
>
();
return
result
;
if
constexpr
(
std
::
is_same
<
decltype
(
val_token
),
config_value_access_type
::
list
>::
value
)
{
// The outer square brackets are optional in nested lists. This means we
// need to check for "[[" at the beginning and otherwise we assume the
// leading '[' was omitted.
string_parser_state
tmp
{
ps
.
i
,
ps
.
e
};
has_open_token
=
tmp
.
consume
(
'['
)
&&
tmp
.
consume
(
'['
);
if
(
has_open_token
)
ps
.
consume
(
'['
);
}
else
{
has_open_token
=
ps
.
consume
(
'['
);
}
}
do
{
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
xs
,
top_level_cli_parsing_t
)
{
bool
has_open_token
;
auto
subtype
=
select_config_value_oracle
<
value_type
>
();
if
(
subtype
==
select_config_value_hint
::
is_list
)
{
// The outer square brackets are optional in nested lists. This means we
// need to check for "[[" at the beginning and otherwise we assume the
// leading '[' was omitted.
string_parser_state
tmp
{
ps
.
i
,
ps
.
e
};
has_open_token
=
tmp
.
consume
(
'['
)
&&
tmp
.
consume
(
'['
);
if
(
has_open_token
)
ps
.
consume
(
'['
);
}
else
{
has_open_token
=
ps
.
consume
(
'['
);
}
do
{
ps
.
skip_whitespaces
();
if
(
has_open_token
)
{
if
(
ps
.
consume
(
']'
))
{
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
return
;
}
}
else
if
(
ps
.
at_end
())
{
// Allow trailing commas and empty strings.
ps
.
code
=
pec
::
success
;
return
;
}
value_type
tmp
;
value_trait
::
parse_cli
(
ps
,
tmp
,
nested_cli_parsing
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
xs
.
insert
(
xs
.
end
(),
std
::
move
(
tmp
));
}
while
(
ps
.
consume
(
','
));
if
(
has_open_token
&&
!
ps
.
consume
(
']'
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
ps
.
skip_whitespaces
();
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
if
(
has_open_token
)
{
}
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
xs
,
nested_cli_parsing_t
)
{
if
(
!
ps
.
consume
(
'['
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
do
{
if
(
ps
.
consume
(
']'
))
{
if
(
ps
.
consume
(
']'
))
{
ps
.
skip_whitespaces
();
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
return
;
return
;
}
}
value_type
tmp
;
}
else
if
(
ps
.
at_end
())
{
value_trait
::
parse_cli
(
ps
,
tmp
,
nested_cli_parsing
);
// Allow trailing commas and empty strings.
if
(
ps
.
code
>
pec
::
trailing_character
)
ps
.
code
=
pec
::
success
;
return
;
xs
.
insert
(
xs
.
end
(),
std
::
move
(
tmp
));
}
while
(
ps
.
consume
(
','
));
if
(
!
ps
.
consume
(
']'
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
return
;
}
}
ps
.
skip_whitespaces
();
value_type
tmp
;
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
value_access
::
parse_cli
(
ps
,
tmp
,
nested_cli_parsing
);
}
if
(
ps
.
code
>
pec
::
trailing_character
)
};
return
;
};
xs
.
insert
(
xs
.
end
(),
std
::
move
(
tmp
));
}
while
(
ps
.
consume
(
','
));
/// Catches all non-specialized map types.
if
(
has_open_token
&&
!
ps
.
consume
(
']'
))
{
template
<
class
T
>
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
struct
select_config_value_access
<
T
,
select_config_value_hint
::
is_map
>
{
return
;
struct
type
{
using
map_type
=
T
;
using
mapped_type
=
typename
map_type
::
mapped_type
;
using
mapped_trait
=
select_config_value_access_t
<
mapped_type
>
;
static
std
::
string
type_name
()
{
std
::
string
result
=
"dictionary of "
;
auto
nested_name
=
mapped_trait
::
type_name
();
result
.
insert
(
result
.
end
(),
nested_name
.
begin
(),
nested_name
.
end
());
return
result
;
}
}
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
}
static
bool
is
(
const
config_value
&
x
)
{
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
xs
,
nested_cli_parsing_t
)
{
using
value_type
=
config_value
::
dictionary
::
value_type
;
if
(
!
ps
.
consume
(
'['
))
{
auto
is_mapped_type
=
[](
const
value_type
&
y
)
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
caf
::
holds_alternative
<
mapped_type
>
(
y
.
second
);
return
;
};
if
(
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
&
x
))
return
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
is_mapped_type
);
return
false
;
}
}
do
{
static
optional
<
map_type
>
get_if
(
const
config_value
*
x
)
{
if
(
ps
.
consume
(
']'
)
)
{
using
value_type
=
config_value
::
dictionary
::
value_type
;
ps
.
skip_whitespaces
()
;
map_type
result
;
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
auto
extract
=
[
&
](
const
value_type
&
y
)
{
return
;
if
(
auto
opt
=
caf
::
get_if
<
mapped_type
>
(
&
y
.
second
))
{
}
result
.
emplace
(
y
.
first
,
move_if_optional
(
opt
))
;
value_type
tmp
;
return
true
;
value_access
::
parse_cli
(
ps
,
tmp
,
nested_cli_parsing
)
;
}
if
(
ps
.
code
>
pec
::
trailing_character
)
return
false
;
return
;
}
;
xs
.
insert
(
xs
.
end
(),
std
::
move
(
tmp
))
;
if
(
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
x
))
}
while
(
ps
.
consume
(
','
));
if
(
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
extract
))
if
(
!
ps
.
consume
(
']'
))
{
return
result
;
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
none
;
return
;
}
}
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
}
};
static
map_type
get
(
const
config_value
&
x
)
{
template
<
class
T
>
auto
result
=
get_if
(
&
x
);
struct
map_config_value_access
{
if
(
!
result
)
using
map_type
=
T
;
CAF_RAISE_ERROR
(
"invalid type found"
);
return
std
::
move
(
*
result
);
}
template
<
class
Nested
>
using
mapped_type
=
typename
map_type
::
mapped_type
;
static
void
parse_cli
(
string_parser_state
&
ps
,
map_type
&
xs
,
Nested
)
{
detail
::
parse
(
ps
,
xs
);
}
static
config_value
::
dictionary
convert
(
const
map_type
&
xs
)
{
using
mapped_access
=
config_value_access_t
<
mapped_type
>
;
config_value
::
dictionary
result
;
for
(
const
auto
&
x
:
xs
)
result
.
emplace
(
x
.
first
,
mapped_trait
::
convert
(
x
.
second
));
return
result
;
}
};
};
template
<
>
struct
config_value_access
<
float
>
{
static
std
::
string
type_name
()
{
static
std
::
string
type_name
()
{
return
"real32"
;
std
::
string
result
=
"dictionary of "
;
auto
nested_name
=
mapped_access
::
type_name
();
result
.
insert
(
result
.
end
(),
nested_name
.
begin
(),
nested_name
.
end
());
return
result
;
}
}
static
bool
is
(
const
config_value
&
x
)
{
static
bool
is
(
const
config_value
&
x
)
{
return
holds_alternative
<
double
>
(
x
.
get_data
());
using
value_type
=
config_value
::
dictionary
::
value_type
;
auto
is_mapped_type
=
[](
const
value_type
&
y
)
{
return
caf
::
holds_alternative
<
mapped_type
>
(
y
.
second
);
};
if
(
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
&
(
x
.
get_data
())))
return
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
is_mapped_type
);
return
false
;
}
}
static
optional
<
float
>
get_if
(
const
config_value
*
x
)
{
static
optional
<
map_type
>
get_if
(
const
config_value
*
x
)
{
if
(
auto
res
=
caf
::
get_if
<
double
>
(
&
(
x
->
get_data
())))
using
value_type
=
config_value
::
dictionary
::
value_type
;
return
static_cast
<
float
>
(
*
res
);
map_type
result
;
auto
extract
=
[
&
](
const
value_type
&
y
)
{
if
(
auto
opt
=
caf
::
get_if
<
mapped_type
>
(
&
y
.
second
))
{
result
.
emplace
(
y
.
first
,
move_if_optional
(
opt
));
return
true
;
}
return
false
;
};
if
(
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
&
(
x
->
get_data
())))
if
(
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
extract
))
return
result
;
return
none
;
return
none
;
}
}
static
float
get
(
const
config_value
&
x
)
{
static
map_type
get
(
const
config_value
&
x
)
{
return
static_cast
<
float
>
(
caf
::
get
<
double
>
(
x
.
get_data
()));
auto
result
=
get_if
(
&
x
);
if
(
!
result
)
CAF_RAISE_ERROR
(
"invalid type found"
);
return
std
::
move
(
*
result
);
}
}
static
double
convert
(
float
x
)
{
template
<
class
Nested
>
return
x
;
static
void
parse_cli
(
string_parser_state
&
ps
,
map_type
&
xs
,
Nested
)
{
detail
::
parse
(
ps
,
xs
);
}
}
template
<
class
Nested
>
static
config_value
::
dictionary
convert
(
const
map_type
&
xs
)
{
static
void
parse_cli
(
string_parser_state
&
ps
,
float
&
x
,
Nested
)
{
config_value
::
dictionary
result
;
detail
::
parse
(
ps
,
x
);
for
(
const
auto
&
x
:
xs
)
result
.
emplace
(
x
.
first
,
mapped_access
::
convert
(
x
.
second
));
return
result
;
}
}
};
};
/// Implements automagic unboxing of `std::tuple<Ts...>` from a heterogeneous
///`config_value::list`.
/// @relates config_value
template
<
class
...
Ts
>
template
<
class
...
Ts
>
struct
config_value_access
<
std
::
tuple
<
Ts
...
>>
{
struct
tuple_
config_value_access
<
std
::
tuple
<
Ts
...
>>
{
using
tuple_type
=
std
::
tuple
<
Ts
...
>
;
using
tuple_type
=
std
::
tuple
<
Ts
...
>
;
static
std
::
string
type_name
()
{
static
std
::
string
type_name
()
{
...
@@ -697,7 +664,7 @@ struct config_value_access<std::tuple<Ts...>> {
...
@@ -697,7 +664,7 @@ struct config_value_access<std::tuple<Ts...>> {
}
}
static
bool
is
(
const
config_value
&
x
)
{
static
bool
is
(
const
config_value
&
x
)
{
if
(
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
x
))
{
if
(
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
(
x
.
get_data
())
))
{
if
(
lst
->
size
()
!=
sizeof
...(
Ts
))
if
(
lst
->
size
()
!=
sizeof
...(
Ts
))
return
false
;
return
false
;
return
rec_is
(
*
lst
,
detail
::
int_token
<
0
>
(),
detail
::
type_list
<
Ts
...
>
());
return
rec_is
(
*
lst
,
detail
::
int_token
<
0
>
(),
detail
::
type_list
<
Ts
...
>
());
...
@@ -706,7 +673,7 @@ struct config_value_access<std::tuple<Ts...>> {
...
@@ -706,7 +673,7 @@ struct config_value_access<std::tuple<Ts...>> {
}
}
static
optional
<
tuple_type
>
get_if
(
const
config_value
*
x
)
{
static
optional
<
tuple_type
>
get_if
(
const
config_value
*
x
)
{
if
(
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
x
))
{
if
(
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
(
x
->
get_data
())
))
{
if
(
lst
->
size
()
!=
sizeof
...(
Ts
))
if
(
lst
->
size
()
!=
sizeof
...(
Ts
))
return
none
;
return
none
;
tuple_type
result
;
tuple_type
result
;
...
@@ -793,7 +760,7 @@ private:
...
@@ -793,7 +760,7 @@ private:
template
<
int
Pos
,
class
U
,
class
...
Us
>
template
<
int
Pos
,
class
U
,
class
...
Us
>
static
void
rec_convert
(
config_value
::
list
&
result
,
const
tuple_type
&
xs
,
static
void
rec_convert
(
config_value
::
list
&
result
,
const
tuple_type
&
xs
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<
U
,
Us
...
>
)
{
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<
U
,
Us
...
>
)
{
using
trait
=
select_
config_value_access_t
<
U
>
;
using
trait
=
config_value_access_t
<
U
>
;
result
.
emplace_back
(
trait
::
convert
(
std
::
get
<
Pos
>
(
xs
)));
result
.
emplace_back
(
trait
::
convert
(
std
::
get
<
Pos
>
(
xs
)));
return
rec_convert
(
result
,
xs
,
detail
::
int_token
<
Pos
+
1
>
(),
return
rec_convert
(
result
,
xs
,
detail
::
int_token
<
Pos
+
1
>
(),
detail
::
type_list
<
Us
...
>
());
detail
::
type_list
<
Us
...
>
());
...
@@ -808,7 +775,7 @@ private:
...
@@ -808,7 +775,7 @@ private:
template
<
int
Pos
,
class
U
,
class
...
Us
>
template
<
int
Pos
,
class
U
,
class
...
Us
>
static
void
rec_parse
(
string_parser_state
&
ps
,
tuple_type
&
xs
,
static
void
rec_parse
(
string_parser_state
&
ps
,
tuple_type
&
xs
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<
U
,
Us
...
>
)
{
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<
U
,
Us
...
>
)
{
using
trait
=
select_
config_value_access_t
<
U
>
;
using
trait
=
config_value_access_t
<
U
>
;
trait
::
parse_cli
(
std
::
get
<
Pos
>
(
xs
),
nested_cli_parsing
);
trait
::
parse_cli
(
std
::
get
<
Pos
>
(
xs
),
nested_cli_parsing
);
if
(
ps
.
code
>
pec
::
trailing_character
)
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
return
;
...
@@ -818,7 +785,121 @@ private:
...
@@ -818,7 +785,121 @@ private:
}
}
};
};
// -- SumType-like access of dictionary values ---------------------------------
template
<
class
T
>
struct
inspect_config_value_access
{
static
std
::
string
type_name
()
{
return
to_string
(
type_name_or_anonymous
<
T
>
());
}
static
optional
<
T
>
get_if
(
const
config_value
*
x
)
{
config_value_reader
reader
{
x
};
auto
tmp
=
T
{};
if
(
detail
::
load_value
(
reader
,
tmp
))
return
optional
<
T
>
{
std
::
move
(
tmp
)};
return
none
;
}
static
bool
is
(
const
config_value
&
x
)
{
return
get_if
(
&
x
)
!=
none
;
}
static
T
get
(
const
config_value
&
x
)
{
auto
result
=
get_if
(
&
x
);
if
(
!
result
)
CAF_RAISE_ERROR
(
"invalid type found"
);
return
std
::
move
(
*
result
);
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
,
Nested
)
{
// TODO: we could try to read a config_value here and then deserialize the
// value from that.
ps
.
code
=
pec
::
invalid_argument
;
}
static
config_value
convert
(
const
T
&
x
)
{
config_value
result
;
config_value_writer
writer
{
&
result
};
if
(
!
detail
::
save_value
(
writer
,
x
))
CAF_RAISE_ERROR
(
"unable to convert type to a config_value"
);
return
result
;
}
};
}
// namespace detail
// -- SumType access of dictionary values --------------------------------------
template
<
>
struct
sum_type_access
<
config_value
>
{
using
types
=
typename
config_value
::
types
;
using
type0
=
typename
detail
::
tl_head
<
types
>::
type
;
static
constexpr
bool
specialized
=
true
;
template
<
class
U
,
int
Pos
>
static
bool
is
(
const
config_value
&
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
return
x
.
get_data
().
is
(
pos
(
token
));
}
template
<
class
U
>
static
bool
is
(
const
config_value
&
x
,
sum_type_token
<
U
,
-
1
>
)
{
return
detail
::
config_value_access_t
<
U
>::
is
(
x
);
}
template
<
class
U
,
int
Pos
>
static
U
&
get
(
config_value
&
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
return
x
.
get_data
().
get
(
pos
(
token
));
}
template
<
class
U
>
static
U
get
(
config_value
&
x
,
sum_type_token
<
U
,
-
1
>
)
{
return
detail
::
config_value_access_t
<
U
>::
get
(
x
);
}
template
<
class
U
,
int
Pos
>
static
const
U
&
get
(
const
config_value
&
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
return
x
.
get_data
().
get
(
pos
(
token
));
}
template
<
class
U
>
static
U
get
(
const
config_value
&
x
,
sum_type_token
<
U
,
-
1
>
)
{
return
detail
::
config_value_access_t
<
U
>::
get
(
x
);
}
template
<
class
U
,
int
Pos
>
static
U
*
get_if
(
config_value
*
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
return
is
(
*
x
,
token
)
?
&
get
(
*
x
,
token
)
:
nullptr
;
}
template
<
class
U
>
static
optional
<
U
>
get_if
(
config_value
*
x
,
sum_type_token
<
U
,
-
1
>
)
{
return
detail
::
config_value_access_t
<
U
>::
get_if
(
x
);
}
template
<
class
U
,
int
Pos
>
static
const
U
*
get_if
(
const
config_value
*
x
,
sum_type_token
<
U
,
Pos
>
token
)
{
return
is
(
*
x
,
token
)
?
&
get
(
*
x
,
token
)
:
nullptr
;
}
template
<
class
U
>
static
optional
<
U
>
get_if
(
const
config_value
*
x
,
sum_type_token
<
U
,
-
1
>
)
{
return
detail
::
config_value_access_t
<
U
>::
get_if
(
x
);
}
template
<
class
Result
,
class
Visitor
,
class
...
Ts
>
static
Result
apply
(
config_value
&
x
,
Visitor
&&
visitor
,
Ts
&&
...
xs
)
{
return
x
.
get_data
().
template
apply
<
Result
>(
std
::
forward
<
Visitor
>
(
visitor
),
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
Result
,
class
Visitor
,
class
...
Ts
>
static
Result
apply
(
const
config_value
&
x
,
Visitor
&&
visitor
,
Ts
&&
...
xs
)
{
return
x
.
get_data
().
template
apply
<
Result
>(
std
::
forward
<
Visitor
>
(
visitor
),
std
::
forward
<
Ts
>
(
xs
)...);
}
};
/// @relates config_value
/// @relates config_value
CAF_CORE_EXPORT
bool
operator
<
(
const
config_value
&
x
,
const
config_value
&
y
);
CAF_CORE_EXPORT
bool
operator
<
(
const
config_value
&
x
,
const
config_value
&
y
);
...
@@ -855,15 +936,16 @@ template <>
...
@@ -855,15 +936,16 @@ template <>
struct
variant_inspector_traits
<
config_value
>
{
struct
variant_inspector_traits
<
config_value
>
{
using
value_type
=
config_value
;
using
value_type
=
config_value
;
static
constexpr
type_id_t
allowed_types
[]
static
constexpr
type_id_t
allowed_types
[]
=
{
=
{
type_id_v
<
config_value
::
integer
>
,
type_id_v
<
config_value
::
integer
>
,
type_id_v
<
config_value
::
boolean
>
,
type_id_v
<
config_value
::
boolean
>
,
type_id_v
<
config_value
::
real
>
,
type_id_v
<
config_value
::
real
>
,
type_id_v
<
config_value
::
timespan
>
,
type_id_v
<
config_value
::
timespan
>
,
type_id_v
<
uri
>
,
type_id_v
<
uri
>
,
type_id_v
<
config_value
::
string
>
,
type_id_v
<
config_value
::
string
>
,
type_id_v
<
config_value
::
list
>
,
type_id_v
<
config_value
::
list
>
,
type_id_v
<
config_value
::
dictionary
>
};
type_id_v
<
config_value
::
dictionary
>
,
};
static
auto
type_index
(
const
config_value
&
x
)
{
static
auto
type_index
(
const
config_value
&
x
)
{
return
x
.
get_data
().
index
();
return
x
.
get_data
().
index
();
...
...
libcaf_core/caf/config_value_adaptor.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 <array>
#include <tuple>
#include <type_traits>
#include "caf/config_value_adaptor_field.hpp"
#include "caf/detail/config_value_adaptor_field_impl.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/optional.hpp"
#include "caf/span.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
/// Interfaces between a user-defined type and CAF config values by going
/// through intermediate values.
template
<
class
...
Ts
>
class
config_value_adaptor
{
public:
using
value_type
=
std
::
tuple
<
Ts
...
>
;
using
indices
=
typename
detail
::
il_indices
<
value_type
>::
type
;
using
fields_tuple
=
typename
detail
::
select_adaptor_fields
<
value_type
,
indices
>::
type
;
using
array_type
=
std
::
array
<
config_value_field
<
value_type
>*
,
sizeof
...(
Ts
)
>
;
template
<
class
U
,
class
=
detail
::
enable_if_t
<
!
std
::
is_same
<
detail
::
decay_t
<
U
>,
config_value_adaptor
>::
value
>
,
class
...
Us
>
config_value_adaptor
(
U
&&
x
,
Us
&&
...
xs
)
:
fields_
(
make_fields
(
indices
{},
std
::
forward
<
U
>
(
x
),
std
::
forward
<
Us
>
(
xs
)...))
{
init
(
indices
{});
}
config_value_adaptor
(
config_value_adaptor
&&
)
=
default
;
span
<
typename
array_type
::
value_type
>
fields
()
{
return
make_span
(
ptr_fields_
);
}
private:
// TODO: This is a workaround for GCC <= 5 because initializing fields_
// directly from (xs...) fails. Remove when moving on to newer
// compilers.
template
<
long
...
Pos
,
class
...
Us
>
fields_tuple
make_fields
(
detail
::
int_list
<
Pos
...
>
,
Us
&&
...
xs
)
{
return
std
::
make_tuple
(
detail
::
config_value_adaptor_field_impl
<
value_type
,
Pos
>
(
std
::
forward
<
Us
>
(
xs
))...);
}
template
<
long
...
Pos
>
void
init
(
detail
::
int_list
<
Pos
...
>
)
{
ptr_fields_
=
array_type
{{
&
std
::
get
<
Pos
>
(
fields_
)...}};
}
fields_tuple
fields_
;
array_type
ptr_fields_
;
};
template
<
class
...
Ts
>
config_value_adaptor
<
typename
Ts
::
value_type
...
>
make_config_value_adaptor
(
Ts
...
fields
)
{
return
{
std
::
move
(
fields
)...};
}
}
// namespace caf
libcaf_core/caf/config_value_adaptor_access.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/config_value_object_access.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
/// Enables user-defined types in config files and on the CLI by converting
/// them to and from tuples. Wraps a `config_value_object_access` in order to
/// allow CAF to interact with the underlying tuple.
///
/// ~~
/// struct trait {
/// using value_type = ...;
///
/// using tuple_type = ...;
///
/// static config_value_adaptor<...> adaptor_ref();
///
/// static span<config_value_field<object_type>*> fields();
///
/// static void convert(const value_type& src, tuple_type& dst);
///
/// static void convert(const tuple_type& src, value_type& dst);
/// };
/// ~~
template
<
class
Trait
>
struct
config_value_adaptor_access
{
struct
object_trait
{
using
object_type
=
typename
Trait
::
tuple_type
;
static
std
::
string
type_name
()
{
return
Trait
::
type_name
();
}
static
caf
::
span
<
config_value_field
<
object_type
>*>
fields
()
{
return
Trait
::
adaptor_ref
().
fields
();
}
};
using
tuple_access
=
config_value_object_access
<
object_trait
>
;
using
value_type
=
typename
Trait
::
value_type
;
using
tuple_type
=
typename
Trait
::
tuple_type
;
static
std
::
string
type_name
()
{
return
Trait
::
type_name
();
}
static
bool
is
(
const
config_value
&
x
)
{
return
tuple_access
::
is
(
x
);
}
static
optional
<
value_type
>
get_if
(
const
config_value
*
x
)
{
if
(
auto
tmp
=
tuple_access
::
get_if
(
x
))
{
value_type
result
;
convert
(
*
tmp
,
result
);
return
result
;
}
return
none
;
}
static
value_type
get
(
const
config_value
&
x
)
{
auto
tmp
=
tuple_access
::
get
(
x
);
value_type
result
;
convert
(
tmp
,
result
);
return
result
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
value_type
&
x
,
Nested
nested
)
{
tuple_type
tmp
;
tuple_access
::
parse_cli
(
ps
,
tmp
,
nested
);
if
(
ps
.
code
<=
pec
::
trailing_character
)
convert
(
tmp
,
x
);
}
static
void
convert
(
const
value_type
&
src
,
tuple_type
&
dst
)
{
Trait
::
convert
(
src
,
dst
);
}
static
void
convert
(
const
tuple_type
&
src
,
value_type
&
dst
)
{
Trait
::
convert
(
src
,
dst
);
}
static
config_value
::
dictionary
convert
(
const
value_type
&
x
)
{
tuple_type
tmp
;
convert
(
x
,
tmp
);
return
tuple_access
::
convert
(
tmp
);
}
};
}
// namespace caf
libcaf_core/caf/config_value_adaptor_field.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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/optional.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
/// Describes a field of type T of an adaptor.
template
<
class
T
>
struct
config_value_adaptor_field
{
/// Type of the field.
using
value_type
=
T
;
/// Predicate function for verifying user input.
using
predicate_function
=
bool
(
*
)(
const
value_type
&
);
/// Name of the field in configuration files and on the CLI.
string_view
name
;
/// If set, makes the field optional in configuration files and on the CLI by
/// assigning the default whenever the user provides no value.
optional
<
value_type
>
default_value
;
/// If set, makes the field only accept values that pass this predicate.
predicate_function
predicate
;
};
/// Convenience function for creating a `config_value_adaptor_field`.
/// @param name name of the field in configuration files and on the CLI.
/// @param default_value if set, provides a fallback value if the user does not
/// provide a value.
/// @param predicate if set, restricts what values the field accepts.
/// @returns a `config_value_adaptor_field` object, constructed from given
/// arguments.
/// @relates config_value_adaptor_field
template
<
class
T
>
config_value_adaptor_field
<
T
>
make_config_value_adaptor_field
(
string_view
name
,
optional
<
T
>
default_value
=
none
,
bool
(
*
predicate
)(
const
T
&
)
=
nullptr
)
{
return
{
name
,
std
::
move
(
default_value
),
predicate
};
}
}
// namespace caf
libcaf_core/caf/config_value_field.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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/fwd.hpp"
#include "caf/parser_state.hpp"
namespace
caf
{
/// Describes a field of `Object`.
template
<
class
Object
>
class
config_value_field
{
public:
using
object_type
=
Object
;
virtual
~
config_value_field
()
=
default
;
// -- observers --------------------------------------------------------------
/// Returns whether this field has a default value.
virtual
bool
has_default
()
const
noexcept
=
0
;
/// Returns the name of this field.
virtual
string_view
name
()
const
noexcept
=
0
;
/// Returns the value of this field in `object` as config value.
virtual
config_value
get
(
const
Object
&
object
)
const
=
0
;
/// Returns whether calling `set` with `x` would succeed.
virtual
bool
valid_input
(
const
config_value
&
x
)
const
=
0
;
// -- modifiers --------------------------------------------------------------
/// Tries to set this field in `object` to `x`.
/// @returns `true` on success, `false` otherwise.
virtual
bool
set
(
Object
&
object
,
const
config_value
&
x
)
const
=
0
;
/// Restores the default value for this field in `object`.
/// @pre `has_default()`
virtual
void
set_default
(
Object
&
object
)
const
=
0
;
/// Parses the content for this field in `object` from `ps`.
virtual
void
parse_cli
(
string_parser_state
&
ps
,
Object
&
object
,
bool
is_nested
)
const
=
0
;
};
}
// namespace caf
libcaf_core/caf/config_value_object_access.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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/config_value.hpp"
#include "caf/config_value_field.hpp"
namespace
caf
{
/// Enables user-defined types in config files and on the CLI by converting
/// them to and from `config_value::dictionary`.
///
/// ~~
/// struct trait {
/// using object_type = ...;
///
/// static string_value type_name();
///
/// static span<config_value_field<object_type>*> fields();
/// };
/// ~~
template
<
class
Trait
>
struct
config_value_object_access
{
using
object_type
=
typename
Trait
::
object_type
;
static
std
::
string
type_name
()
{
return
Trait
::
type_name
();
}
static
bool
extract
(
const
config_value
*
src
,
object_type
*
dst
)
{
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
src
);
if
(
!
dict
)
return
false
;
for
(
auto
field
:
Trait
::
fields
())
{
if
(
auto
value
=
caf
::
get_if
(
dict
,
field
->
name
()))
{
if
(
dst
)
{
if
(
!
field
->
set
(
*
dst
,
*
value
))
return
false
;
}
else
{
if
(
!
field
->
valid_input
(
*
value
))
return
false
;
}
}
else
{
if
(
!
field
->
has_default
())
return
false
;
if
(
dst
)
field
->
set_default
(
*
dst
);
}
}
return
true
;
}
static
bool
is
(
const
config_value
&
x
)
{
return
extract
(
&
x
,
nullptr
);
}
static
optional
<
object_type
>
get_if
(
const
config_value
*
x
)
{
object_type
result
;
if
(
extract
(
x
,
&
result
))
return
result
;
return
none
;
}
static
object_type
get
(
const
config_value
&
x
)
{
auto
result
=
get_if
(
&
x
);
if
(
!
result
)
CAF_RAISE_ERROR
(
"config_value does not contain requested object"
);
return
std
::
move
(
*
result
);
}
static
config_value
::
dictionary
convert
(
const
object_type
&
x
)
{
config_value
::
dictionary
result
;
for
(
auto
field
:
Trait
::
fields
())
result
.
emplace
(
field
->
name
(),
field
->
get
(
x
));
return
result
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
,
Nested
)
{
using
field_type
=
config_value_field
<
object_type
>
;
std
::
vector
<
field_type
*>
parsed_fields
;
auto
got
=
[
&
](
field_type
*
f
)
{
auto
e
=
parsed_fields
.
end
();
return
std
::
find
(
parsed_fields
.
begin
(),
e
,
f
)
!=
e
;
};
auto
push
=
[
&
](
field_type
*
f
)
{
if
(
got
(
f
))
return
false
;
parsed_fields
.
emplace_back
(
f
);
return
true
;
};
auto
finalize
=
[
&
]
{
for
(
auto
field
:
Trait
::
fields
())
{
if
(
!
got
(
field
))
{
if
(
field
->
has_default
())
{
field
->
set_default
(
x
);
}
else
{
ps
.
code
=
pec
::
missing_field
;
return
;
}
}
}
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
};
auto
fs
=
Trait
::
fields
();
if
(
!
ps
.
consume
(
'{'
))
{
ps
.
code
=
pec
::
unexpected_character
;
return
;
}
using
string_access
=
select_config_value_access_t
<
std
::
string
>
;
config_value
::
dictionary
result
;
do
{
if
(
ps
.
consume
(
'}'
))
{
finalize
();
return
;
}
std
::
string
field_name
;
string_access
::
parse_cli
(
ps
,
field_name
,
nested_cli_parsing
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
if
(
!
ps
.
consume
(
'='
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
auto
predicate
=
[
&
](
config_value_field
<
object_type
>*
x
)
{
return
x
->
name
()
==
field_name
;
};
auto
f
=
std
::
find_if
(
fs
.
begin
(),
fs
.
end
(),
predicate
);
if
(
f
==
fs
.
end
())
{
ps
.
code
=
pec
::
invalid_field_name
;
return
;
}
auto
fptr
=
*
f
;
if
(
!
push
(
fptr
))
{
ps
.
code
=
pec
::
repeated_field_name
;
return
;
}
fptr
->
parse_cli
(
ps
,
x
,
true
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
if
(
ps
.
at_end
())
{
ps
.
code
=
pec
::
unexpected_eof
;
return
;
}
result
[
fptr
->
name
()]
=
fptr
->
get
(
x
);
}
while
(
ps
.
consume
(
','
));
if
(
!
ps
.
consume
(
'}'
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
finalize
();
}
};
}
// namespace caf
libcaf_core/caf/config_value_reader.hpp
0 → 100644
View file @
c6e7fdb6
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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
config_value_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 --------------------
config_value_reader
(
const
config_value
*
input
,
actor_system
&
sys
)
:
super
(
sys
)
{
st_
.
push
(
input
);
has_human_readable_format_
=
true
;
}
config_value_reader
(
const
config_value
*
input
,
execution_unit
*
ctx
)
:
super
(
ctx
)
{
st_
.
push
(
input
);
has_human_readable_format_
=
true
;
}
explicit
config_value_reader
(
const
config_value
*
input
)
:
config_value_reader
(
input
,
nullptr
)
{
// nop
}
~
config_value_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_
;
};
}
// namespace caf
libcaf_core/caf/
settings
_writer.hpp
→
libcaf_core/caf/
config_value
_writer.hpp
View file @
c6e7fdb6
...
@@ -18,17 +18,16 @@
...
@@ -18,17 +18,16 @@
#pragma once
#pragma once
#include "caf/
config_value
.hpp"
#include "caf/
fwd
.hpp"
#include "caf/serializer.hpp"
#include "caf/serializer.hpp"
#include "caf/settings.hpp"
#include <stack>
#include <stack>
#include <vector>
#include <vector>
namespace
caf
{
namespace
caf
{
///
Writes objects into @ref settings
.
///
Serializes an objects into a @ref config_value
.
class
settings
_writer
final
:
public
serializer
{
class
config_value
_writer
final
:
public
serializer
{
public:
public:
// -- member types------------------------------------------------------------
// -- member types------------------------------------------------------------
...
@@ -42,30 +41,29 @@ public:
...
@@ -42,30 +41,29 @@ public:
struct
absent_field
{};
struct
absent_field
{};
using
value_type
using
value_type
=
variant
<
config_value
*
,
settings
*
,
absent_field
,
=
variant
<
settings
*
,
absent_field
,
present_field
,
config_value
::
list
*>
;
present_field
,
std
::
vector
<
config_value
>
*>
;
using
stack_type
=
std
::
stack
<
value_type
,
std
::
vector
<
value_type
>>
;
using
stack_type
=
std
::
stack
<
value_type
,
std
::
vector
<
value_type
>>
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
settings_writer
(
settings
*
destination
,
actor_system
&
sys
)
config_value_writer
(
config_value
*
dst
,
actor_system
&
sys
)
:
super
(
sys
)
{
:
super
(
sys
),
root_
(
destination
)
{
st_
.
push
(
dst
);
st_
.
push
(
destination
);
has_human_readable_format_
=
true
;
has_human_readable_format_
=
true
;
}
}
settings_writer
(
settings
*
destination
,
execution_unit
*
ctx
)
config_value_writer
(
config_value
*
dst
,
execution_unit
*
ctx
)
:
super
(
ctx
)
{
:
super
(
ctx
),
root_
(
destination
)
{
st_
.
push
(
dst
);
has_human_readable_format_
=
true
;
has_human_readable_format_
=
true
;
}
}
explicit
settings_writer
(
settings
*
destination
)
explicit
config_value_writer
(
config_value
*
destination
)
:
settings
_writer
(
destination
,
nullptr
)
{
:
config_value
_writer
(
destination
,
nullptr
)
{
// nop
// nop
}
}
~
settings
_writer
()
override
;
~
config_value
_writer
()
override
;
// -- interface functions ----------------------------------------------------
// -- interface functions ----------------------------------------------------
...
@@ -140,7 +138,6 @@ private:
...
@@ -140,7 +138,6 @@ private:
stack_type
st_
;
stack_type
st_
;
string_view
type_hint_
;
string_view
type_hint_
;
settings
*
root_
;
};
};
}
// namespace caf
}
// namespace caf
libcaf_core/caf/detail/config_value_adaptor_field_impl.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 <cstddef>
#include <tuple>
#include "caf/config_value.hpp"
#include "caf/config_value_adaptor_field.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/string_view.hpp"
namespace
caf
::
detail
{
template
<
class
T
,
size_t
Pos
>
class
config_value_adaptor_field_impl
:
public
config_value_field_base
<
T
,
typename
std
::
tuple_element
<
Pos
,
T
>::
type
>
{
public:
using
object_type
=
T
;
using
value_type
=
typename
std
::
tuple_element
<
Pos
,
T
>::
type
;
using
field_type
=
config_value_adaptor_field
<
value_type
>
;
using
predicate_type
=
bool
(
*
)(
const
value_type
&
);
using
super
=
config_value_field_base
<
object_type
,
value_type
>
;
explicit
config_value_adaptor_field_impl
(
field_type
x
)
:
super
(
x
.
name
,
std
::
move
(
x
.
default_value
),
x
.
predicate
)
{
// nop
}
config_value_adaptor_field_impl
(
config_value_adaptor_field_impl
&&
)
=
default
;
const
value_type
&
get_value
(
const
object_type
&
x
)
const
override
{
return
std
::
get
<
Pos
>
(
x
);
}
void
set_value
(
object_type
&
x
,
value_type
y
)
const
override
{
std
::
get
<
Pos
>
(
x
)
=
std
::
move
(
y
);
}
};
template
<
class
T
,
class
Ps
>
struct
select_adaptor_fields
;
template
<
class
T
,
long
...
Pos
>
struct
select_adaptor_fields
<
T
,
detail
::
int_list
<
Pos
...
>>
{
using
type
=
std
::
tuple
<
config_value_adaptor_field_impl
<
T
,
Pos
>
...
>
;
};
}
// namespace caf::detail
libcaf_core/caf/detail/config_value_field_base.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/optional.hpp"
namespace
caf
::
detail
{
template
<
class
Object
,
class
Value
>
class
config_value_field_base
:
public
config_value_field
<
Object
>
{
public:
using
super
=
config_value_field
<
Object
>
;
using
object_type
=
typename
super
::
object_type
;
using
value_type
=
Value
;
using
predicate_type
=
bool
(
*
)(
const
value_type
&
);
config_value_field_base
(
string_view
name
,
optional
<
value_type
>
default_value
,
predicate_type
predicate
)
:
name_
(
name
),
default_value_
(
std
::
move
(
default_value
)),
predicate_
(
predicate
)
{
// nop
}
config_value_field_base
(
config_value_field_base
&&
)
=
default
;
bool
has_default
()
const
noexcept
override
{
return
static_cast
<
bool
>
(
default_value_
);
}
string_view
name
()
const
noexcept
override
{
return
name_
;
}
config_value
get
(
const
object_type
&
object
)
const
override
{
using
access
=
caf
::
select_config_value_access_t
<
value_type
>
;
return
config_value
{
access
::
convert
(
get_value
(
object
))};
}
bool
valid_input
(
const
config_value
&
x
)
const
override
{
if
(
!
predicate_
)
return
holds_alternative
<
value_type
>
(
x
);
if
(
auto
value
=
get_if
<
value_type
>
(
&
x
))
return
predicate_
(
*
value
);
return
false
;
}
bool
set
(
object_type
&
x
,
const
config_value
&
y
)
const
override
{
if
(
auto
value
=
get_if
<
value_type
>
(
&
y
))
{
if
(
predicate_
&&
!
predicate_
(
*
value
))
return
false
;
set_value
(
x
,
move_if_optional
(
value
));
return
true
;
}
return
false
;
}
void
set_default
(
object_type
&
x
)
const
override
{
set_value
(
x
,
*
default_value_
);
}
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
,
bool
nested
)
const
override
{
using
access
=
caf
::
select_config_value_access_t
<
value_type
>
;
value_type
tmp
;
if
(
nested
)
access
::
parse_cli
(
ps
,
tmp
,
nested_cli_parsing
);
else
access
::
parse_cli
(
ps
,
tmp
,
top_level_cli_parsing
);
if
(
ps
.
code
<=
pec
::
trailing_character
)
{
if
(
predicate_
&&
!
predicate_
(
tmp
))
ps
.
code
=
pec
::
invalid_argument
;
else
set_value
(
x
,
std
::
move
(
tmp
));
}
}
virtual
const
value_type
&
get_value
(
const
object_type
&
object
)
const
=
0
;
virtual
void
set_value
(
object_type
&
object
,
value_type
value
)
const
=
0
;
protected:
string_view
name_
;
optional
<
value_type
>
default_value_
;
predicate_type
predicate_
;
};
}
// namespace caf::detail
libcaf_core/caf/detail/config_value_field_impl.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 <string>
#include <utility>
#include "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/optional.hpp"
#include "caf/string_view.hpp"
namespace
caf
::
detail
{
template
<
class
MemberObjectPointer
>
class
config_value_field_impl
;
// A config value with direct access to a field via member object pointer.
template
<
class
Value
,
class
Object
>
class
config_value_field_impl
<
Value
Object
::*>
:
public
config_value_field_base
<
Object
,
Value
>
{
public:
using
super
=
config_value_field_base
<
Object
,
Value
>
;
using
member_pointer
=
Value
Object
::*
;
using
object_type
=
Object
;
using
value_type
=
Value
;
using
predicate_type
=
bool
(
*
)(
const
value_type
&
);
constexpr
config_value_field_impl
(
string_view
name
,
member_pointer
ptr
,
optional
<
value_type
>
default_value
=
none
,
predicate_type
predicate
=
nullptr
)
:
super
(
name
,
std
::
move
(
default_value
),
predicate
),
ptr_
(
ptr
)
{
// nop
}
constexpr
config_value_field_impl
(
config_value_field_impl
&&
)
=
default
;
const
value_type
&
get_value
(
const
object_type
&
x
)
const
override
{
return
x
.
*
ptr_
;
}
void
set_value
(
object_type
&
x
,
value_type
y
)
const
override
{
x
.
*
ptr_
=
std
::
move
(
y
);
}
private:
member_pointer
ptr_
;
};
template
<
class
Get
>
struct
config_value_field_trait
{
using
trait
=
get_callable_trait_t
<
Get
>
;
static_assert
(
trait
::
num_args
==
1
,
"Get must take exactly one argument (the object)"
);
using
get_argument_type
=
tl_head_t
<
typename
trait
::
arg_types
>
;
using
object_type
=
decay_t
<
get_argument_type
>
;
using
get_result_type
=
typename
trait
::
result_type
;
using
value_type
=
decay_t
<
get_result_type
>
;
};
// A config value with access to a field via getter and setter.
template
<
class
Get
,
class
Set
>
class
config_value_field_impl
<
std
::
pair
<
Get
,
Set
>>
:
public
config_value_field_base
<
typename
config_value_field_trait
<
Get
>::
object_type
,
typename
config_value_field_trait
<
Get
>::
value_type
>
{
public:
using
trait
=
config_value_field_trait
<
Get
>
;
using
object_type
=
typename
trait
::
object_type
;
using
get_result_type
=
typename
trait
::
get_result_type
;
using
value_type
=
typename
trait
::
value_type
;
using
predicate_type
=
bool
(
*
)(
const
value_type
&
);
using
super
=
config_value_field_base
<
object_type
,
value_type
>
;
constexpr
config_value_field_impl
(
string_view
name
,
Get
getter
,
Set
setter
,
optional
<
value_type
>
default_value
=
none
,
predicate_type
predicate
=
nullptr
)
:
super
(
name
,
std
::
move
(
default_value
),
predicate
),
get_
(
std
::
move
(
getter
)),
set_
(
std
::
move
(
setter
))
{
// nop
}
constexpr
config_value_field_impl
(
config_value_field_impl
&&
)
=
default
;
const
value_type
&
get_value
(
const
object_type
&
x
)
const
override
{
bool_token
<
std
::
is_lvalue_reference
<
get_result_type
>::
value
>
token
;
return
get_value_impl
(
x
,
token
);
}
void
set_value
(
object_type
&
x
,
value_type
y
)
const
override
{
set_
(
x
,
std
::
move
(
y
));
}
private:
template
<
class
O
>
const
value_type
&
get_value_impl
(
const
O
&
x
,
std
::
true_type
)
const
{
return
get_
(
x
);
}
template
<
class
O
>
const
value_type
&
get_value_impl
(
const
O
&
x
,
std
::
false_type
)
const
{
dummy_
=
get_
(
x
);
return
dummy_
;
}
Get
get_
;
Set
set_
;
mutable
value_type
dummy_
;
};
}
// namespace caf::detail
libcaf_core/caf/detail/parse.hpp
View file @
c6e7fdb6
...
@@ -97,6 +97,8 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, float& x);
...
@@ -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
,
double
&
x
);
CAF_CORE_EXPORT
void
parse
(
string_parser_state
&
ps
,
long
double
&
x
);
// -- CAF types ----------------------------------------------------------------
// -- CAF types ----------------------------------------------------------------
CAF_CORE_EXPORT
void
parse
(
string_parser_state
&
ps
,
ipv4_address
&
x
);
CAF_CORE_EXPORT
void
parse
(
string_parser_state
&
ps
,
ipv4_address
&
x
);
...
...
libcaf_core/caf/make_config_option.hpp
View file @
c6e7fdb6
...
@@ -48,7 +48,7 @@ void store_impl(void* ptr, const config_value& x) {
...
@@ -48,7 +48,7 @@ void store_impl(void* ptr, const config_value& x) {
template
<
class
T
>
template
<
class
T
>
config_value
get_impl
(
const
void
*
ptr
)
{
config_value
get_impl
(
const
void
*
ptr
)
{
using
trait
=
select_
config_value_access_t
<
T
>
;
using
trait
=
detail
::
config_value_access_t
<
T
>
;
return
config_value
{
trait
::
convert
(
*
reinterpret_cast
<
const
T
*>
(
ptr
))};
return
config_value
{
trait
::
convert
(
*
reinterpret_cast
<
const
T
*>
(
ptr
))};
}
}
...
@@ -60,7 +60,7 @@ expected<config_value> parse_impl(T* ptr, string_view str) {
...
@@ -60,7 +60,7 @@ expected<config_value> parse_impl(T* ptr, string_view str) {
}
}
if
constexpr
(
detail
::
has_clear_member
<
T
>::
value
)
if
constexpr
(
detail
::
has_clear_member
<
T
>::
value
)
ptr
->
clear
();
ptr
->
clear
();
using
trait
=
select_
config_value_access_t
<
T
>
;
using
trait
=
detail
::
config_value_access_t
<
T
>
;
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
trait
::
parse_cli
(
ps
,
*
ptr
,
top_level_cli_parsing
);
trait
::
parse_cli
(
ps
,
*
ptr
,
top_level_cli_parsing
);
if
(
ps
.
code
!=
pec
::
success
)
if
(
ps
.
code
!=
pec
::
success
)
...
@@ -78,7 +78,7 @@ expected<config_value> parse_impl_delegate(void* ptr, string_view str) {
...
@@ -78,7 +78,7 @@ expected<config_value> parse_impl_delegate(void* ptr, string_view str) {
template
<
class
T
>
template
<
class
T
>
config_option
::
meta_state
*
option_meta_state_instance
()
{
config_option
::
meta_state
*
option_meta_state_instance
()
{
using
trait
=
select_
config_value_access_t
<
T
>
;
using
trait
=
detail
::
config_value_access_t
<
T
>
;
static
config_option
::
meta_state
obj
{
check_impl
<
T
>
,
store_impl
<
T
>
,
static
config_option
::
meta_state
obj
{
check_impl
<
T
>
,
store_impl
<
T
>
,
get_impl
<
T
>
,
parse_impl_delegate
<
T
>
,
get_impl
<
T
>
,
parse_impl_delegate
<
T
>
,
trait
::
type_name
()};
trait
::
type_name
()};
...
...
libcaf_core/caf/make_config_value_field.hpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 <array>
#include <tuple>
#include <type_traits>
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_impl.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
{
/// Creates a field with direct access to a member in `T` via member-to-object
/// pointer.
template
<
class
T
,
class
U
,
class
...
Args
>
detail
::
config_value_field_impl
<
U
T
::*>
make_config_value_field
(
string_view
name
,
U
T
::*
ptr
,
Args
&&
...
xs
)
{
return
{
name
,
ptr
,
std
::
forward
<
Args
>
(
xs
)...};
}
/// Creates a field with access to a member in `T` via `getter` and `setter`.
template
<
class
Getter
,
class
Setter
,
class
E
=
detail
::
enable_if_t
<!
std
::
is_member_pointer
<
Getter
>
::
value
>
,
class
...
Args
>
detail
::
config_value_field_impl
<
std
::
pair
<
Getter
,
Setter
>>
make_config_value_field
(
string_view
name
,
Getter
getter
,
Setter
setter
,
Args
&&
...
xs
)
{
return
{
name
,
std
::
move
(
getter
),
std
::
move
(
setter
),
std
::
forward
<
Args
>
(
xs
)...};
}
template
<
class
T
,
class
...
Ts
>
class
config_value_field_storage
{
public:
using
tuple_type
=
std
::
tuple
<
T
,
Ts
...
>
;
using
object_type
=
typename
T
::
object_type
;
using
indices
=
typename
detail
::
il_indices
<
tuple_type
>::
type
;
using
array_type
=
std
::
array
<
config_value_field
<
object_type
>*
,
sizeof
...(
Ts
)
+
1
>
;
template
<
class
...
Us
>
config_value_field_storage
(
T
x
,
Us
&&
...
xs
)
:
fields_
(
std
::
move
(
x
),
std
::
forward
<
Us
>
(
xs
)...)
{
init
(
detail
::
get_indices
(
fields_
));
}
config_value_field_storage
(
config_value_field_storage
&&
)
=
default
;
span
<
config_value_field
<
object_type
>*>
fields
()
{
return
make_span
(
ptr_fields_
);
}
private:
template
<
long
...
Pos
>
void
init
(
detail
::
int_list
<
Pos
...
>
)
{
ptr_fields_
=
array_type
{{
&
std
::
get
<
Pos
>
(
fields_
)...}};
}
std
::
tuple
<
T
,
Ts
...
>
fields_
;
array_type
ptr_fields_
;
};
template
<
class
...
Ts
>
config_value_field_storage
<
Ts
...
>
make_config_value_field_storage
(
Ts
...
fields
)
{
return
{
std
::
move
(
fields
)...};
}
}
// namespace caf
libcaf_core/caf/sec.hpp
View file @
c6e7fdb6
...
@@ -145,19 +145,21 @@ enum class sec : uint8_t {
...
@@ -145,19 +145,21 @@ enum class sec : uint8_t {
no_tracing_context
,
no_tracing_context
,
/// No request produced a valid result.
/// No request produced a valid result.
all_requests_failed
,
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.
/// the content of a field.
field_invariant_check_failed
=
55
,
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
,
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
,
invalid_field_type
,
/// Serialization failed because a type was flagged as unsafe message type.
/// Serialization failed because a type was flagged as unsafe message type.
unsafe_type
,
unsafe_type
,
/// Serialization failed
,
because a save callback returned `false`.
/// Serialization failed because a save callback returned `false`.
save_callback_failed
,
save_callback_failed
,
/// Deserialization failed, because a load callback returned `false`.
/// Deserialization failed because a load callback returned `false`.
load_callback_failed
,
load_callback_failed
=
60
,
/// Converting between two types failed.
conversion_failed
,
};
};
/// @relates sec
/// @relates sec
...
...
libcaf_core/caf/settings.hpp
View file @
c6e7fdb6
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
#include "caf/optional.hpp"
#include "caf/optional.hpp"
#include "caf/raise_error.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_view.hpp"
#include "caf/string_view.hpp"
#include "caf/sum_type.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -50,7 +51,7 @@ auto get_if(const settings* xs, string_view name) {
...
@@ -50,7 +51,7 @@ auto get_if(const settings* xs, string_view name) {
/// @relates config_value
/// @relates config_value
template
<
class
T
>
template
<
class
T
>
bool
holds_alternative
(
const
settings
&
xs
,
string_view
name
)
{
bool
holds_alternative
(
const
settings
&
xs
,
string_view
name
)
{
using
access
=
select_
config_value_access_t
<
T
>
;
using
access
=
detail
::
config_value_access_t
<
T
>
;
if
(
auto
value
=
get_if
(
&
xs
,
name
))
if
(
auto
value
=
get_if
(
&
xs
,
name
))
return
access
::
is
(
*
value
);
return
access
::
is
(
*
value
);
return
false
;
return
false
;
...
...
libcaf_core/src/config_value_reader.cpp
0 → 100644
View file @
c6e7fdb6
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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/config_value_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
::
config_value_reader
::
absent_field
,
"absent field"
);
PRETTY_NAME
(
caf
::
config_value_reader
::
sequence
,
"sequence"
);
PRETTY_NAME
(
caf
::
config_value_reader
::
associative_array
,
"associative array"
);
template
<
class
T
>
constexpr
auto
pretty_name_v
=
pretty_name
<
T
>::
value
;
auto
get_pretty_name
(
const
caf
::
config_value_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
config_value_reader
::
sequence
::
at_end
()
const
noexcept
{
return
index
>=
ls
->
size
();
}
const
config_value
&
config_value_reader
::
sequence
::
current
()
{
return
(
*
ls
)[
index
];
}
bool
config_value_reader
::
associative_array
::
at_end
()
const
noexcept
{
return
pos
==
end
;
}
const
std
::
pair
<
const
std
::
string
,
config_value
>&
config_value_reader
::
associative_array
::
current
()
{
return
*
pos
;
}
// -- constructors, destructors, and assignment operators ----------------------
config_value_reader
::~
config_value_reader
()
{
// nop
}
// -- interface functions ------------------------------------------------------
bool
config_value_reader
::
fetch_next_object_type
(
type_id_t
&
type
)
{
if
(
st_
.
empty
())
{
emplace_error
(
sec
::
runtime_error
,
"tried to read multiple objects from the root object"
);
return
false
;
}
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
config_value_reader
::
begin_object
(
string_view
)
{
if
(
st_
.
empty
())
{
emplace_error
(
sec
::
runtime_error
,
"tried to read multiple objects from the root object"
);
return
false
;
}
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
config_value_reader
::
end_object
()
{
SCOPE
(
const
settings
*
);
st_
.
pop
();
return
true
;
}
bool
config_value_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
config_value_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
config_value_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
config_value_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
config_value_reader
::
end_field
()
{
CHECK_NOT_EMPTY
();
// Note: no pop() here, because the value(s) were already consumed.
return
true
;
}
bool
config_value_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
config_value_reader
::
end_tuple
()
{
return
end_sequence
();
}
bool
config_value_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
config_value_reader
::
end_key_value_pair
()
{
SCOPE
(
associative_array
);
++
top
.
pos
;
return
true
;
}
bool
config_value_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
config_value_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
config_value_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
config_value_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
(
config_value_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
<
config_value_reader
::
sequence
>
(
top
))
{
auto
&
seq
=
get
<
config_value_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
<
config_value_reader
::
key_ptr
>
(
top
))
{
auto
ptr
=
get
<
config_value_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
config_value_reader
::
value
(
bool
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
int8_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
uint8_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
int16_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
uint16_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
int32_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
uint32_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
int64_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
uint64_t
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
float
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
double
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
long
double
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
std
::
string
&
x
)
{
CHECK_NOT_EMPTY
();
return
pull
(
*
this
,
x
);
}
bool
config_value_reader
::
value
(
std
::
u16string
&
)
{
emplace_error
(
sec
::
runtime_error
,
"u16string support not implemented yet"
);
return
false
;
}
bool
config_value_reader
::
value
(
std
::
u32string
&
)
{
emplace_error
(
sec
::
runtime_error
,
"u32string support not implemented yet"
);
return
false
;
}
bool
config_value_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
config_value_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/src/
settings
_writer.cpp
→
libcaf_core/src/
config_value
_writer.cpp
View file @
c6e7fdb6
...
@@ -16,10 +16,12 @@
...
@@ -16,10 +16,12 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#include "caf/
settings
_writer.hpp"
#include "caf/
config_value
_writer.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/append_hex.hpp"
#include "caf/detail/append_hex.hpp"
#include "caf/detail/overload.hpp"
#include "caf/detail/overload.hpp"
#include "caf/settings.hpp"
#define CHECK_NOT_EMPTY() \
#define CHECK_NOT_EMPTY() \
do { \
do { \
...
@@ -58,13 +60,13 @@ namespace caf {
...
@@ -58,13 +60,13 @@ namespace caf {
// -- constructors, destructors, and assignment operators ----------------------
// -- constructors, destructors, and assignment operators ----------------------
settings_writer
::~
settings
_writer
()
{
config_value_writer
::~
config_value
_writer
()
{
// nop
// nop
}
}
// -- interface functions ------------------------------------------------------
// -- interface functions ------------------------------------------------------
bool
settings
_writer
::
inject_next_object_type
(
type_id_t
type
)
{
bool
config_value
_writer
::
inject_next_object_type
(
type_id_t
type
)
{
CHECK_NOT_EMPTY
();
CHECK_NOT_EMPTY
();
type_hint_
=
query_type_name
(
type
);
type_hint_
=
query_type_name
(
type
);
if
(
type_hint_
.
empty
())
{
if
(
type_hint_
.
empty
())
{
...
@@ -75,48 +77,47 @@ bool settings_writer::inject_next_object_type(type_id_t type) {
...
@@ -75,48 +77,47 @@ bool settings_writer::inject_next_object_type(type_id_t type) {
return
true
;
return
true
;
}
}
bool
settings_writer
::
begin_object
(
string_view
)
{
bool
config_value_writer
::
begin_object
(
string_view
)
{
if
(
st_
.
empty
())
{
CHECK_NOT_EMPTY
();
if
(
root_
==
nullptr
)
{
auto
f
=
detail
::
make_overload
(
[
this
](
config_value
*
x
)
{
// Morph the root element into a dictionary.
auto
&
dict
=
x
->
as_dictionary
();
dict
.
clear
();
st_
.
top
()
=
&
dict
;
return
true
;
},
[
this
](
settings
*
)
{
emplace_error
(
sec
::
runtime_error
,
emplace_error
(
sec
::
runtime_error
,
"
tried to serialize multiple objects into the root
object"
);
"
begin_object called inside another
object"
);
return
false
;
return
false
;
}
},
st_
.
push
(
root_
);
[
this
](
absent_field
)
{
root_
=
nullptr
;
emplace_error
(
sec
::
runtime_error
,
}
else
{
"begin_object called inside non-existent optional field"
);
auto
f
=
detail
::
make_overload
(
return
false
;
[
this
](
settings
*
)
{
},
emplace_error
(
sec
::
runtime_error
,
[
this
](
present_field
fld
)
{
"begin_object called inside another object"
);
CAF_ASSERT
(
fld
.
parent
!=
nullptr
);
return
false
;
auto
[
iter
,
added
]
=
fld
.
parent
->
emplace
(
fld
.
name
,
settings
{});
},
if
(
!
added
)
{
[
this
](
absent_field
)
{
emplace_error
(
sec
::
runtime_error
,
emplace_error
(
sec
::
runtime_error
,
"
begin_object called inside non-existent optional field"
);
"
field already defined: "
+
to_string
(
fld
.
name
)
);
return
false
;
return
false
;
},
}
[
this
](
present_field
fld
)
{
auto
obj
=
std
::
addressof
(
get
<
settings
>
(
iter
->
second
));
auto
[
iter
,
added
]
=
fld
.
parent
->
emplace
(
fld
.
name
,
settings
{});
if
(
!
fld
.
type
.
empty
())
if
(
!
added
)
{
put
(
*
obj
,
"@type"
,
fld
.
type
);
emplace_error
(
sec
::
runtime_error
,
st_
.
push
(
obj
);
"field already defined: "
+
to_string
(
fld
.
name
));
return
true
;
return
false
;
},
}
[
this
](
config_value
::
list
*
ls
)
{
auto
obj
=
std
::
addressof
(
get
<
settings
>
(
iter
->
second
));
ls
->
emplace_back
(
settings
{});
if
(
!
fld
.
type
.
empty
())
st_
.
push
(
std
::
addressof
(
get
<
settings
>
(
ls
->
back
())));
put
(
*
obj
,
"@type"
,
fld
.
type
);
return
true
;
st_
.
push
(
obj
);
});
return
true
;
if
(
!
visit
(
f
,
st_
.
top
()))
},
return
false
;
[
this
](
config_value
::
list
*
ls
)
{
ls
->
emplace_back
(
settings
{});
st_
.
push
(
std
::
addressof
(
get
<
settings
>
(
ls
->
back
())));
return
true
;
});
if
(
!
visit
(
f
,
st_
.
top
()))
return
false
;
}
if
(
!
type_hint_
.
empty
())
{
if
(
!
type_hint_
.
empty
())
{
put
(
*
get
<
settings
*>
(
st_
.
top
()),
"@type"
,
type_hint_
);
put
(
*
get
<
settings
*>
(
st_
.
top
()),
"@type"
,
type_hint_
);
type_hint_
=
string_view
{};
type_hint_
=
string_view
{};
...
@@ -124,19 +125,19 @@ bool settings_writer::begin_object(string_view) {
...
@@ -124,19 +125,19 @@ bool settings_writer::begin_object(string_view) {
return
true
;
return
true
;
}
}
bool
settings
_writer
::
end_object
()
{
bool
config_value
_writer
::
end_object
()
{
SCOPE
(
settings
*
);
SCOPE
(
settings
*
);
st_
.
pop
();
st_
.
pop
();
return
true
;
return
true
;
}
}
bool
settings
_writer
::
begin_field
(
string_view
name
)
{
bool
config_value
_writer
::
begin_field
(
string_view
name
)
{
SCOPE
(
settings
*
);
SCOPE
(
settings
*
);
st_
.
push
(
present_field
{
top
,
name
,
string_view
{}});
st_
.
push
(
present_field
{
top
,
name
,
string_view
{}});
return
true
;
return
true
;
}
}
bool
settings
_writer
::
begin_field
(
string_view
name
,
bool
is_present
)
{
bool
config_value
_writer
::
begin_field
(
string_view
name
,
bool
is_present
)
{
SCOPE
(
settings
*
);
SCOPE
(
settings
*
);
if
(
is_present
)
if
(
is_present
)
st_
.
push
(
present_field
{
top
,
name
,
string_view
{}});
st_
.
push
(
present_field
{
top
,
name
,
string_view
{}});
...
@@ -145,8 +146,9 @@ bool settings_writer::begin_field(string_view name, bool is_present) {
...
@@ -145,8 +146,9 @@ bool settings_writer::begin_field(string_view name, bool is_present) {
return
true
;
return
true
;
}
}
bool
settings_writer
::
begin_field
(
string_view
name
,
span
<
const
type_id_t
>
types
,
bool
config_value_writer
::
begin_field
(
string_view
name
,
size_t
index
)
{
span
<
const
type_id_t
>
types
,
size_t
index
)
{
SCOPE
(
settings
*
);
SCOPE
(
settings
*
);
if
(
index
>=
types
.
size
())
{
if
(
index
>=
types
.
size
())
{
emplace_error
(
sec
::
invalid_argument
,
emplace_error
(
sec
::
invalid_argument
,
...
@@ -164,15 +166,16 @@ bool settings_writer::begin_field(string_view name, span<const type_id_t> types,
...
@@ -164,15 +166,16 @@ bool settings_writer::begin_field(string_view name, span<const type_id_t> types,
return
true
;
return
true
;
}
}
bool
settings_writer
::
begin_field
(
string_view
name
,
bool
is_present
,
bool
config_value_writer
::
begin_field
(
string_view
name
,
bool
is_present
,
span
<
const
type_id_t
>
types
,
size_t
index
)
{
span
<
const
type_id_t
>
types
,
size_t
index
)
{
if
(
is_present
)
if
(
is_present
)
return
begin_field
(
name
,
types
,
index
);
return
begin_field
(
name
,
types
,
index
);
else
else
return
begin_field
(
name
,
false
);
return
begin_field
(
name
,
false
);
}
}
bool
settings
_writer
::
end_field
()
{
bool
config_value
_writer
::
end_field
()
{
CHECK_NOT_EMPTY
();
CHECK_NOT_EMPTY
();
if
(
!
holds_alternative
<
present_field
>
(
st_
.
top
())
if
(
!
holds_alternative
<
present_field
>
(
st_
.
top
())
&&
!
holds_alternative
<
absent_field
>
(
st_
.
top
()))
{
&&
!
holds_alternative
<
absent_field
>
(
st_
.
top
()))
{
...
@@ -183,15 +186,15 @@ bool settings_writer::end_field() {
...
@@ -183,15 +186,15 @@ bool settings_writer::end_field() {
return
true
;
return
true
;
}
}
bool
settings
_writer
::
begin_tuple
(
size_t
size
)
{
bool
config_value
_writer
::
begin_tuple
(
size_t
size
)
{
return
begin_sequence
(
size
);
return
begin_sequence
(
size
);
}
}
bool
settings
_writer
::
end_tuple
()
{
bool
config_value
_writer
::
end_tuple
()
{
return
end_sequence
();
return
end_sequence
();
}
}
bool
settings
_writer
::
begin_key_value_pair
()
{
bool
config_value
_writer
::
begin_key_value_pair
()
{
SCOPE
(
settings
*
);
SCOPE
(
settings
*
);
auto
[
iter
,
added
]
=
top
->
emplace
(
"@tmp"
,
config_value
::
list
{});
auto
[
iter
,
added
]
=
top
->
emplace
(
"@tmp"
,
config_value
::
list
{});
if
(
!
added
)
{
if
(
!
added
)
{
...
@@ -202,7 +205,7 @@ bool settings_writer::begin_key_value_pair() {
...
@@ -202,7 +205,7 @@ bool settings_writer::begin_key_value_pair() {
return
true
;
return
true
;
}
}
bool
settings
_writer
::
end_key_value_pair
()
{
bool
config_value
_writer
::
end_key_value_pair
()
{
config_value
::
list
tmp
;
config_value
::
list
tmp
;
/* lifetime scope of the list */
{
/* lifetime scope of the list */
{
SCOPE
(
config_value
::
list
*
);
SCOPE
(
config_value
::
list
*
);
...
@@ -229,9 +232,16 @@ bool settings_writer::end_key_value_pair() {
...
@@ -229,9 +232,16 @@ bool settings_writer::end_key_value_pair() {
return
true
;
return
true
;
}
}
bool
settings
_writer
::
begin_sequence
(
size_t
)
{
bool
config_value
_writer
::
begin_sequence
(
size_t
)
{
CHECK_NOT_EMPTY
();
CHECK_NOT_EMPTY
();
auto
f
=
detail
::
make_overload
(
auto
f
=
detail
::
make_overload
(
[
this
](
config_value
*
val
)
{
// Morph the value into a list.
auto
&
ls
=
val
->
as_list
();
ls
.
clear
();
st_
.
top
()
=
&
ls
;
return
true
;
},
[
this
](
settings
*
)
{
[
this
](
settings
*
)
{
emplace_error
(
sec
::
runtime_error
,
emplace_error
(
sec
::
runtime_error
,
"cannot start sequence/tuple inside an object"
);
"cannot start sequence/tuple inside an object"
);
...
@@ -261,16 +271,23 @@ bool settings_writer::begin_sequence(size_t) {
...
@@ -261,16 +271,23 @@ bool settings_writer::begin_sequence(size_t) {
return
visit
(
f
,
st_
.
top
());
return
visit
(
f
,
st_
.
top
());
}
}
bool
settings
_writer
::
end_sequence
()
{
bool
config_value
_writer
::
end_sequence
()
{
SCOPE
(
config_value
::
list
*
);
SCOPE
(
config_value
::
list
*
);
st_
.
pop
();
st_
.
pop
();
return
true
;
return
true
;
}
}
bool
settings
_writer
::
begin_associative_array
(
size_t
)
{
bool
config_value
_writer
::
begin_associative_array
(
size_t
)
{
CHECK_NOT_EMPTY
();
CHECK_NOT_EMPTY
();
settings
*
inner
=
nullptr
;
settings
*
inner
=
nullptr
;
auto
f
=
detail
::
make_overload
(
auto
f
=
detail
::
make_overload
(
[
this
](
config_value
*
val
)
{
// Morph the top element into a dictionary.
auto
&
dict
=
val
->
as_dictionary
();
dict
.
clear
();
st_
.
top
()
=
&
dict
;
return
true
;
},
[
this
](
settings
*
)
{
[
this
](
settings
*
)
{
emplace_error
(
sec
::
runtime_error
,
"cannot write values outside fields"
);
emplace_error
(
sec
::
runtime_error
,
"cannot write values outside fields"
);
return
false
;
return
false
;
...
@@ -316,45 +333,45 @@ bool settings_writer::begin_associative_array(size_t) {
...
@@ -316,45 +333,45 @@ bool settings_writer::begin_associative_array(size_t) {
return
false
;
return
false
;
}
}
bool
settings
_writer
::
end_associative_array
()
{
bool
config_value
_writer
::
end_associative_array
()
{
SCOPE
(
settings
*
);
SCOPE
(
settings
*
);
st_
.
pop
();
st_
.
pop
();
return
true
;
return
true
;
}
}
bool
settings
_writer
::
value
(
bool
x
)
{
bool
config_value
_writer
::
value
(
bool
x
)
{
return
push
(
config_value
{
x
});
return
push
(
config_value
{
x
});
}
}
bool
settings
_writer
::
value
(
int8_t
x
)
{
bool
config_value
_writer
::
value
(
int8_t
x
)
{
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
uint8_t
x
)
{
bool
config_value
_writer
::
value
(
uint8_t
x
)
{
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
int16_t
x
)
{
bool
config_value
_writer
::
value
(
int16_t
x
)
{
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
uint16_t
x
)
{
bool
config_value
_writer
::
value
(
uint16_t
x
)
{
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
int32_t
x
)
{
bool
config_value
_writer
::
value
(
int32_t
x
)
{
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
uint32_t
x
)
{
bool
config_value
_writer
::
value
(
uint32_t
x
)
{
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
int64_t
x
)
{
bool
config_value
_writer
::
value
(
int64_t
x
)
{
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
uint64_t
x
)
{
bool
config_value
_writer
::
value
(
uint64_t
x
)
{
auto
max_val
=
std
::
numeric_limits
<
config_value
::
integer
>::
max
();
auto
max_val
=
std
::
numeric_limits
<
config_value
::
integer
>::
max
();
if
(
x
>
static_cast
<
uint64_t
>
(
max_val
))
{
if
(
x
>
static_cast
<
uint64_t
>
(
max_val
))
{
emplace_error
(
sec
::
runtime_error
,
"integer overflow"
);
emplace_error
(
sec
::
runtime_error
,
"integer overflow"
);
...
@@ -363,41 +380,45 @@ bool settings_writer::value(uint64_t x) {
...
@@ -363,41 +380,45 @@ bool settings_writer::value(uint64_t x) {
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
return
push
(
config_value
{
static_cast
<
config_value
::
integer
>
(
x
)});
}
}
bool
settings
_writer
::
value
(
float
x
)
{
bool
config_value
_writer
::
value
(
float
x
)
{
return
push
(
config_value
{
double
{
x
}});
return
push
(
config_value
{
double
{
x
}});
}
}
bool
settings
_writer
::
value
(
double
x
)
{
bool
config_value
_writer
::
value
(
double
x
)
{
return
push
(
config_value
{
x
});
return
push
(
config_value
{
x
});
}
}
bool
settings
_writer
::
value
(
long
double
x
)
{
bool
config_value
_writer
::
value
(
long
double
x
)
{
return
push
(
config_value
{
std
::
to_string
(
x
)});
return
push
(
config_value
{
std
::
to_string
(
x
)});
}
}
bool
settings
_writer
::
value
(
string_view
x
)
{
bool
config_value
_writer
::
value
(
string_view
x
)
{
return
push
(
config_value
{
to_string
(
x
)});
return
push
(
config_value
{
to_string
(
x
)});
}
}
bool
settings
_writer
::
value
(
const
std
::
u16string
&
)
{
bool
config_value
_writer
::
value
(
const
std
::
u16string
&
)
{
emplace_error
(
sec
::
runtime_error
,
"u16string support not implemented yet"
);
emplace_error
(
sec
::
runtime_error
,
"u16string support not implemented yet"
);
return
false
;
return
false
;
}
}
bool
settings
_writer
::
value
(
const
std
::
u32string
&
)
{
bool
config_value
_writer
::
value
(
const
std
::
u32string
&
)
{
emplace_error
(
sec
::
runtime_error
,
"u32string support not implemented yet"
);
emplace_error
(
sec
::
runtime_error
,
"u32string support not implemented yet"
);
return
false
;
return
false
;
}
}
bool
settings
_writer
::
value
(
span
<
const
byte
>
x
)
{
bool
config_value
_writer
::
value
(
span
<
const
byte
>
x
)
{
std
::
string
str
;
std
::
string
str
;
detail
::
append_hex
(
str
,
x
.
data
(),
x
.
size
());
detail
::
append_hex
(
str
,
x
.
data
(),
x
.
size
());
return
push
(
config_value
{
std
::
move
(
str
)});
return
push
(
config_value
{
std
::
move
(
str
)});
}
}
bool
settings
_writer
::
push
(
config_value
&&
x
)
{
bool
config_value
_writer
::
push
(
config_value
&&
x
)
{
CHECK_NOT_EMPTY
();
CHECK_NOT_EMPTY
();
auto
f
=
detail
::
make_overload
(
auto
f
=
detail
::
make_overload
(
[
&
x
](
config_value
*
val
)
{
*
val
=
std
::
move
(
x
);
return
true
;
},
[
this
](
settings
*
)
{
[
this
](
settings
*
)
{
emplace_error
(
sec
::
runtime_error
,
"cannot write values outside fields"
);
emplace_error
(
sec
::
runtime_error
,
"cannot write values outside fields"
);
return
false
;
return
false
;
...
...
libcaf_core/src/detail/parse.cpp
View file @
c6e7fdb6
...
@@ -142,6 +142,8 @@ PARSE_IMPL(float, floating_point)
...
@@ -142,6 +142,8 @@ PARSE_IMPL(float, floating_point)
PARSE_IMPL
(
double
,
floating_point
)
PARSE_IMPL
(
double
,
floating_point
)
PARSE_IMPL
(
long
double
,
floating_point
)
void
parse
(
string_parser_state
&
ps
,
uri
&
x
)
{
void
parse
(
string_parser_state
&
ps
,
uri
&
x
)
{
uri_builder
builder
;
uri_builder
builder
;
if
(
ps
.
consume
(
'<'
))
{
if
(
ps
.
consume
(
'<'
))
{
...
...
libcaf_core/src/make_config_option.cpp
View file @
c6e7fdb6
...
@@ -24,11 +24,10 @@
...
@@ -24,11 +24,10 @@
#include "caf/optional.hpp"
#include "caf/optional.hpp"
#define DEFAULT_META(type, parse_fun) \
#define DEFAULT_META(type, parse_fun) \
config_option::meta_state \
config_option::meta_state type##_meta_state{ \
type##_meta_state{default_config_option_check<type>, \
default_config_option_check<type>, default_config_option_store<type>, \
default_config_option_store<type>, get_impl<type>, \
get_impl<type>, parse_fun, \
parse_fun, \
detail::config_value_access_t<type>::type_name()};
select_config_value_access_t<type>::type_name()};
using
std
::
string
;
using
std
::
string
;
...
@@ -78,7 +77,7 @@ config_value bool_get_neg(const void* ptr) {
...
@@ -78,7 +77,7 @@ config_value bool_get_neg(const void* ptr) {
meta_state
bool_neg_meta
{
detail
::
check_impl
<
bool
>
,
bool_store_neg
,
bool_get_neg
,
meta_state
bool_neg_meta
{
detail
::
check_impl
<
bool
>
,
bool_store_neg
,
bool_get_neg
,
nullptr
,
nullptr
,
select_
config_value_access_t
<
bool
>::
type_name
()};
detail
::
config_value_access_t
<
bool
>::
type_name
()};
error
check_timespan
(
const
config_value
&
x
)
{
error
check_timespan
(
const
config_value
&
x
)
{
if
(
holds_alternative
<
timespan
>
(
x
))
if
(
holds_alternative
<
timespan
>
(
x
))
...
@@ -100,11 +99,11 @@ config_value get_timespan(const void* ptr) {
...
@@ -100,11 +99,11 @@ config_value get_timespan(const void* ptr) {
meta_state
us_res_meta
{
check_timespan
,
store_timespan
<
1000
>
,
get_timespan
<
1000
>
,
meta_state
us_res_meta
{
check_timespan
,
store_timespan
<
1000
>
,
get_timespan
<
1000
>
,
nullptr
,
nullptr
,
select_
config_value_access_t
<
timespan
>::
type_name
()};
detail
::
config_value_access_t
<
timespan
>::
type_name
()};
meta_state
ms_res_meta
{
check_timespan
,
store_timespan
<
1000000
>
,
meta_state
ms_res_meta
{
check_timespan
,
store_timespan
<
1000000
>
,
get_timespan
<
1000000
>
,
nullptr
,
get_timespan
<
1000000
>
,
nullptr
,
select_
config_value_access_t
<
timespan
>::
type_name
()};
detail
::
config_value_access_t
<
timespan
>::
type_name
()};
}
// namespace
}
// namespace
...
@@ -114,17 +113,15 @@ config_option make_negated_config_option(bool& storage, string_view category,
...
@@ -114,17 +113,15 @@ config_option make_negated_config_option(bool& storage, string_view category,
return
{
category
,
name
,
description
,
&
bool_neg_meta
,
&
storage
};
return
{
category
,
name
,
description
,
&
bool_neg_meta
,
&
storage
};
}
}
config_option
make_us_resolution_config_option
(
size_t
&
storage
,
config_option
string_view
category
,
make_us_resolution_config_option
(
size_t
&
storage
,
string_view
category
,
string_view
name
,
string_view
name
,
string_view
description
)
{
string_view
description
)
{
return
{
category
,
name
,
description
,
&
us_res_meta
,
&
storage
};
return
{
category
,
name
,
description
,
&
us_res_meta
,
&
storage
};
}
}
config_option
make_ms_resolution_config_option
(
size_t
&
storage
,
config_option
string_view
category
,
make_ms_resolution_config_option
(
size_t
&
storage
,
string_view
category
,
string_view
name
,
string_view
name
,
string_view
description
)
{
string_view
description
)
{
return
{
category
,
name
,
description
,
&
ms_res_meta
,
&
storage
};
return
{
category
,
name
,
description
,
&
ms_res_meta
,
&
storage
};
}
}
...
...
libcaf_core/src/sec_strings.cpp
View file @
c6e7fdb6
...
@@ -137,6 +137,8 @@ std::string to_string(sec x) {
...
@@ -137,6 +137,8 @@ std::string to_string(sec x) {
return
"save_callback_failed"
;
return
"save_callback_failed"
;
case
sec
:
:
load_callback_failed
:
case
sec
:
:
load_callback_failed
:
return
"load_callback_failed"
;
return
"load_callback_failed"
;
case
sec
:
:
conversion_failed
:
return
"conversion_failed"
;
};
};
}
}
...
...
libcaf_core/test/config_value.cpp
View file @
c6e7fdb6
...
@@ -439,3 +439,58 @@ CAF_TEST(conversion to std::unordered_multimap) {
...
@@ -439,3 +439,58 @@ CAF_TEST(conversion to std::unordered_multimap) {
CAF_REQUIRE
(
ys
);
CAF_REQUIRE
(
ys
);
CAF_CHECK_EQUAL
(
*
ys
,
map_type
({{
"a"
,
1
},
{
"b"
,
2
},
{
"c"
,
3
},
{
"d"
,
4
}}));
CAF_CHECK_EQUAL
(
*
ys
,
map_type
({{
"a"
,
1
},
{
"b"
,
2
},
{
"c"
,
3
},
{
"d"
,
4
}}));
}
}
namespace
{
struct
point_3d
{
int32_t
x
;
int32_t
y
;
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
),
f
.
field
(
"z"
,
x
.
z
));
}
struct
line
{
point_3d
p1
;
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
));
}
}
// namespace
CAF_TEST
(
config
values
pick
up
user
defined
inspect
overloads
)
{
config_value
x
;
CAF_MESSAGE
(
"fill config value with the fields necessary for a 'line'"
);
{
auto
&
dict
=
x
.
as_dictionary
();
put
(
dict
,
"p1.x"
,
1
);
put
(
dict
,
"p1.y"
,
2
);
put
(
dict
,
"p1.z"
,
3
);
put
(
dict
,
"p2.x"
,
10
);
put
(
dict
,
"p2.y"
,
20
);
put
(
dict
,
"p2.z"
,
30
);
}
CAF_MESSAGE
(
"read 'line' via get_if and verify the object"
);
{
auto
l
=
get_if
<
line
>
(
&
x
);
CAF_CHECK_NOT_EQUAL
(
l
,
none
);
if
(
l
)
CAF_CHECK_EQUAL
(
*
l
,
(
line
{{
1
,
2
,
3
},
{
10
,
20
,
30
}}));
}
}
libcaf_core/test/config_value_adaptor.cpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 config_value_adaptor
#include "caf/config_value_adaptor.hpp"
#include "core-test.hpp"
#include "caf/config_value_adaptor_access.hpp"
using
namespace
caf
;
namespace
{
// We want to configure this type as follows:
// my-duration = {
// count = 1
// resolution = "s"
// }
struct
my_duration
{
public:
constexpr
my_duration
()
noexcept
:
ns_
(
0
)
{
// nop
}
constexpr
my_duration
(
const
my_duration
&
)
noexcept
=
default
;
my_duration
&
operator
=
(
const
my_duration
&
)
noexcept
=
default
;
int64_t
ns
()
const
{
return
ns_
;
}
int64_t
us
()
const
{
return
ns
()
/
1000
;
}
int64_t
ms
()
const
{
return
us
()
/
1000
;
}
int64_t
s
()
const
{
return
ms
()
/
1000
;
}
static
my_duration
from_ns
(
int64_t
count
)
{
my_duration
result
;
result
.
ns_
=
count
;
return
result
;
}
static
my_duration
from_us
(
int64_t
count
)
{
return
from_ns
(
count
*
1000
);
}
static
my_duration
from_ms
(
int64_t
count
)
{
return
from_us
(
count
*
1000
);
}
static
my_duration
from_s
(
int64_t
count
)
{
return
from_ms
(
count
*
1000
);
}
private:
int64_t
ns_
;
};
bool
operator
==
(
my_duration
x
,
my_duration
y
)
{
return
x
.
ns
()
==
y
.
ns
();
}
std
::
string
to_string
(
my_duration
x
)
{
return
std
::
to_string
(
x
.
ns
())
+
"ns"
;
}
struct
my_duration_adaptor
{
using
value_type
=
my_duration
;
using
tuple_type
=
std
::
tuple
<
int64_t
,
std
::
string
>
;
static
std
::
string
type_name
()
noexcept
{
return
"my-duration"
;
}
static
bool
resolution_valid
(
const
std
::
string
&
str
)
{
static
constexpr
string_view
whitelist
[]
=
{
"s"
,
"ms"
,
"us"
,
"ns"
};
auto
matches
=
[
&
](
string_view
x
)
{
return
str
==
x
;
};
return
std
::
any_of
(
std
::
begin
(
whitelist
),
std
::
end
(
whitelist
),
matches
);
}
static
config_value_adaptor
<
int64_t
,
std
::
string
>&
adaptor_ref
()
{
static
auto
singleton
=
make_config_value_adaptor
(
make_config_value_adaptor_field
<
int64_t
>
(
"count"
),
make_config_value_adaptor_field
<
std
::
string
>
(
"resolution"
,
none
,
resolution_valid
));
return
singleton
;
}
static
void
convert
(
const
value_type
&
src
,
tuple_type
&
dst
)
{
int
count
=
src
.
ns
();
if
(
count
/
1000
!=
0
)
{
dst
=
std
::
tie
(
count
,
"ns"
);
return
;
}
count
/=
1000
;
if
(
count
/
1000
!=
0
)
{
dst
=
std
::
tie
(
count
,
"us"
);
return
;
}
count
/=
1000
;
if
(
count
/
1000
!=
0
)
{
dst
=
std
::
tie
(
count
,
"ms"
);
return
;
}
count
/=
1000
;
dst
=
std
::
tie
(
count
,
"s"
);
}
static
void
convert
(
const
tuple_type
&
src
,
value_type
&
dst
)
{
auto
count
=
std
::
get
<
0
>
(
src
);
const
auto
&
resolution
=
std
::
get
<
1
>
(
src
);
if
(
resolution
==
"ns"
)
dst
=
my_duration
::
from_ns
(
count
);
else
if
(
resolution
==
"us"
)
dst
=
my_duration
::
from_us
(
count
);
else
if
(
resolution
==
"ms"
)
dst
=
my_duration
::
from_ms
(
count
);
else
dst
=
my_duration
::
from_s
(
count
);
}
};
struct
fixture
{
config_option_set
opts
;
template
<
class
T
>
expected
<
T
>
read
(
std
::
vector
<
std
::
string
>
args
)
{
settings
cfg
;
auto
res
=
opts
.
parse
(
cfg
,
args
);
if
(
res
.
first
!=
pec
::
success
)
return
make_error
(
res
.
first
,
*
res
.
second
);
auto
x
=
get_if
<
T
>
(
&
cfg
,
"value"
);
if
(
x
==
none
)
return
sec
::
invalid_argument
;
return
*
x
;
}
};
}
// namespace
namespace
caf
{
template
<
>
struct
config_value_access
<
my_duration
>
:
config_value_adaptor_access
<
my_duration_adaptor
>
{};
}
// namespace caf
CAF_TEST_FIXTURE_SCOPE
(
config_value_adaptor_tests
,
fixture
)
CAF_TEST
(
holds_alternative
)
{
auto
make_value
=
[](
int64_t
count
,
std
::
string
resolution
)
{
settings
x
;
put
(
x
,
"count"
,
count
);
put
(
x
,
"resolution"
,
std
::
move
(
resolution
));
return
config_value
{
std
::
move
(
x
)};
};
CAF_CHECK
(
holds_alternative
<
my_duration
>
(
make_value
(
1
,
"s"
)));
CAF_CHECK
(
holds_alternative
<
my_duration
>
(
make_value
(
1
,
"ms"
)));
CAF_CHECK
(
holds_alternative
<
my_duration
>
(
make_value
(
1
,
"us"
)));
CAF_CHECK
(
holds_alternative
<
my_duration
>
(
make_value
(
1
,
"ns"
)));
CAF_CHECK
(
!
holds_alternative
<
my_duration
>
(
make_value
(
1
,
"foo"
)));
}
CAF_TEST
(
access
from
dictionary
)
{
settings
x
;
put
(
x
,
"value.count"
,
42
);
put
(
x
,
"value.resolution"
,
"s"
);
auto
value
=
x
[
"value"
];
CAF_REQUIRE
(
holds_alternative
<
my_duration
>
(
value
));
CAF_CHECK_EQUAL
(
get_if
<
my_duration
>
(
&
value
),
my_duration
::
from_s
(
42
));
CAF_CHECK_EQUAL
(
get
<
my_duration
>
(
value
),
my_duration
::
from_s
(
42
));
}
namespace
{
constexpr
const
char
*
config_text
=
R"__(
max-delay = {
count = 123
resolution = "s"
}
)__"
;
struct
test_config
:
actor_system_config
{
test_config
()
{
opt_group
{
custom_options_
,
"global"
}.
add
(
max_delay
,
"max-delay,m"
,
"maximum delay"
);
}
my_duration
max_delay
;
};
}
// namespace
CAF_TEST
(
adaptor
access
from
actor
system
config
-
file
input
)
{
test_config
cfg
;
std
::
istringstream
in
{
config_text
};
if
(
auto
err
=
cfg
.
parse
(
0
,
nullptr
,
in
))
CAF_FAIL
(
"cfg.parse failed: "
<<
err
);
CAF_CHECK_EQUAL
(
cfg
.
max_delay
,
my_duration
::
from_s
(
123
));
}
CAF_TEST
(
adaptor
access
from
actor
system
config
-
file
input
and
arguments
)
{
std
::
vector
<
std
::
string
>
args
{
"--max-delay={count = 20, resolution = ms}"
,
};
test_config
cfg
;
std
::
istringstream
in
{
config_text
};
if
(
auto
err
=
cfg
.
parse
(
std
::
move
(
args
),
in
))
CAF_FAIL
(
"cfg.parse failed: "
<<
err
);
CAF_CHECK_EQUAL
(
cfg
.
max_delay
,
my_duration
::
from_ms
(
20
));
}
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_core/test/config_value_reader.cpp
0 → 100644
View file @
c6e7fdb6
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 config_value_reader
#include "caf/config_value_reader.hpp"
#include "caf/test/dsl.hpp"
#include "inspector-tests.hpp"
#include "caf/config_value.hpp"
#include "caf/config_value_writer.hpp"
#include "caf/inspector_access.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
config_value
&
src
,
T
&
value
)
{
config_value_reader
reader
{
&
src
};
if
(
!
detail
::
load_value
(
reader
,
value
))
CAF_FAIL
(
"failed to deserialize from settings: "
<<
reader
.
get_error
());
}
template
<
class
T
>
void
deserialize
(
const
settings
&
src
,
T
&
value
)
{
deserialize
(
config_value
{
src
},
value
);
}
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
(
config_value_reader_tests
,
fixture
)
CAF_TEST
(
readers
deserialize
builtin
types
from
config
values
)
{
std
::
string
value
;
put
(
xs
,
"foo"
,
"bar"
);
deserialize
(
xs
[
"foo"
],
value
);
CAF_CHECK_EQUAL
(
value
,
"bar"
);
}
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
}};
config_value
tmp
;
config_value_writer
writer
{
&
tmp
};
if
(
!
detail
::
save_value
(
writer
,
l
))
CAF_FAIL
(
"failed two write to settings: "
<<
writer
.
get_error
());
if
(
!
holds_alternative
<
settings
>
(
tmp
))
CAF_FAIL
(
"writer failed to produce a dictionary"
);
xs
=
std
::
move
(
caf
::
get
<
settings
>
(
tmp
));
}
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
()
libcaf_core/test/
settings
_writer.cpp
→
libcaf_core/test/
config_value
_writer.cpp
View file @
c6e7fdb6
...
@@ -16,14 +16,16 @@
...
@@ -16,14 +16,16 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#define CAF_SUITE
settings
_writer
#define CAF_SUITE
config_value
_writer
#include "caf/
settings
_writer.hpp"
#include "caf/
config_value
_writer.hpp"
#include "caf/test/dsl.hpp"
#include "caf/test/dsl.hpp"
#include "inspector-tests.hpp"
#include "inspector-tests.hpp"
#include "caf/inspector_access.hpp"
using
namespace
caf
;
using
namespace
caf
;
using
namespace
std
::
literals
::
string_literals
;
using
namespace
std
::
literals
::
string_literals
;
...
@@ -43,9 +45,13 @@ struct fixture {
...
@@ -43,9 +45,13 @@ struct fixture {
template
<
class
T
>
template
<
class
T
>
void
set
(
const
T
&
value
)
{
void
set
(
const
T
&
value
)
{
settings_writer
writer
{
&
xs
};
config_value
val
;
if
(
!
writer
.
apply_object
(
value
))
config_value_writer
writer
{
&
val
};
if
(
!
detail
::
save_value
(
writer
,
value
))
CAF_FAIL
(
"failed two write to settings: "
<<
writer
.
get_error
());
CAF_FAIL
(
"failed two write to settings: "
<<
writer
.
get_error
());
if
(
!
holds_alternative
<
settings
>
(
val
))
CAF_FAIL
(
"serializing T did not result in a dictionary"
);
xs
=
std
::
move
(
caf
::
get
<
settings
>
(
val
));
}
}
template
<
class
T
>
template
<
class
T
>
...
@@ -63,7 +69,7 @@ struct fixture {
...
@@ -63,7 +69,7 @@ struct fixture {
}
// namespace
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
settings
_writer_tests
,
fixture
)
CAF_TEST_FIXTURE_SCOPE
(
config_value
_writer_tests
,
fixture
)
CAF_TEST
(
structs
become
dictionaries
)
{
CAF_TEST
(
structs
become
dictionaries
)
{
set
(
foobar
{
"hello"
,
"world"
});
set
(
foobar
{
"hello"
,
"world"
});
...
...
libcaf_core/test/inspector-tests.hpp
View file @
c6e7fdb6
...
@@ -47,6 +47,10 @@ struct point_3d {
...
@@ -47,6 +47,10 @@ struct point_3d {
int32_t
z
;
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
>
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
point_3d
&
x
)
{
bool
inspect
(
Inspector
&
f
,
point_3d
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"x"
,
x
.
x
),
f
.
field
(
"y"
,
x
.
y
),
return
f
.
object
(
x
).
fields
(
f
.
field
(
"x"
,
x
.
x
),
f
.
field
(
"y"
,
x
.
y
),
...
@@ -58,6 +62,10 @@ struct line {
...
@@ -58,6 +62,10 @@ struct line {
point_3d
p2
;
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
>
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
line
&
x
)
{
bool
inspect
(
Inspector
&
f
,
line
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"p1"
,
x
.
p1
),
f
.
field
(
"p2"
,
x
.
p2
));
return
f
.
object
(
x
).
fields
(
f
.
field
(
"p1"
,
x
.
p1
),
f
.
field
(
"p2"
,
x
.
p2
));
...
@@ -141,6 +149,11 @@ struct dummy_message {
...
@@ -141,6 +149,11 @@ struct dummy_message {
caf
::
variant
<
std
::
string
,
double
>
content
;
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
>
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
dummy_message
&
x
)
{
bool
inspect
(
Inspector
&
f
,
dummy_message
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"content"
,
x
.
content
));
return
f
.
object
(
x
).
fields
(
f
.
field
(
"content"
,
x
.
content
));
...
...
libcaf_core/test/make_config_value_field.cpp
deleted
100644 → 0
View file @
97fea3fd
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 make_config_value_field
#include "caf/make_config_value_field.hpp"
#include "core-test.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/config_option_set.hpp"
#include "caf/config_value_object_access.hpp"
using
namespace
caf
;
namespace
{
struct
foobar
{
int
foo
=
0
;
std
::
string
bar
;
foobar
()
=
default
;
foobar
(
int
foo
,
std
::
string
bar
)
:
foo
(
foo
),
bar
(
std
::
move
(
bar
))
{
// nop
}
};
std
::
string
to_string
(
const
foobar
&
x
)
{
return
deep_to_string
(
std
::
forward_as_tuple
(
x
.
foo
,
x
.
bar
));
}
bool
operator
==
(
const
foobar
&
x
,
const
foobar
&
y
)
{
return
x
.
foo
==
y
.
foo
&&
x
.
bar
==
y
.
bar
;
}
bool
foo_valid
(
const
int
&
x
)
{
return
x
>=
0
;
}
int
get_foo_fun
(
foobar
x
)
{
return
x
.
foo
;
}
void
set_foo_fun
(
foobar
&
x
,
const
int
&
value
)
{
x
.
foo
=
value
;
}
struct
get_foo_t
{
int
operator
()(
const
foobar
&
x
)
const
noexcept
{
return
x
.
foo
;
}
};
struct
set_foo_t
{
int
&
operator
()(
foobar
&
x
,
int
value
)
const
noexcept
{
x
.
foo
=
value
;
return
x
.
foo
;
}
};
struct
foobar_trait
{
using
object_type
=
foobar
;
static
std
::
string
type_name
()
{
return
"foobar"
;
}
static
span
<
config_value_field
<
object_type
>*>
fields
()
{
static
auto
singleton
=
make_config_value_field_storage
(
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
123
),
make_config_value_field
(
"bar"
,
&
foobar
::
bar
));
return
singleton
.
fields
();
}
};
struct
foobar_foobar
{
foobar
x
;
foobar
y
;
foobar_foobar
()
=
default
;
foobar_foobar
(
foobar
x
,
foobar
y
)
:
x
(
x
),
y
(
y
)
{
// nop
}
};
std
::
string
to_string
(
const
foobar_foobar
&
x
)
{
return
deep_to_string
(
std
::
forward_as_tuple
(
x
.
x
,
x
.
y
));
}
bool
operator
==
(
const
foobar_foobar
&
x
,
const
foobar_foobar
&
y
)
{
return
x
.
x
==
y
.
x
&&
x
.
y
==
y
.
y
;
}
struct
foobar_foobar_trait
{
using
object_type
=
foobar_foobar
;
static
std
::
string
type_name
()
{
return
"foobar-foobar"
;
}
static
span
<
config_value_field
<
object_type
>*>
fields
()
{
static
auto
singleton
=
make_config_value_field_storage
(
make_config_value_field
(
"x"
,
&
foobar_foobar
::
x
),
make_config_value_field
(
"y"
,
&
foobar_foobar
::
y
));
return
singleton
.
fields
();
}
};
struct
fixture
{
get_foo_t
get_foo
;
set_foo_t
set_foo
;
config_option_set
opts
;
void
test_foo_field
(
config_value_field
<
foobar
>&
foo_field
)
{
foobar
x
;
CAF_CHECK_EQUAL
(
foo_field
.
name
(),
"foo"
);
CAF_REQUIRE
(
foo_field
.
has_default
());
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
0
));
foo_field
.
set_default
(
x
);
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
42
));
CAF_CHECK
(
!
foo_field
.
valid_input
(
config_value
(
1.
)));
CAF_CHECK
(
!
foo_field
.
valid_input
(
config_value
(
-
1
)));
CAF_CHECK
(
!
foo_field
.
set
(
x
,
config_value
(
-
1
)));
string_view
input
=
"123"
;
string_parser_state
ps
{
input
.
begin
(),
input
.
end
()};
foo_field
.
parse_cli
(
ps
,
x
,
false
);
CAF_CHECK_EQUAL
(
ps
.
code
,
pec
::
success
);
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
123
));
}
template
<
class
T
>
expected
<
T
>
read
(
std
::
vector
<
std
::
string
>
args
)
{
settings
cfg
;
auto
res
=
opts
.
parse
(
cfg
,
args
);
if
(
res
.
first
!=
pec
::
success
)
return
make_error
(
res
.
first
,
*
res
.
second
);
auto
x
=
get_if
<
T
>
(
&
cfg
,
"value"
);
if
(
x
==
none
)
return
sec
::
invalid_argument
;
return
*
x
;
}
};
}
// namespace
namespace
caf
{
template
<
>
struct
config_value_access
<
foobar
>
:
config_value_object_access
<
foobar_trait
>
{
};
template
<
>
struct
config_value_access
<
foobar_foobar
>
:
config_value_object_access
<
foobar_foobar_trait
>
{};
}
// namespace caf
CAF_TEST_FIXTURE_SCOPE
(
make_config_value_field_tests
,
fixture
)
CAF_TEST
(
construction
from
pointer
to
member
)
{
make_config_value_field
(
"foo"
,
&
foobar
::
foo
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
none
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
none
,
nullptr
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
nullptr
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
foo_valid
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
[](
const
int
&
x
)
{
return
x
!=
0
;
});
}
CAF_TEST
(
pointer
to
member
access
)
{
auto
foo_field
=
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
foo_valid
);
test_foo_field
(
foo_field
);
}
CAF_TEST
(
construction
from
getter
and
setter
)
{
auto
get_foo_lambda
=
[](
const
foobar
&
x
)
{
return
x
.
foo
;
};
auto
set_foo_lambda
=
[](
foobar
&
x
,
int
value
)
{
x
.
foo
=
value
;
};
make_config_value_field
(
"foo"
,
get_foo
,
set_foo
);
make_config_value_field
(
"foo"
,
get_foo_fun
,
set_foo
);
make_config_value_field
(
"foo"
,
get_foo_fun
,
set_foo_fun
);
make_config_value_field
(
"foo"
,
get_foo_lambda
,
set_foo_lambda
);
}
CAF_TEST
(
getter
and
setter
access
)
{
auto
foo_field
=
make_config_value_field
(
"foo"
,
get_foo
,
set_foo
,
42
,
foo_valid
);
test_foo_field
(
foo_field
);
}
CAF_TEST
(
object
access
from
dictionary
-
foobar
)
{
settings
x
;
put
(
x
,
"my-value.bar"
,
"hello"
);
CAF_MESSAGE
(
"without foo member"
);
{
CAF_REQUIRE
(
holds_alternative
<
foobar
>
(
x
,
"my-value"
));
CAF_REQUIRE
(
get_if
<
foobar
>
(
&
x
,
"my-value"
)
!=
caf
::
none
);
auto
fb
=
get
<
foobar
>
(
x
,
"my-value"
);
CAF_CHECK_EQUAL
(
fb
.
foo
,
123
);
CAF_CHECK_EQUAL
(
fb
.
bar
,
"hello"
);
}
CAF_MESSAGE
(
"with foo member"
);
put
(
x
,
"my-value.foo"
,
42
);
{
CAF_REQUIRE
(
holds_alternative
<
foobar
>
(
x
,
"my-value"
));
CAF_REQUIRE
(
get_if
<
foobar
>
(
&
x
,
"my-value"
)
!=
caf
::
none
);
auto
fb
=
get
<
foobar
>
(
x
,
"my-value"
);
CAF_CHECK_EQUAL
(
fb
.
foo
,
42
);
CAF_CHECK_EQUAL
(
fb
.
bar
,
"hello"
);
}
}
CAF_TEST
(
object
access
from
dictionary
-
foobar_foobar
)
{
settings
x
;
put
(
x
,
"my-value.x.foo"
,
1
);
put
(
x
,
"my-value.x.bar"
,
"hello"
);
put
(
x
,
"my-value.y.bar"
,
"world"
);
CAF_REQUIRE
(
holds_alternative
<
foobar_foobar
>
(
x
,
"my-value"
));
CAF_REQUIRE
(
get_if
<
foobar_foobar
>
(
&
x
,
"my-value"
)
!=
caf
::
none
);
auto
fbfb
=
get
<
foobar_foobar
>
(
x
,
"my-value"
);
CAF_CHECK_EQUAL
(
fbfb
.
x
.
foo
,
1
);
CAF_CHECK_EQUAL
(
fbfb
.
x
.
bar
,
"hello"
);
CAF_CHECK_EQUAL
(
fbfb
.
y
.
foo
,
123
);
CAF_CHECK_EQUAL
(
fbfb
.
y
.
bar
,
"world"
);
}
CAF_TEST
(
object
access
from
CLI
arguments
-
foobar
)
{
opts
.
add
<
foobar
>
(
"value,v"
,
"some value"
);
CAF_CHECK_EQUAL
(
read
<
foobar
>
({
"--value={foo = 1, bar = hello}"
}),
foobar
(
1
,
"hello"
));
CAF_CHECK_EQUAL
(
read
<
foobar
>
({
"-v{bar =
\"
hello
\"
}"
}),
foobar
(
123
,
"hello"
));
CAF_CHECK_EQUAL
(
read
<
foobar
>
({
"-v"
,
"{foo = 1, bar =hello ,}"
}),
foobar
(
1
,
"hello"
));
}
CAF_TEST
(
object
access
from
CLI
arguments
-
foobar_foobar
)
{
using
fbfb
=
foobar_foobar
;
opts
.
add
<
fbfb
>
(
"value,v"
,
"some value"
);
CAF_CHECK_EQUAL
(
read
<
fbfb
>
({
"-v{x={bar = hello},y={foo=1,bar=world!},}"
}),
fbfb
({
123
,
"hello"
},
{
1
,
"world!"
}));
}
namespace
{
constexpr
const
char
*
config_text
=
R"__(
arg1 = {
foo = 42
bar = "Don't panic!"
}
arg2 = {
x = {
foo = 1
bar = "hello"
}
y = {
foo = 2
bar = "world"
}
}
)__"
;
struct
test_config
:
actor_system_config
{
test_config
()
{
opt_group
{
custom_options_
,
"global"
}
.
add
(
fb
,
"arg1,1"
,
"some foobar"
)
.
add
(
fbfb
,
"arg2,2"
,
"somme foobar-foobar"
);
}
foobar
fb
;
foobar_foobar
fbfb
;
};
}
// namespace
CAF_TEST
(
object
access
from
actor
system
config
-
file
input
)
{
test_config
cfg
;
std
::
istringstream
in
{
config_text
};
if
(
auto
err
=
cfg
.
parse
(
0
,
nullptr
,
in
))
CAF_FAIL
(
"cfg.parse failed: "
<<
err
);
CAF_CHECK_EQUAL
(
cfg
.
fb
.
foo
,
42
);
CAF_CHECK_EQUAL
(
cfg
.
fb
.
bar
,
"Don't panic!"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
foo
,
1
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
foo
,
2
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
bar
,
"hello"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
bar
,
"world"
);
}
CAF_TEST
(
object
access
from
actor
system
config
-
file
input
and
arguments
)
{
std
::
vector
<
std
::
string
>
args
{
"-2"
,
"{y = {bar = CAF, foo = 20}, x = {foo = 10, bar = hello}}"
,
};
test_config
cfg
;
std
::
istringstream
in
{
config_text
};
if
(
auto
err
=
cfg
.
parse
(
std
::
move
(
args
),
in
))
CAF_FAIL
(
"cfg.parse failed: "
<<
err
);
CAF_CHECK_EQUAL
(
cfg
.
fb
.
foo
,
42
);
CAF_CHECK_EQUAL
(
cfg
.
fb
.
bar
,
"Don't panic!"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
foo
,
10
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
foo
,
20
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
x
.
bar
,
"hello"
);
CAF_CHECK_EQUAL
(
cfg
.
fbfb
.
y
.
bar
,
"CAF"
);
}
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